[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('yui2-paginator', function(Y) { 2 var YAHOO = Y.YUI2; 3 /* 4 Copyright (c) 2011, Yahoo! Inc. All rights reserved. 5 Code licensed under the BSD License: 6 http://developer.yahoo.com/yui/license.html 7 version: 2.9.0 8 */ 9 (function () { 10 /** 11 * The Paginator widget provides a set of controls to navigate through paged 12 * data. 13 * 14 * @module paginator 15 * @uses YAHOO.util.EventProvider 16 * @uses YAHOO.util.AttributeProvider 17 */ 18 19 var Dom = YAHOO.util.Dom, 20 lang = YAHOO.lang, 21 isObject = lang.isObject, 22 isFunction = lang.isFunction, 23 isArray = lang.isArray, 24 isString = lang.isString; 25 26 /** 27 * Instantiate a Paginator, passing a configuration object to the contructor. 28 * The configuration object should contain the following properties: 29 * <ul> 30 * <li>rowsPerPage : <em>n</em> (int)</li> 31 * <li>totalRecords : <em>n</em> (int or Paginator.VALUE_UNLIMITED)</li> 32 * <li>containers : <em>id | el | arr</em> (HTMLElement reference, its id, or an array of either)</li> 33 * </ul> 34 * 35 * @namespace YAHOO.widget 36 * @class Paginator 37 * @constructor 38 * @param config {Object} Object literal to set instance and ui component 39 * configuration. 40 */ 41 function Paginator(config) { 42 var UNLIMITED = Paginator.VALUE_UNLIMITED, 43 attrib, initialPage, records, perPage, startIndex; 44 45 config = isObject(config) ? config : {}; 46 47 this.initConfig(); 48 49 this.initEvents(); 50 51 // Set the basic config keys first 52 this.set('rowsPerPage',config.rowsPerPage,true); 53 if (Paginator.isNumeric(config.totalRecords)) { 54 this.set('totalRecords',config.totalRecords,true); 55 } 56 57 this.initUIComponents(); 58 59 // Update the other config values 60 for (attrib in config) { 61 if (config.hasOwnProperty(attrib)) { 62 this.set(attrib,config[attrib],true); 63 } 64 } 65 66 // Calculate the initial record offset 67 initialPage = this.get('initialPage'); 68 records = this.get('totalRecords'); 69 perPage = this.get('rowsPerPage'); 70 if (initialPage > 1 && perPage !== UNLIMITED) { 71 startIndex = (initialPage - 1) * perPage; 72 if (records === UNLIMITED || startIndex < records) { 73 this.set('recordOffset',startIndex,true); 74 } 75 } 76 } 77 78 79 // Static members 80 lang.augmentObject(Paginator, { 81 /** 82 * Incrementing index used to give instances unique ids. 83 * @static 84 * @property Paginator.id 85 * @type number 86 * @private 87 */ 88 id : 0, 89 90 /** 91 * Base of id strings used for ui components. 92 * @static 93 * @property Paginator.ID_BASE 94 * @type string 95 * @private 96 */ 97 ID_BASE : 'yui-pg', 98 99 /** 100 * Used to identify unset, optional configurations, or used explicitly in 101 * the case of totalRecords to indicate unlimited pagination. 102 * @static 103 * @property Paginator.VALUE_UNLIMITED 104 * @type number 105 * @final 106 */ 107 VALUE_UNLIMITED : -1, 108 109 /** 110 * Default template used by Paginator instances. Update this if you want 111 * all new Paginators to use a different default template. 112 * @static 113 * @property Paginator.TEMPLATE_DEFAULT 114 * @type string 115 */ 116 TEMPLATE_DEFAULT : "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}", 117 118 /** 119 * Common alternate pagination format, including page links, links for 120 * previous, next, first and last pages as well as a rows-per-page 121 * dropdown. Offered as a convenience. 122 * @static 123 * @property Paginator.TEMPLATE_ROWS_PER_PAGE 124 * @type string 125 */ 126 TEMPLATE_ROWS_PER_PAGE : "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}", 127 128 /** 129 * Storage object for UI Components 130 * @static 131 * @property Paginator.ui 132 */ 133 ui : {}, 134 135 /** 136 * Similar to YAHOO.lang.isNumber, but allows numeric strings. This is 137 * is used for attribute validation in conjunction with getters that return 138 * numbers. 139 * 140 * @method Paginator.isNumeric 141 * @param v {Number|String} value to be checked for number or numeric string 142 * @returns {Boolean} true if the input is coercable into a finite number 143 * @static 144 */ 145 isNumeric : function (v) { 146 return isFinite(+v); 147 }, 148 149 /** 150 * Return a number or null from input 151 * 152 * @method Paginator.toNumber 153 * @param n {Number|String} a number or numeric string 154 * @return Number 155 * @static 156 */ 157 toNumber : function (n) { 158 return isFinite(+n) ? +n : null; 159 } 160 161 },true); 162 163 164 // Instance members and methods 165 Paginator.prototype = { 166 167 // Instance members 168 169 /** 170 * Array of nodes in which to render pagination controls. This is set via 171 * the "containers" attribute. 172 * @property _containers 173 * @type Array(HTMLElement) 174 * @private 175 */ 176 _containers : [], 177 178 /** 179 * Flag used to indicate multiple attributes are being updated via setState 180 * @property _batch 181 * @type boolean 182 * @protected 183 */ 184 _batch : false, 185 186 /** 187 * Used by setState to indicate when a page change has occurred 188 * @property _pageChanged 189 * @type boolean 190 * @protected 191 */ 192 _pageChanged : false, 193 194 /** 195 * Temporary state cache used by setState to keep track of the previous 196 * state for eventual pageChange event firing 197 * @property _state 198 * @type Object 199 * @protected 200 */ 201 _state : null, 202 203 204 // Instance methods 205 206 /** 207 * Initialize the Paginator's attributes (see YAHOO.util.Element class 208 * AttributeProvider). 209 * @method initConfig 210 * @private 211 */ 212 initConfig : function () { 213 214 var UNLIMITED = Paginator.VALUE_UNLIMITED; 215 216 /** 217 * REQUIRED. Number of records constituting a "page" 218 * @attribute rowsPerPage 219 * @type integer 220 */ 221 this.setAttributeConfig('rowsPerPage', { 222 value : 0, 223 validator : Paginator.isNumeric, 224 setter : Paginator.toNumber 225 }); 226 227 /** 228 * REQUIRED. Node references or ids of nodes in which to render the 229 * pagination controls. 230 * @attribute containers 231 * @type {string|HTMLElement|Array(string|HTMLElement)} 232 */ 233 this.setAttributeConfig('containers', { 234 value : null, 235 validator : function (val) { 236 if (!isArray(val)) { 237 val = [val]; 238 } 239 for (var i = 0, len = val.length; i < len; ++i) { 240 if (isString(val[i]) || 241 (isObject(val[i]) && val[i].nodeType === 1)) { 242 continue; 243 } 244 return false; 245 } 246 return true; 247 }, 248 method : function (val) { 249 val = Dom.get(val); 250 if (!isArray(val)) { 251 val = [val]; 252 } 253 this._containers = val; 254 } 255 }); 256 257 /** 258 * Total number of records to paginate through 259 * @attribute totalRecords 260 * @type integer 261 * @default 0 262 */ 263 this.setAttributeConfig('totalRecords', { 264 value : 0, 265 validator : Paginator.isNumeric, 266 setter : Paginator.toNumber 267 }); 268 269 /** 270 * Zero based index of the record considered first on the current page. 271 * For page based interactions, don't modify this attribute directly; 272 * use setPage(n). 273 * @attribute recordOffset 274 * @type integer 275 * @default 0 276 */ 277 this.setAttributeConfig('recordOffset', { 278 value : 0, 279 validator : function (val) { 280 var total = this.get('totalRecords'); 281 if (Paginator.isNumeric(val)) { 282 val = +val; 283 return total === UNLIMITED || total > val || 284 (total === 0 && val === 0); 285 } 286 287 return false; 288 }, 289 setter : Paginator.toNumber 290 }); 291 292 /** 293 * Page to display on initial paint 294 * @attribute initialPage 295 * @type integer 296 * @default 1 297 */ 298 this.setAttributeConfig('initialPage', { 299 value : 1, 300 validator : Paginator.isNumeric, 301 setter : Paginator.toNumber 302 }); 303 304 /** 305 * Template used to render controls. The string will be used as 306 * innerHTML on all specified container nodes. Bracketed keys 307 * (e.g. {pageLinks}) in the string will be replaced with an instance 308 * of the so named ui component. 309 * @see Paginator.TEMPLATE_DEFAULT 310 * @see Paginator.TEMPLATE_ROWS_PER_PAGE 311 * @attribute template 312 * @type string 313 */ 314 this.setAttributeConfig('template', { 315 value : Paginator.TEMPLATE_DEFAULT, 316 validator : isString 317 }); 318 319 /** 320 * Class assigned to the element(s) containing pagination controls. 321 * @attribute containerClass 322 * @type string 323 * @default 'yui-pg-container' 324 */ 325 this.setAttributeConfig('containerClass', { 326 value : 'yui-pg-container', 327 validator : isString 328 }); 329 330 /** 331 * Display pagination controls even when there is only one page. Set 332 * to false to forgo rendering and/or hide the containers when there 333 * is only one page of data. Note if you are using the rowsPerPage 334 * dropdown ui component, visibility will be maintained as long as the 335 * number of records exceeds the smallest page size. 336 * @attribute alwaysVisible 337 * @type boolean 338 * @default true 339 */ 340 this.setAttributeConfig('alwaysVisible', { 341 value : true, 342 validator : lang.isBoolean 343 }); 344 345 /** 346 * Update the UI immediately upon interaction. If false, changeRequest 347 * subscribers or other external code will need to explicitly set the 348 * new values in the paginator to trigger repaint. 349 * @attribute updateOnChange 350 * @type boolean 351 * @default false 352 * @deprecated use changeRequest listener that calls setState 353 */ 354 this.setAttributeConfig('updateOnChange', { 355 value : false, 356 validator : lang.isBoolean 357 }); 358 359 360 361 // Read only attributes 362 363 /** 364 * Unique id assigned to this instance 365 * @attribute id 366 * @type integer 367 * @final 368 */ 369 this.setAttributeConfig('id', { 370 value : Paginator.id++, 371 readOnly : true 372 }); 373 374 /** 375 * Indicator of whether the DOM nodes have been initially created 376 * @attribute rendered 377 * @type boolean 378 * @final 379 */ 380 this.setAttributeConfig('rendered', { 381 value : false, 382 readOnly : true 383 }); 384 385 }, 386 387 /** 388 * Initialize registered ui components onto this instance. 389 * @method initUIComponents 390 * @private 391 */ 392 initUIComponents : function () { 393 var ui = Paginator.ui, 394 name,UIComp; 395 for (name in ui) { 396 if (ui.hasOwnProperty(name)) { 397 UIComp = ui[name]; 398 if (isObject(UIComp) && isFunction(UIComp.init)) { 399 UIComp.init(this); 400 } 401 } 402 } 403 }, 404 405 /** 406 * Initialize this instance's CustomEvents. 407 * @method initEvents 408 * @private 409 */ 410 initEvents : function () { 411 /** 412 * Event fired when the Paginator is initially rendered 413 * @event render 414 */ 415 this.createEvent('render'); 416 417 /** 418 * Event fired when the Paginator is initially rendered 419 * @event rendered 420 * @deprecated use render event 421 */ 422 this.createEvent('rendered'); // backward compatibility 423 424 /** 425 * Event fired when a change in pagination values is requested, 426 * either by interacting with the various ui components or via the 427 * setStartIndex(n) etc APIs. 428 * Subscribers will receive the proposed state as the first parameter. 429 * The proposed state object will contain the following keys: 430 * <ul> 431 * <li>paginator - the Paginator instance</li> 432 * <li>page</li> 433 * <li>totalRecords</li> 434 * <li>recordOffset - index of the first record on the new page</li> 435 * <li>rowsPerPage</li> 436 * <li>records - array containing [start index, end index] for the records on the new page</li> 437 * <li>before - object literal with all these keys for the current state</li> 438 * </ul> 439 * @event changeRequest 440 */ 441 this.createEvent('changeRequest'); 442 443 /** 444 * Event fired when attribute changes have resulted in the calculated 445 * current page changing. 446 * @event pageChange 447 */ 448 this.createEvent('pageChange'); 449 450 /** 451 * Event that fires before the destroy event. 452 * @event beforeDestroy 453 */ 454 this.createEvent('beforeDestroy'); 455 456 /** 457 * Event used to trigger cleanup of ui components 458 * @event destroy 459 */ 460 this.createEvent('destroy'); 461 462 this._selfSubscribe(); 463 }, 464 465 /** 466 * Subscribes to instance attribute change events to automate certain 467 * behaviors. 468 * @method _selfSubscribe 469 * @protected 470 */ 471 _selfSubscribe : function () { 472 // Listen for changes to totalRecords and alwaysVisible 473 this.subscribe('totalRecordsChange',this.updateVisibility,this,true); 474 this.subscribe('alwaysVisibleChange',this.updateVisibility,this,true); 475 476 // Fire the pageChange event when appropriate 477 this.subscribe('totalRecordsChange',this._handleStateChange,this,true); 478 this.subscribe('recordOffsetChange',this._handleStateChange,this,true); 479 this.subscribe('rowsPerPageChange',this._handleStateChange,this,true); 480 481 // Update recordOffset when totalRecords is reduced below 482 this.subscribe('totalRecordsChange',this._syncRecordOffset,this,true); 483 }, 484 485 /** 486 * Sets recordOffset to the starting index of the previous page when 487 * totalRecords is reduced below the current recordOffset. 488 * @method _syncRecordOffset 489 * @param e {Event} totalRecordsChange event 490 * @protected 491 */ 492 _syncRecordOffset : function (e) { 493 var v = e.newValue,rpp,state; 494 if (e.prevValue !== v) { 495 if (v !== Paginator.VALUE_UNLIMITED) { 496 rpp = this.get('rowsPerPage'); 497 498 if (rpp && this.get('recordOffset') >= v) { 499 state = this.getState({ 500 totalRecords : e.prevValue, 501 recordOffset : this.get('recordOffset') 502 }); 503 504 this.set('recordOffset', state.before.recordOffset); 505 this._firePageChange(state); 506 } 507 } 508 } 509 }, 510 511 /** 512 * Fires the pageChange event when the state attributes have changed in 513 * such a way as to locate the current recordOffset on a new page. 514 * @method _handleStateChange 515 * @param e {Event} the attribute change event 516 * @protected 517 */ 518 _handleStateChange : function (e) { 519 if (e.prevValue !== e.newValue) { 520 var change = this._state || {}, 521 state; 522 523 change[e.type.replace(/Change$/,'')] = e.prevValue; 524 state = this.getState(change); 525 526 if (state.page !== state.before.page) { 527 if (this._batch) { 528 this._pageChanged = true; 529 } else { 530 this._firePageChange(state); 531 } 532 } 533 } 534 }, 535 536 /** 537 * Fires a pageChange event in the form of a standard attribute change 538 * event with additional properties prevState and newState. 539 * @method _firePageChange 540 * @param state {Object} the result of getState(oldState) 541 * @protected 542 */ 543 _firePageChange : function (state) { 544 if (isObject(state)) { 545 var current = state.before; 546 delete state.before; 547 this.fireEvent('pageChange',{ 548 type : 'pageChange', 549 prevValue : state.page, 550 newValue : current.page, 551 prevState : state, 552 newState : current 553 }); 554 } 555 }, 556 557 /** 558 * Render the pagination controls per the format attribute into the 559 * specified container nodes. 560 * @method render 561 * @return the Paginator instance 562 * @chainable 563 */ 564 render : function () { 565 if (this.get('rendered')) { 566 return this; 567 } 568 569 var template = this.get('template'), 570 state = this.getState(), 571 // ex. yui-pg0-1 (first paginator, second container) 572 id_base = Paginator.ID_BASE + this.get('id') + '-', 573 i, len; 574 575 // Assemble the containers, keeping them hidden 576 for (i = 0, len = this._containers.length; i < len; ++i) { 577 this._renderTemplate(this._containers[i],template,id_base+i,true); 578 } 579 580 // Show the containers if appropriate 581 this.updateVisibility(); 582 583 // Set render attribute manually to support its readOnly contract 584 if (this._containers.length) { 585 this.setAttributeConfig('rendered', { value: true }); 586 587 this.fireEvent('render', state); 588 // For backward compatibility 589 this.fireEvent('rendered', state); 590 } 591 592 return this; 593 }, 594 595 /** 596 * Creates the individual ui components and renders them into a container. 597 * 598 * @method _renderTemplate 599 * @param container {HTMLElement} where to add the ui components 600 * @param template {String} the template to use as a guide for rendering 601 * @param id_base {String} id base for the container's ui components 602 * @param hide {Boolean} leave the container hidden after assembly 603 * @protected 604 */ 605 _renderTemplate : function (container, template, id_base, hide) { 606 var containerClass = this.get('containerClass'), 607 markers, i, len; 608 609 if (!container) { 610 return; 611 } 612 613 // Hide the container while its contents are rendered 614 Dom.setStyle(container,'display','none'); 615 616 Dom.addClass(container, containerClass); 617 618 // Place the template innerHTML, adding marker spans to the template 619 // html to indicate drop zones for ui components 620 container.innerHTML = template.replace(/\{([a-z0-9_ \-]+)\}/gi, 621 '<span class="yui-pg-ui yui-pg-ui-$1"></span>'); 622 623 // Replace each marker with the ui component's render() output 624 markers = Dom.getElementsByClassName('yui-pg-ui','span',container); 625 626 for (i = 0, len = markers.length; i < len; ++i) { 627 this.renderUIComponent(markers[i], id_base); 628 } 629 630 if (!hide) { 631 // Show the container allowing page reflow 632 Dom.setStyle(container,'display',''); 633 } 634 }, 635 636 /** 637 * Replaces a marker node with a rendered UI component, determined by the 638 * yui-pg-ui-(UI component class name) in the marker's className. e.g. 639 * yui-pg-ui-PageLinks => new YAHOO.widget.Paginator.ui.PageLinks(this) 640 * 641 * @method renderUIComponent 642 * @param marker {HTMLElement} the marker node to replace 643 * @param id_base {String} string base the component's generated id 644 * @return the Paginator instance 645 * @chainable 646 */ 647 renderUIComponent : function (marker, id_base) { 648 var par = marker.parentNode, 649 name = /yui-pg-ui-(\w+)/.exec(marker.className), 650 UIComp = name && Paginator.ui[name[1]], 651 comp; 652 653 if (isFunction(UIComp)) { 654 comp = new UIComp(this); 655 if (isFunction(comp.render)) { 656 par.replaceChild(comp.render(id_base),marker); 657 } 658 } 659 660 return this; 661 }, 662 663 /** 664 * Removes controls from the page and unhooks events. 665 * @method destroy 666 */ 667 destroy : function () { 668 this.fireEvent('beforeDestroy'); 669 this.fireEvent('destroy'); 670 671 this.setAttributeConfig('rendered',{value:false}); 672 this.unsubscribeAll(); 673 }, 674 675 /** 676 * Hides the containers if there is only one page of data and attribute 677 * alwaysVisible is false. Conversely, it displays the containers if either 678 * there is more than one page worth of data or alwaysVisible is turned on. 679 * @method updateVisibility 680 */ 681 updateVisibility : function (e) { 682 var alwaysVisible = this.get('alwaysVisible'), 683 totalRecords, visible, rpp, rppOptions, i, len, opt; 684 685 if (!e || e.type === 'alwaysVisibleChange' || !alwaysVisible) { 686 totalRecords = this.get('totalRecords'); 687 visible = true; 688 rpp = this.get('rowsPerPage'); 689 rppOptions = this.get('rowsPerPageOptions'); 690 691 if (isArray(rppOptions)) { 692 for (i = 0, len = rppOptions.length; i < len; ++i) { 693 opt = rppOptions[i]; 694 // account for value 'all' 695 if (lang.isNumber(opt || opt.value)) { 696 rpp = Math.min(rpp, (opt.value || opt)); 697 } 698 } 699 } 700 701 if (totalRecords !== Paginator.VALUE_UNLIMITED && 702 totalRecords <= rpp) { 703 visible = false; 704 } 705 706 visible = visible || alwaysVisible; 707 708 for (i = 0, len = this._containers.length; i < len; ++i) { 709 Dom.setStyle(this._containers[i],'display', 710 visible ? '' : 'none'); 711 } 712 } 713 }, 714 715 716 717 718 /** 719 * Get the configured container nodes 720 * @method getContainerNodes 721 * @return {Array} array of HTMLElement nodes 722 */ 723 getContainerNodes : function () { 724 return this._containers; 725 }, 726 727 /** 728 * Get the total number of pages in the data set according to the current 729 * rowsPerPage and totalRecords values. If totalRecords is not set, or 730 * set to YAHOO.widget.Paginator.VALUE_UNLIMITED, returns 731 * YAHOO.widget.Paginator.VALUE_UNLIMITED. 732 * @method getTotalPages 733 * @return {number} 734 */ 735 getTotalPages : function () { 736 var records = this.get('totalRecords'), 737 perPage = this.get('rowsPerPage'); 738 739 // rowsPerPage not set. Can't calculate 740 if (!perPage) { 741 return null; 742 } 743 744 if (records === Paginator.VALUE_UNLIMITED) { 745 return Paginator.VALUE_UNLIMITED; 746 } 747 748 return Math.ceil(records/perPage); 749 }, 750 751 /** 752 * Does the requested page have any records? 753 * @method hasPage 754 * @param page {number} the page in question 755 * @return {boolean} 756 */ 757 hasPage : function (page) { 758 if (!lang.isNumber(page) || page < 1) { 759 return false; 760 } 761 762 var totalPages = this.getTotalPages(); 763 764 return (totalPages === Paginator.VALUE_UNLIMITED || totalPages >= page); 765 }, 766 767 /** 768 * Get the page number corresponding to the current record offset. 769 * @method getCurrentPage 770 * @return {number} 771 */ 772 getCurrentPage : function () { 773 var perPage = this.get('rowsPerPage'); 774 if (!perPage || !this.get('totalRecords')) { 775 return 0; 776 } 777 return Math.floor(this.get('recordOffset') / perPage) + 1; 778 }, 779 780 /** 781 * Are there records on the next page? 782 * @method hasNextPage 783 * @return {boolean} 784 */ 785 hasNextPage : function () { 786 var currentPage = this.getCurrentPage(), 787 totalPages = this.getTotalPages(); 788 789 return currentPage && (totalPages === Paginator.VALUE_UNLIMITED || currentPage < totalPages); 790 }, 791 792 /** 793 * Get the page number of the next page, or null if the current page is the 794 * last page. 795 * @method getNextPage 796 * @return {number} 797 */ 798 getNextPage : function () { 799 return this.hasNextPage() ? this.getCurrentPage() + 1 : null; 800 }, 801 802 /** 803 * Is there a page before the current page? 804 * @method hasPreviousPage 805 * @return {boolean} 806 */ 807 hasPreviousPage : function () { 808 return (this.getCurrentPage() > 1); 809 }, 810 811 /** 812 * Get the page number of the previous page, or null if the current page 813 * is the first page. 814 * @method getPreviousPage 815 * @return {number} 816 */ 817 getPreviousPage : function () { 818 return (this.hasPreviousPage() ? this.getCurrentPage() - 1 : 1); 819 }, 820 821 /** 822 * Get the start and end record indexes of the specified page. 823 * @method getPageRecords 824 * @param page {number} (optional) The page (current page if not specified) 825 * @return {Array} [start_index, end_index] 826 */ 827 getPageRecords : function (page) { 828 if (!lang.isNumber(page)) { 829 page = this.getCurrentPage(); 830 } 831 832 var perPage = this.get('rowsPerPage'), 833 records = this.get('totalRecords'), 834 start, end; 835 836 if (!page || !perPage) { 837 return null; 838 } 839 840 start = (page - 1) * perPage; 841 if (records !== Paginator.VALUE_UNLIMITED) { 842 if (start >= records) { 843 return null; 844 } 845 end = Math.min(start + perPage, records) - 1; 846 } else { 847 end = start + perPage - 1; 848 } 849 850 return [start,end]; 851 }, 852 853 /** 854 * Set the current page to the provided page number if possible. 855 * @method setPage 856 * @param newPage {number} the new page number 857 * @param silent {boolean} whether to forcibly avoid firing the 858 * changeRequest event 859 */ 860 setPage : function (page,silent) { 861 if (this.hasPage(page) && page !== this.getCurrentPage()) { 862 if (this.get('updateOnChange') || silent) { 863 this.set('recordOffset', (page - 1) * this.get('rowsPerPage')); 864 } else { 865 this.fireEvent('changeRequest',this.getState({'page':page})); 866 } 867 } 868 }, 869 870 /** 871 * Get the number of rows per page. 872 * @method getRowsPerPage 873 * @return {number} the current setting of the rowsPerPage attribute 874 */ 875 getRowsPerPage : function () { 876 return this.get('rowsPerPage'); 877 }, 878 879 /** 880 * Set the number of rows per page. 881 * @method setRowsPerPage 882 * @param rpp {number} the new number of rows per page 883 * @param silent {boolean} whether to forcibly avoid firing the 884 * changeRequest event 885 */ 886 setRowsPerPage : function (rpp,silent) { 887 if (Paginator.isNumeric(rpp) && +rpp > 0 && 888 +rpp !== this.get('rowsPerPage')) { 889 if (this.get('updateOnChange') || silent) { 890 this.set('rowsPerPage',rpp); 891 } else { 892 this.fireEvent('changeRequest', 893 this.getState({'rowsPerPage':+rpp})); 894 } 895 } 896 }, 897 898 /** 899 * Get the total number of records. 900 * @method getTotalRecords 901 * @return {number} the current setting of totalRecords attribute 902 */ 903 getTotalRecords : function () { 904 return this.get('totalRecords'); 905 }, 906 907 /** 908 * Set the total number of records. 909 * @method setTotalRecords 910 * @param total {number} the new total number of records 911 * @param silent {boolean} whether to forcibly avoid firing the changeRequest event 912 */ 913 setTotalRecords : function (total,silent) { 914 if (Paginator.isNumeric(total) && +total >= 0 && 915 +total !== this.get('totalRecords')) { 916 if (this.get('updateOnChange') || silent) { 917 this.set('totalRecords',total); 918 } else { 919 this.fireEvent('changeRequest', 920 this.getState({'totalRecords':+total})); 921 } 922 } 923 }, 924 925 /** 926 * Get the index of the first record on the current page 927 * @method getStartIndex 928 * @return {number} the index of the first record on the current page 929 */ 930 getStartIndex : function () { 931 return this.get('recordOffset'); 932 }, 933 934 /** 935 * Move the record offset to a new starting index. This will likely cause 936 * the calculated current page to change. You should probably use setPage. 937 * @method setStartIndex 938 * @param offset {number} the new record offset 939 * @param silent {boolean} whether to forcibly avoid firing the changeRequest event 940 */ 941 setStartIndex : function (offset,silent) { 942 if (Paginator.isNumeric(offset) && +offset >= 0 && 943 +offset !== this.get('recordOffset')) { 944 if (this.get('updateOnChange') || silent) { 945 this.set('recordOffset',offset); 946 } else { 947 this.fireEvent('changeRequest', 948 this.getState({'recordOffset':+offset})); 949 } 950 } 951 }, 952 953 /** 954 * Get an object literal describing the current state of the paginator. If 955 * an object literal of proposed values is passed, the proposed state will 956 * be returned as an object literal with the following keys: 957 * <ul> 958 * <li>paginator - instance of the Paginator</li> 959 * <li>page - number</li> 960 * <li>totalRecords - number</li> 961 * <li>recordOffset - number</li> 962 * <li>rowsPerPage - number</li> 963 * <li>records - [ start_index, end_index ]</li> 964 * <li>before - (OPTIONAL) { state object literal for current state }</li> 965 * </ul> 966 * @method getState 967 * @return {object} 968 * @param changes {object} OPTIONAL object literal with proposed values 969 * Supported change keys include: 970 * <ul> 971 * <li>rowsPerPage</li> 972 * <li>totalRecords</li> 973 * <li>recordOffset OR</li> 974 * <li>page</li> 975 * </ul> 976 */ 977 getState : function (changes) { 978 var UNLIMITED = Paginator.VALUE_UNLIMITED, 979 M = Math, max = M.max, ceil = M.ceil, 980 currentState, state, offset; 981 982 function normalizeOffset(offset,total,rpp) { 983 if (offset <= 0 || total === 0) { 984 return 0; 985 } 986 if (total === UNLIMITED || total > offset) { 987 return offset - (offset % rpp); 988 } 989 return total - (total % rpp || rpp); 990 } 991 992 currentState = { 993 paginator : this, 994 totalRecords : this.get('totalRecords'), 995 rowsPerPage : this.get('rowsPerPage'), 996 records : this.getPageRecords() 997 }; 998 currentState.recordOffset = normalizeOffset( 999 this.get('recordOffset'), 1000 currentState.totalRecords, 1001 currentState.rowsPerPage); 1002 currentState.page = ceil(currentState.recordOffset / 1003 currentState.rowsPerPage) + 1; 1004 1005 if (!changes) { 1006 return currentState; 1007 } 1008 1009 state = { 1010 paginator : this, 1011 before : currentState, 1012 1013 rowsPerPage : changes.rowsPerPage || currentState.rowsPerPage, 1014 totalRecords : (Paginator.isNumeric(changes.totalRecords) ? 1015 max(changes.totalRecords,UNLIMITED) : 1016 +currentState.totalRecords) 1017 }; 1018 1019 if (state.totalRecords === 0) { 1020 state.recordOffset = 1021 state.page = 0; 1022 } else { 1023 offset = Paginator.isNumeric(changes.page) ? 1024 (changes.page - 1) * state.rowsPerPage : 1025 Paginator.isNumeric(changes.recordOffset) ? 1026 +changes.recordOffset : 1027 currentState.recordOffset; 1028 1029 state.recordOffset = normalizeOffset(offset, 1030 state.totalRecords, 1031 state.rowsPerPage); 1032 1033 state.page = ceil(state.recordOffset / state.rowsPerPage) + 1; 1034 } 1035 1036 state.records = [ state.recordOffset, 1037 state.recordOffset + state.rowsPerPage - 1 ]; 1038 1039 // limit upper index to totalRecords - 1 1040 if (state.totalRecords !== UNLIMITED && 1041 state.recordOffset < state.totalRecords && state.records && 1042 state.records[1] > state.totalRecords - 1) { 1043 state.records[1] = state.totalRecords - 1; 1044 } 1045 1046 return state; 1047 }, 1048 1049 /** 1050 * Convenience method to facilitate setting state attributes rowsPerPage, 1051 * totalRecords, recordOffset in batch. Also supports calculating 1052 * recordOffset from state.page if state.recordOffset is not provided. 1053 * Fires only a single pageChange event, if appropriate. 1054 * This will not fire a changeRequest event. 1055 * @method setState 1056 * @param state {Object} Object literal of attribute:value pairs to set 1057 */ 1058 setState : function (state) { 1059 if (isObject(state)) { 1060 // get flux state based on current state with before state as well 1061 this._state = this.getState({}); 1062 1063 // use just the state props from the input obj 1064 state = { 1065 page : state.page, 1066 rowsPerPage : state.rowsPerPage, 1067 totalRecords : state.totalRecords, 1068 recordOffset : state.recordOffset 1069 }; 1070 1071 // calculate recordOffset from page if recordOffset not specified. 1072 // not using lang.isNumber for support of numeric strings 1073 if (state.page && state.recordOffset === undefined) { 1074 state.recordOffset = (state.page - 1) * 1075 (state.rowsPerPage || this.get('rowsPerPage')); 1076 } 1077 1078 this._batch = true; 1079 this._pageChanged = false; 1080 1081 for (var k in state) { 1082 if (state.hasOwnProperty(k) && this._configs.hasOwnProperty(k)) { 1083 this.set(k,state[k]); 1084 } 1085 } 1086 1087 this._batch = false; 1088 1089 if (this._pageChanged) { 1090 this._pageChanged = false; 1091 1092 this._firePageChange(this.getState(this._state)); 1093 } 1094 } 1095 } 1096 }; 1097 1098 lang.augmentProto(Paginator, YAHOO.util.AttributeProvider); 1099 1100 YAHOO.widget.Paginator = Paginator; 1101 })(); 1102 (function () { 1103 1104 var Paginator = YAHOO.widget.Paginator, 1105 l = YAHOO.lang, 1106 setId = YAHOO.util.Dom.generateId; 1107 1108 /** 1109 * ui Component to generate the textual report of current pagination status. 1110 * E.g. "Now viewing page 1 of 13". 1111 * 1112 * @namespace YAHOO.widget.Paginator.ui 1113 * @class CurrentPageReport 1114 * @for YAHOO.widget.Paginator 1115 * 1116 * @constructor 1117 * @param p {Pagintor} Paginator instance to attach to 1118 */ 1119 Paginator.ui.CurrentPageReport = function (p) { 1120 this.paginator = p; 1121 1122 p.subscribe('recordOffsetChange', this.update,this,true); 1123 p.subscribe('rowsPerPageChange', this.update,this,true); 1124 p.subscribe('totalRecordsChange',this.update,this,true); 1125 p.subscribe('pageReportTemplateChange', this.update,this,true); 1126 p.subscribe('destroy',this.destroy,this,true); 1127 1128 //TODO: make this work 1129 p.subscribe('pageReportClassChange', this.update,this,true); 1130 }; 1131 1132 /** 1133 * Decorates Paginator instances with new attributes. Called during 1134 * Paginator instantiation. 1135 * @method init 1136 * @param p {Paginator} Paginator instance to decorate 1137 * @static 1138 */ 1139 Paginator.ui.CurrentPageReport.init = function (p) { 1140 1141 /** 1142 * CSS class assigned to the span containing the info. 1143 * @attribute pageReportClass 1144 * @default 'yui-pg-current' 1145 */ 1146 p.setAttributeConfig('pageReportClass', { 1147 value : 'yui-pg-current', 1148 validator : l.isString 1149 }); 1150 1151 /** 1152 * Used as innerHTML for the span. Place holders in the form of {name} 1153 * will be replaced with the so named value from the key:value map 1154 * generated by the function held in the pageReportValueGenerator attribute. 1155 * @attribute pageReportTemplate 1156 * @default '({currentPage} of {totalPages})' 1157 * @see pageReportValueGenerator attribute 1158 */ 1159 p.setAttributeConfig('pageReportTemplate', { 1160 value : '({currentPage} of {totalPages})', 1161 validator : l.isString 1162 }); 1163 1164 /** 1165 * Function to generate the value map used to populate the 1166 * pageReportTemplate. The function is passed the Paginator instance as a 1167 * parameter. The default function returns a map with the following keys: 1168 * <ul> 1169 * <li>currentPage</li> 1170 * <li>totalPages</li> 1171 * <li>startIndex</li> 1172 * <li>endIndex</li> 1173 * <li>startRecord</li> 1174 * <li>endRecord</li> 1175 * <li>totalRecords</li> 1176 * </ul> 1177 * @attribute pageReportValueGenarator 1178 */ 1179 p.setAttributeConfig('pageReportValueGenerator', { 1180 value : function (paginator) { 1181 var curPage = paginator.getCurrentPage(), 1182 records = paginator.getPageRecords(); 1183 1184 return { 1185 'currentPage' : records ? curPage : 0, 1186 'totalPages' : paginator.getTotalPages(), 1187 'startIndex' : records ? records[0] : 0, 1188 'endIndex' : records ? records[1] : 0, 1189 'startRecord' : records ? records[0] + 1 : 0, 1190 'endRecord' : records ? records[1] + 1 : 0, 1191 'totalRecords': paginator.get('totalRecords') 1192 }; 1193 }, 1194 validator : l.isFunction 1195 }); 1196 }; 1197 1198 /** 1199 * Replace place holders in a string with the named values found in an 1200 * object literal. 1201 * @static 1202 * @method sprintf 1203 * @param template {string} The content string containing place holders 1204 * @param values {object} The key:value pairs used to replace the place holders 1205 * @return {string} 1206 */ 1207 Paginator.ui.CurrentPageReport.sprintf = function (template, values) { 1208 return template.replace(/\{([\w\s\-]+)\}/g, function (x,key) { 1209 return (key in values) ? values[key] : ''; 1210 }); 1211 }; 1212 1213 Paginator.ui.CurrentPageReport.prototype = { 1214 1215 /** 1216 * Span node containing the formatted info 1217 * @property span 1218 * @type HTMLElement 1219 * @private 1220 */ 1221 span : null, 1222 1223 1224 /** 1225 * Generate the span containing info formatted per the pageReportTemplate 1226 * attribute. 1227 * @method render 1228 * @param id_base {string} used to create unique ids for generated nodes 1229 * @return {HTMLElement} 1230 */ 1231 render : function (id_base) { 1232 this.span = document.createElement('span'); 1233 this.span.className = this.paginator.get('pageReportClass'); 1234 setId(this.span, id_base + '-page-report'); 1235 this.update(); 1236 1237 return this.span; 1238 }, 1239 1240 /** 1241 * Regenerate the content of the span if appropriate. Calls 1242 * CurrentPageReport.sprintf with the value of the pageReportTemplate 1243 * attribute and the value map returned from pageReportValueGenerator 1244 * function. 1245 * @method update 1246 * @param e {CustomEvent} The calling change event 1247 */ 1248 update : function (e) { 1249 if (e && e.prevValue === e.newValue) { 1250 return; 1251 } 1252 1253 this.span.innerHTML = Paginator.ui.CurrentPageReport.sprintf( 1254 this.paginator.get('pageReportTemplate'), 1255 this.paginator.get('pageReportValueGenerator')(this.paginator)); 1256 }, 1257 1258 /** 1259 * Removes the link/span node and clears event listeners 1260 * removal. 1261 * @method destroy 1262 * @private 1263 */ 1264 destroy : function () { 1265 this.span.parentNode.removeChild(this.span); 1266 this.span = null; 1267 } 1268 1269 }; 1270 1271 })(); 1272 (function () { 1273 1274 var Paginator = YAHOO.widget.Paginator, 1275 l = YAHOO.lang, 1276 setId = YAHOO.util.Dom.generateId; 1277 1278 /** 1279 * ui Component to generate the page links 1280 * 1281 * @namespace YAHOO.widget.Paginator.ui 1282 * @class PageLinks 1283 * @for YAHOO.widget.Paginator 1284 * 1285 * @constructor 1286 * @param p {Pagintor} Paginator instance to attach to 1287 */ 1288 Paginator.ui.PageLinks = function (p) { 1289 this.paginator = p; 1290 1291 p.subscribe('recordOffsetChange',this.update,this,true); 1292 p.subscribe('rowsPerPageChange',this.update,this,true); 1293 p.subscribe('totalRecordsChange',this.update,this,true); 1294 p.subscribe('pageLinksChange', this.rebuild,this,true); 1295 p.subscribe('pageLinkClassChange', this.rebuild,this,true); 1296 p.subscribe('currentPageClassChange', this.rebuild,this,true); 1297 p.subscribe('destroy',this.destroy,this,true); 1298 1299 //TODO: Make this work 1300 p.subscribe('pageLinksContainerClassChange', this.rebuild,this,true); 1301 }; 1302 1303 /** 1304 * Decorates Paginator instances with new attributes. Called during 1305 * Paginator instantiation. 1306 * @method init 1307 * @param p {Paginator} Paginator instance to decorate 1308 * @static 1309 */ 1310 Paginator.ui.PageLinks.init = function (p) { 1311 1312 /** 1313 * CSS class assigned to each page link/span. 1314 * @attribute pageLinkClass 1315 * @default 'yui-pg-page' 1316 */ 1317 p.setAttributeConfig('pageLinkClass', { 1318 value : 'yui-pg-page', 1319 validator : l.isString 1320 }); 1321 1322 /** 1323 * CSS class assigned to the current page span. 1324 * @attribute currentPageClass 1325 * @default 'yui-pg-current-page' 1326 */ 1327 p.setAttributeConfig('currentPageClass', { 1328 value : 'yui-pg-current-page', 1329 validator : l.isString 1330 }); 1331 1332 /** 1333 * CSS class assigned to the span containing the page links. 1334 * @attribute pageLinksContainerClass 1335 * @default 'yui-pg-pages' 1336 */ 1337 p.setAttributeConfig('pageLinksContainerClass', { 1338 value : 'yui-pg-pages', 1339 validator : l.isString 1340 }); 1341 1342 /** 1343 * Maximum number of page links to display at one time. 1344 * @attribute pageLinks 1345 * @default 10 1346 */ 1347 p.setAttributeConfig('pageLinks', { 1348 value : 10, 1349 validator : Paginator.isNumeric 1350 }); 1351 1352 /** 1353 * Function used generate the innerHTML for each page link/span. The 1354 * function receives as parameters the page number and a reference to the 1355 * paginator object. 1356 * @attribute pageLabelBuilder 1357 * @default function (page, paginator) { return page; } 1358 */ 1359 p.setAttributeConfig('pageLabelBuilder', { 1360 value : function (page, paginator) { return page; }, 1361 validator : l.isFunction 1362 }); 1363 1364 /** 1365 * Function used generate the title for each page link. The 1366 * function receives as parameters the page number and a reference to the 1367 * paginator object. 1368 * @attribute pageTitleBuilder 1369 * @default function (page, paginator) { return page; } 1370 */ 1371 p.setAttributeConfig('pageTitleBuilder', { 1372 value : function (page, paginator) { return "Page " + page; }, 1373 validator : l.isFunction 1374 }); 1375 }; 1376 1377 /** 1378 * Calculates start and end page numbers given a current page, attempting 1379 * to keep the current page in the middle 1380 * @static 1381 * @method calculateRange 1382 * @param {int} currentPage The current page 1383 * @param {int} totalPages (optional) Maximum number of pages 1384 * @param {int} numPages (optional) Preferred number of pages in range 1385 * @return {Array} [start_page_number, end_page_number] 1386 */ 1387 Paginator.ui.PageLinks.calculateRange = function (currentPage,totalPages,numPages) { 1388 var UNLIMITED = Paginator.VALUE_UNLIMITED, 1389 start, end, delta; 1390 1391 // Either has no pages, or unlimited pages. Show none. 1392 if (!currentPage || numPages === 0 || totalPages === 0 || 1393 (totalPages === UNLIMITED && numPages === UNLIMITED)) { 1394 return [0,-1]; 1395 } 1396 1397 // Limit requested pageLinks if there are fewer totalPages 1398 if (totalPages !== UNLIMITED) { 1399 numPages = numPages === UNLIMITED ? 1400 totalPages : 1401 Math.min(numPages,totalPages); 1402 } 1403 1404 // Determine start and end, trying to keep current in the middle 1405 start = Math.max(1,Math.ceil(currentPage - (numPages/2))); 1406 if (totalPages === UNLIMITED) { 1407 end = start + numPages - 1; 1408 } else { 1409 end = Math.min(totalPages, start + numPages - 1); 1410 } 1411 1412 // Adjust the start index when approaching the last page 1413 delta = numPages - (end - start + 1); 1414 start = Math.max(1, start - delta); 1415 1416 return [start,end]; 1417 }; 1418 1419 1420 Paginator.ui.PageLinks.prototype = { 1421 1422 /** 1423 * Current page 1424 * @property current 1425 * @type number 1426 * @private 1427 */ 1428 current : 0, 1429 1430 /** 1431 * Span node containing the page links 1432 * @property container 1433 * @type HTMLElement 1434 * @private 1435 */ 1436 container : null, 1437 1438 1439 /** 1440 * Generate the nodes and return the container node containing page links 1441 * appropriate to the current pagination state. 1442 * @method render 1443 * @param id_base {string} used to create unique ids for generated nodes 1444 * @return {HTMLElement} 1445 */ 1446 render : function (id_base) { 1447 var p = this.paginator; 1448 1449 // Set up container 1450 this.container = document.createElement('span'); 1451 setId(this.container, id_base + '-pages'); 1452 this.container.className = p.get('pageLinksContainerClass'); 1453 YAHOO.util.Event.on(this.container,'click',this.onClick,this,true); 1454 1455 // Call update, flagging a need to rebuild 1456 this.update({newValue : null, rebuild : true}); 1457 1458 return this.container; 1459 }, 1460 1461 /** 1462 * Update the links if appropriate 1463 * @method update 1464 * @param e {CustomEvent} The calling change event 1465 */ 1466 update : function (e) { 1467 if (e && e.prevValue === e.newValue) { 1468 return; 1469 } 1470 1471 var p = this.paginator, 1472 currentPage = p.getCurrentPage(); 1473 1474 // Replace content if there's been a change 1475 if (this.current !== currentPage || !currentPage || e.rebuild) { 1476 var labelBuilder = p.get('pageLabelBuilder'), 1477 titleBuilder = p.get('pageTitleBuilder'), 1478 range = Paginator.ui.PageLinks.calculateRange( 1479 currentPage, 1480 p.getTotalPages(), 1481 p.get('pageLinks')), 1482 start = range[0], 1483 end = range[1], 1484 content = '', 1485 linkTemplate,i,spanTemplate; 1486 1487 linkTemplate = '<a href="#" class="{class}" page="{page}" title="{title}">{label}</a>'; 1488 spanTemplate = '<span class="{class}">{label}</span>'; 1489 for (i = start; i <= end; ++i) { 1490 1491 if (i === currentPage) { 1492 content += l.substitute(spanTemplate, { 1493 'class' : p.get('currentPageClass') + ' ' + p.get('pageLinkClass'), 1494 'label' : labelBuilder(i,p) 1495 }); 1496 1497 } else { 1498 content += l.substitute(linkTemplate, { 1499 'class' : p.get('pageLinkClass'), 1500 'page' : i, 1501 'label' : labelBuilder(i,p), 1502 'title' : titleBuilder(i,p) 1503 }); 1504 } 1505 } 1506 1507 this.container.innerHTML = content; 1508 } 1509 }, 1510 1511 /** 1512 * Force a rebuild of the page links. 1513 * @method rebuild 1514 * @param e {CustomEvent} The calling change event 1515 */ 1516 rebuild : function (e) { 1517 e.rebuild = true; 1518 this.update(e); 1519 }, 1520 1521 /** 1522 * Removes the page links container node and clears event listeners 1523 * @method destroy 1524 * @private 1525 */ 1526 destroy : function () { 1527 YAHOO.util.Event.purgeElement(this.container,true); 1528 this.container.parentNode.removeChild(this.container); 1529 this.container = null; 1530 }, 1531 1532 /** 1533 * Listener for the container's onclick event. Looks for qualifying link 1534 * clicks, and pulls the page number from the link's page attribute. 1535 * Sends link's page attribute to the Paginator's setPage method. 1536 * @method onClick 1537 * @param e {DOMEvent} The click event 1538 */ 1539 onClick : function (e) { 1540 var t = YAHOO.util.Event.getTarget(e); 1541 if (t && YAHOO.util.Dom.hasClass(t, 1542 this.paginator.get('pageLinkClass'))) { 1543 1544 YAHOO.util.Event.stopEvent(e); 1545 1546 this.paginator.setPage(parseInt(t.getAttribute('page'),10)); 1547 } 1548 } 1549 1550 }; 1551 1552 })(); 1553 (function () { 1554 1555 var Paginator = YAHOO.widget.Paginator, 1556 l = YAHOO.lang, 1557 setId = YAHOO.util.Dom.generateId; 1558 1559 /** 1560 * ui Component to generate the link to jump to the first page. 1561 * 1562 * @namespace YAHOO.widget.Paginator.ui 1563 * @class FirstPageLink 1564 * @for YAHOO.widget.Paginator 1565 * 1566 * @constructor 1567 * @param p {Pagintor} Paginator instance to attach to 1568 */ 1569 Paginator.ui.FirstPageLink = function (p) { 1570 this.paginator = p; 1571 1572 p.subscribe('recordOffsetChange',this.update,this,true); 1573 p.subscribe('rowsPerPageChange',this.update,this,true); 1574 p.subscribe('totalRecordsChange',this.update,this,true); 1575 p.subscribe('destroy',this.destroy,this,true); 1576 1577 // TODO: make this work 1578 p.subscribe('firstPageLinkLabelChange',this.update,this,true); 1579 p.subscribe('firstPageLinkClassChange',this.update,this,true); 1580 }; 1581 1582 /** 1583 * Decorates Paginator instances with new attributes. Called during 1584 * Paginator instantiation. 1585 * @method init 1586 * @param p {Paginator} Paginator instance to decorate 1587 * @static 1588 */ 1589 Paginator.ui.FirstPageLink.init = function (p) { 1590 1591 /** 1592 * Used as innerHTML for the first page link/span. 1593 * @attribute firstPageLinkLabel 1594 * @default '<< first' 1595 */ 1596 p.setAttributeConfig('firstPageLinkLabel', { 1597 value : '<< first', 1598 validator : l.isString 1599 }); 1600 1601 /** 1602 * CSS class assigned to the link/span 1603 * @attribute firstPageLinkClass 1604 * @default 'yui-pg-first' 1605 */ 1606 p.setAttributeConfig('firstPageLinkClass', { 1607 value : 'yui-pg-first', 1608 validator : l.isString 1609 }); 1610 1611 /** 1612 * Used as title for the first page link. 1613 * @attribute firstPageLinkTitle 1614 * @default 'First Page' 1615 */ 1616 p.setAttributeConfig('firstPageLinkTitle', { 1617 value : 'First Page', 1618 validator : l.isString 1619 }); 1620 }; 1621 1622 // Instance members and methods 1623 Paginator.ui.FirstPageLink.prototype = { 1624 1625 /** 1626 * The currently placed HTMLElement node 1627 * @property current 1628 * @type HTMLElement 1629 * @private 1630 */ 1631 current : null, 1632 1633 /** 1634 * Link node 1635 * @property link 1636 * @type HTMLElement 1637 * @private 1638 */ 1639 link : null, 1640 1641 /** 1642 * Span node (inactive link) 1643 * @property span 1644 * @type HTMLElement 1645 * @private 1646 */ 1647 span : null, 1648 1649 /** 1650 * Generate the nodes and return the appropriate node given the current 1651 * pagination state. 1652 * @method render 1653 * @param id_base {string} used to create unique ids for generated nodes 1654 * @return {HTMLElement} 1655 */ 1656 render : function (id_base) { 1657 var p = this.paginator, 1658 c = p.get('firstPageLinkClass'), 1659 label = p.get('firstPageLinkLabel'), 1660 title = p.get('firstPageLinkTitle'); 1661 1662 this.link = document.createElement('a'); 1663 this.span = document.createElement('span'); 1664 1665 setId(this.link, id_base + '-first-link'); 1666 this.link.href = '#'; 1667 this.link.className = c; 1668 this.link.innerHTML = label; 1669 this.link.title = title; 1670 YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); 1671 1672 setId(this.span, id_base + '-first-span'); 1673 this.span.className = c; 1674 this.span.innerHTML = label; 1675 1676 this.current = p.getCurrentPage() > 1 ? this.link : this.span; 1677 return this.current; 1678 }, 1679 1680 /** 1681 * Swap the link and span nodes if appropriate. 1682 * @method update 1683 * @param e {CustomEvent} The calling change event 1684 */ 1685 update : function (e) { 1686 if (e && e.prevValue === e.newValue) { 1687 return; 1688 } 1689 1690 var par = this.current ? this.current.parentNode : null; 1691 if (this.paginator.getCurrentPage() > 1) { 1692 if (par && this.current === this.span) { 1693 par.replaceChild(this.link,this.current); 1694 this.current = this.link; 1695 } 1696 } else { 1697 if (par && this.current === this.link) { 1698 par.replaceChild(this.span,this.current); 1699 this.current = this.span; 1700 } 1701 } 1702 }, 1703 1704 /** 1705 * Removes the link/span node and clears event listeners 1706 * removal. 1707 * @method destroy 1708 * @private 1709 */ 1710 destroy : function () { 1711 YAHOO.util.Event.purgeElement(this.link); 1712 this.current.parentNode.removeChild(this.current); 1713 this.link = this.span = null; 1714 }, 1715 1716 /** 1717 * Listener for the link's onclick event. Pass new value to setPage method. 1718 * @method onClick 1719 * @param e {DOMEvent} The click event 1720 */ 1721 onClick : function (e) { 1722 YAHOO.util.Event.stopEvent(e); 1723 this.paginator.setPage(1); 1724 } 1725 }; 1726 1727 })(); 1728 (function () { 1729 1730 var Paginator = YAHOO.widget.Paginator, 1731 l = YAHOO.lang, 1732 setId = YAHOO.util.Dom.generateId; 1733 1734 /** 1735 * ui Component to generate the link to jump to the last page. 1736 * 1737 * @namespace YAHOO.widget.Paginator.ui 1738 * @class LastPageLink 1739 * @for YAHOO.widget.Paginator 1740 * 1741 * @constructor 1742 * @param p {Pagintor} Paginator instance to attach to 1743 */ 1744 Paginator.ui.LastPageLink = function (p) { 1745 this.paginator = p; 1746 1747 p.subscribe('recordOffsetChange',this.update,this,true); 1748 p.subscribe('rowsPerPageChange',this.update,this,true); 1749 p.subscribe('totalRecordsChange',this.update,this,true); 1750 p.subscribe('destroy',this.destroy,this,true); 1751 1752 // TODO: make this work 1753 p.subscribe('lastPageLinkLabelChange',this.update,this,true); 1754 p.subscribe('lastPageLinkClassChange', this.update,this,true); 1755 }; 1756 1757 /** 1758 * Decorates Paginator instances with new attributes. Called during 1759 * Paginator instantiation. 1760 * @method init 1761 * @param paginator {Paginator} Paginator instance to decorate 1762 * @static 1763 */ 1764 Paginator.ui.LastPageLink.init = function (p) { 1765 1766 /** 1767 * Used as innerHTML for the last page link/span. 1768 * @attribute lastPageLinkLabel 1769 * @default 'last >>' 1770 */ 1771 p.setAttributeConfig('lastPageLinkLabel', { 1772 value : 'last >>', 1773 validator : l.isString 1774 }); 1775 1776 /** 1777 * CSS class assigned to the link/span 1778 * @attribute lastPageLinkClass 1779 * @default 'yui-pg-last' 1780 */ 1781 p.setAttributeConfig('lastPageLinkClass', { 1782 value : 'yui-pg-last', 1783 validator : l.isString 1784 }); 1785 1786 /** 1787 * Used as title for the last page link. 1788 * @attribute lastPageLinkTitle 1789 * @default 'Last Page' 1790 */ 1791 p.setAttributeConfig('lastPageLinkTitle', { 1792 value : 'Last Page', 1793 validator : l.isString 1794 }); 1795 1796 }; 1797 1798 Paginator.ui.LastPageLink.prototype = { 1799 1800 /** 1801 * Currently placed HTMLElement node 1802 * @property current 1803 * @type HTMLElement 1804 * @private 1805 */ 1806 current : null, 1807 1808 /** 1809 * Link HTMLElement node 1810 * @property link 1811 * @type HTMLElement 1812 * @private 1813 */ 1814 link : null, 1815 1816 /** 1817 * Span node (inactive link) 1818 * @property span 1819 * @type HTMLElement 1820 * @private 1821 */ 1822 span : null, 1823 1824 /** 1825 * Empty place holder node for when the last page link is inappropriate to 1826 * display in any form (unlimited paging). 1827 * @property na 1828 * @type HTMLElement 1829 * @private 1830 */ 1831 na : null, 1832 1833 1834 /** 1835 * Generate the nodes and return the appropriate node given the current 1836 * pagination state. 1837 * @method render 1838 * @param id_base {string} used to create unique ids for generated nodes 1839 * @return {HTMLElement} 1840 */ 1841 render : function (id_base) { 1842 var p = this.paginator, 1843 c = p.get('lastPageLinkClass'), 1844 label = p.get('lastPageLinkLabel'), 1845 last = p.getTotalPages(), 1846 title = p.get('lastPageLinkTitle'); 1847 1848 this.link = document.createElement('a'); 1849 this.span = document.createElement('span'); 1850 this.na = this.span.cloneNode(false); 1851 1852 setId(this.link, id_base + '-last-link'); 1853 this.link.href = '#'; 1854 this.link.className = c; 1855 this.link.innerHTML = label; 1856 this.link.title = title; 1857 YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); 1858 1859 setId(this.span, id_base + '-last-span'); 1860 this.span.className = c; 1861 this.span.innerHTML = label; 1862 1863 setId(this.na, id_base + '-last-na'); 1864 1865 switch (last) { 1866 case Paginator.VALUE_UNLIMITED : 1867 this.current = this.na; break; 1868 case p.getCurrentPage() : 1869 this.current = this.span; break; 1870 default : 1871 this.current = this.link; 1872 } 1873 1874 return this.current; 1875 }, 1876 1877 /** 1878 * Swap the link, span, and na nodes if appropriate. 1879 * @method update 1880 * @param e {CustomEvent} The calling change event (ignored) 1881 */ 1882 update : function (e) { 1883 if (e && e.prevValue === e.newValue) { 1884 return; 1885 } 1886 1887 var par = this.current ? this.current.parentNode : null, 1888 after = this.link; 1889 1890 if (par) { 1891 switch (this.paginator.getTotalPages()) { 1892 case Paginator.VALUE_UNLIMITED : 1893 after = this.na; break; 1894 case this.paginator.getCurrentPage() : 1895 after = this.span; break; 1896 } 1897 1898 if (this.current !== after) { 1899 par.replaceChild(after,this.current); 1900 this.current = after; 1901 } 1902 } 1903 }, 1904 1905 /** 1906 * Removes the link/span node and clears event listeners 1907 * @method destroy 1908 * @private 1909 */ 1910 destroy : function () { 1911 YAHOO.util.Event.purgeElement(this.link); 1912 this.current.parentNode.removeChild(this.current); 1913 this.link = this.span = null; 1914 }, 1915 1916 /** 1917 * Listener for the link's onclick event. Passes to setPage method. 1918 * @method onClick 1919 * @param e {DOMEvent} The click event 1920 */ 1921 onClick : function (e) { 1922 YAHOO.util.Event.stopEvent(e); 1923 this.paginator.setPage(this.paginator.getTotalPages()); 1924 } 1925 }; 1926 1927 })(); 1928 (function () { 1929 1930 var Paginator = YAHOO.widget.Paginator, 1931 l = YAHOO.lang, 1932 setId = YAHOO.util.Dom.generateId; 1933 1934 /** 1935 * ui Component to generate the link to jump to the next page. 1936 * 1937 * @namespace YAHOO.widget.Paginator.ui 1938 * @class NextPageLink 1939 * @for YAHOO.widget.Paginator 1940 * 1941 * @constructor 1942 * @param p {Pagintor} Paginator instance to attach to 1943 */ 1944 Paginator.ui.NextPageLink = function (p) { 1945 this.paginator = p; 1946 1947 p.subscribe('recordOffsetChange', this.update,this,true); 1948 p.subscribe('rowsPerPageChange', this.update,this,true); 1949 p.subscribe('totalRecordsChange', this.update,this,true); 1950 p.subscribe('destroy',this.destroy,this,true); 1951 1952 // TODO: make this work 1953 p.subscribe('nextPageLinkLabelChange', this.update,this,true); 1954 p.subscribe('nextPageLinkClassChange', this.update,this,true); 1955 }; 1956 1957 /** 1958 * Decorates Paginator instances with new attributes. Called during 1959 * Paginator instantiation. 1960 * @method init 1961 * @param p {Paginator} Paginator instance to decorate 1962 * @static 1963 */ 1964 Paginator.ui.NextPageLink.init = function (p) { 1965 1966 /** 1967 * Used as innerHTML for the next page link/span. 1968 * @attribute nextPageLinkLabel 1969 * @default 'next >' 1970 */ 1971 p.setAttributeConfig('nextPageLinkLabel', { 1972 value : 'next >', 1973 validator : l.isString 1974 }); 1975 1976 /** 1977 * CSS class assigned to the link/span 1978 * @attribute nextPageLinkClass 1979 * @default 'yui-pg-next' 1980 */ 1981 p.setAttributeConfig('nextPageLinkClass', { 1982 value : 'yui-pg-next', 1983 validator : l.isString 1984 }); 1985 1986 /** 1987 * Used as title for the next page link. 1988 * @attribute nextPageLinkTitle 1989 * @default 'Next Page' 1990 */ 1991 p.setAttributeConfig('nextPageLinkTitle', { 1992 value : 'Next Page', 1993 validator : l.isString 1994 }); 1995 1996 }; 1997 1998 Paginator.ui.NextPageLink.prototype = { 1999 2000 /** 2001 * Currently placed HTMLElement node 2002 * @property current 2003 * @type HTMLElement 2004 * @private 2005 */ 2006 current : null, 2007 2008 /** 2009 * Link node 2010 * @property link 2011 * @type HTMLElement 2012 * @private 2013 */ 2014 link : null, 2015 2016 /** 2017 * Span node (inactive link) 2018 * @property span 2019 * @type HTMLElement 2020 * @private 2021 */ 2022 span : null, 2023 2024 2025 /** 2026 * Generate the nodes and return the appropriate node given the current 2027 * pagination state. 2028 * @method render 2029 * @param id_base {string} used to create unique ids for generated nodes 2030 * @return {HTMLElement} 2031 */ 2032 render : function (id_base) { 2033 var p = this.paginator, 2034 c = p.get('nextPageLinkClass'), 2035 label = p.get('nextPageLinkLabel'), 2036 last = p.getTotalPages(), 2037 title = p.get('nextPageLinkTitle'); 2038 2039 this.link = document.createElement('a'); 2040 this.span = document.createElement('span'); 2041 2042 setId(this.link, id_base + '-next-link'); 2043 this.link.href = '#'; 2044 this.link.className = c; 2045 this.link.innerHTML = label; 2046 this.link.title = title; 2047 YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); 2048 2049 setId(this.span, id_base + '-next-span'); 2050 this.span.className = c; 2051 this.span.innerHTML = label; 2052 2053 this.current = p.getCurrentPage() === last ? this.span : this.link; 2054 2055 return this.current; 2056 }, 2057 2058 /** 2059 * Swap the link and span nodes if appropriate. 2060 * @method update 2061 * @param e {CustomEvent} The calling change event 2062 */ 2063 update : function (e) { 2064 if (e && e.prevValue === e.newValue) { 2065 return; 2066 } 2067 2068 var last = this.paginator.getTotalPages(), 2069 par = this.current ? this.current.parentNode : null; 2070 2071 if (this.paginator.getCurrentPage() !== last) { 2072 if (par && this.current === this.span) { 2073 par.replaceChild(this.link,this.current); 2074 this.current = this.link; 2075 } 2076 } else if (this.current === this.link) { 2077 if (par) { 2078 par.replaceChild(this.span,this.current); 2079 this.current = this.span; 2080 } 2081 } 2082 }, 2083 2084 /** 2085 * Removes the link/span node and clears event listeners 2086 * @method destroy 2087 * @private 2088 */ 2089 destroy : function () { 2090 YAHOO.util.Event.purgeElement(this.link); 2091 this.current.parentNode.removeChild(this.current); 2092 this.link = this.span = null; 2093 }, 2094 2095 /** 2096 * Listener for the link's onclick event. Passes to setPage method. 2097 * @method onClick 2098 * @param e {DOMEvent} The click event 2099 */ 2100 onClick : function (e) { 2101 YAHOO.util.Event.stopEvent(e); 2102 this.paginator.setPage(this.paginator.getNextPage()); 2103 } 2104 }; 2105 2106 })(); 2107 (function () { 2108 2109 var Paginator = YAHOO.widget.Paginator, 2110 l = YAHOO.lang, 2111 setId = YAHOO.util.Dom.generateId; 2112 2113 /** 2114 * ui Component to generate the link to jump to the previous page. 2115 * 2116 * @namespace YAHOO.widget.Paginator.ui 2117 * @class PreviousPageLink 2118 * @for YAHOO.widget.Paginator 2119 * 2120 * @constructor 2121 * @param p {Pagintor} Paginator instance to attach to 2122 */ 2123 Paginator.ui.PreviousPageLink = function (p) { 2124 this.paginator = p; 2125 2126 p.subscribe('recordOffsetChange',this.update,this,true); 2127 p.subscribe('rowsPerPageChange',this.update,this,true); 2128 p.subscribe('totalRecordsChange',this.update,this,true); 2129 p.subscribe('destroy',this.destroy,this,true); 2130 2131 // TODO: make this work 2132 p.subscribe('previousPageLinkLabelChange',this.update,this,true); 2133 p.subscribe('previousPageLinkClassChange',this.update,this,true); 2134 }; 2135 2136 /** 2137 * Decorates Paginator instances with new attributes. Called during 2138 * Paginator instantiation. 2139 * @method init 2140 * @param p {Paginator} Paginator instance to decorate 2141 * @static 2142 */ 2143 Paginator.ui.PreviousPageLink.init = function (p) { 2144 2145 /** 2146 * Used as innerHTML for the previous page link/span. 2147 * @attribute previousPageLinkLabel 2148 * @default '< prev' 2149 */ 2150 p.setAttributeConfig('previousPageLinkLabel', { 2151 value : '< prev', 2152 validator : l.isString 2153 }); 2154 2155 /** 2156 * CSS class assigned to the link/span 2157 * @attribute previousPageLinkClass 2158 * @default 'yui-pg-previous' 2159 */ 2160 p.setAttributeConfig('previousPageLinkClass', { 2161 value : 'yui-pg-previous', 2162 validator : l.isString 2163 }); 2164 2165 /** 2166 * Used as title for the previous page link. 2167 * @attribute previousPageLinkTitle 2168 * @default 'Previous Page' 2169 */ 2170 p.setAttributeConfig('previousPageLinkTitle', { 2171 value : 'Previous Page', 2172 validator : l.isString 2173 }); 2174 2175 }; 2176 2177 Paginator.ui.PreviousPageLink.prototype = { 2178 2179 /** 2180 * Currently placed HTMLElement node 2181 * @property current 2182 * @type HTMLElement 2183 * @private 2184 */ 2185 current : null, 2186 2187 /** 2188 * Link node 2189 * @property link 2190 * @type HTMLElement 2191 * @private 2192 */ 2193 link : null, 2194 2195 /** 2196 * Span node (inactive link) 2197 * @property span 2198 * @type HTMLElement 2199 * @private 2200 */ 2201 span : null, 2202 2203 2204 /** 2205 * Generate the nodes and return the appropriate node given the current 2206 * pagination state. 2207 * @method render 2208 * @param id_base {string} used to create unique ids for generated nodes 2209 * @return {HTMLElement} 2210 */ 2211 render : function (id_base) { 2212 var p = this.paginator, 2213 c = p.get('previousPageLinkClass'), 2214 label = p.get('previousPageLinkLabel'), 2215 title = p.get('previousPageLinkTitle'); 2216 2217 this.link = document.createElement('a'); 2218 this.span = document.createElement('span'); 2219 2220 setId(this.link, id_base + '-prev-link'); 2221 this.link.href = '#'; 2222 this.link.className = c; 2223 this.link.innerHTML = label; 2224 this.link.title = title; 2225 YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); 2226 2227 setId(this.span, id_base + '-prev-span'); 2228 this.span.className = c; 2229 this.span.innerHTML = label; 2230 2231 this.current = p.getCurrentPage() > 1 ? this.link : this.span; 2232 return this.current; 2233 }, 2234 2235 /** 2236 * Swap the link and span nodes if appropriate. 2237 * @method update 2238 * @param e {CustomEvent} The calling change event 2239 */ 2240 update : function (e) { 2241 if (e && e.prevValue === e.newValue) { 2242 return; 2243 } 2244 2245 var par = this.current ? this.current.parentNode : null; 2246 if (this.paginator.getCurrentPage() > 1) { 2247 if (par && this.current === this.span) { 2248 par.replaceChild(this.link,this.current); 2249 this.current = this.link; 2250 } 2251 } else { 2252 if (par && this.current === this.link) { 2253 par.replaceChild(this.span,this.current); 2254 this.current = this.span; 2255 } 2256 } 2257 }, 2258 2259 /** 2260 * Removes the link/span node and clears event listeners 2261 * @method destroy 2262 * @private 2263 */ 2264 destroy : function () { 2265 YAHOO.util.Event.purgeElement(this.link); 2266 this.current.parentNode.removeChild(this.current); 2267 this.link = this.span = null; 2268 }, 2269 2270 /** 2271 * Listener for the link's onclick event. Passes to setPage method. 2272 * @method onClick 2273 * @param e {DOMEvent} The click event 2274 */ 2275 onClick : function (e) { 2276 YAHOO.util.Event.stopEvent(e); 2277 this.paginator.setPage(this.paginator.getPreviousPage()); 2278 } 2279 }; 2280 2281 })(); 2282 (function () { 2283 2284 var Paginator = YAHOO.widget.Paginator, 2285 l = YAHOO.lang, 2286 setId = YAHOO.util.Dom.generateId; 2287 2288 /** 2289 * ui Component to generate the rows-per-page dropdown 2290 * 2291 * @namespace YAHOO.widget.Paginator.ui 2292 * @class RowsPerPageDropdown 2293 * @for YAHOO.widget.Paginator 2294 * 2295 * @constructor 2296 * @param p {Pagintor} Paginator instance to attach to 2297 */ 2298 Paginator.ui.RowsPerPageDropdown = function (p) { 2299 this.paginator = p; 2300 2301 p.subscribe('rowsPerPageChange',this.update,this,true); 2302 p.subscribe('rowsPerPageOptionsChange',this.rebuild,this,true); 2303 p.subscribe('totalRecordsChange',this._handleTotalRecordsChange,this,true); 2304 p.subscribe('destroy',this.destroy,this,true); 2305 2306 // TODO: make this work 2307 p.subscribe('rowsPerPageDropdownClassChange',this.rebuild,this,true); 2308 }; 2309 2310 /** 2311 * Decorates Paginator instances with new attributes. Called during 2312 * Paginator instantiation. 2313 * @method init 2314 * @param p {Paginator} Paginator instance to decorate 2315 * @static 2316 */ 2317 Paginator.ui.RowsPerPageDropdown.init = function (p) { 2318 2319 /** 2320 * Array of available rows-per-page sizes. Converted into select options. 2321 * Array values may be positive integers or object literals in the form<br> 2322 * { value : NUMBER, text : STRING } 2323 * @attribute rowsPerPageOptions 2324 * @default [] 2325 */ 2326 p.setAttributeConfig('rowsPerPageOptions', { 2327 value : [], 2328 validator : l.isArray 2329 }); 2330 2331 /** 2332 * CSS class assigned to the select node 2333 * @attribute rowsPerPageDropdownClass 2334 * @default 'yui-pg-rpp-options' 2335 */ 2336 p.setAttributeConfig('rowsPerPageDropdownClass', { 2337 value : 'yui-pg-rpp-options', 2338 validator : l.isString 2339 }); 2340 }; 2341 2342 Paginator.ui.RowsPerPageDropdown.prototype = { 2343 2344 /** 2345 * select node 2346 * @property select 2347 * @type HTMLElement 2348 * @private 2349 */ 2350 select : null, 2351 2352 2353 /** 2354 * option node for the optional All value 2355 * 2356 * @property all 2357 * @type HTMLElement 2358 * @protected 2359 */ 2360 all : null, 2361 2362 /** 2363 * Generate the select and option nodes and returns the select node. 2364 * @method render 2365 * @param id_base {string} used to create unique ids for generated nodes 2366 * @return {HTMLElement} 2367 */ 2368 render : function (id_base) { 2369 this.select = document.createElement('select'); 2370 setId(this.select, id_base + '-rpp'); 2371 this.select.className = this.paginator.get('rowsPerPageDropdownClass'); 2372 this.select.title = 'Rows per page'; 2373 2374 YAHOO.util.Event.on(this.select,'change',this.onChange,this,true); 2375 2376 this.rebuild(); 2377 2378 return this.select; 2379 }, 2380 2381 /** 2382 * (Re)generate the select options. 2383 * @method rebuild 2384 */ 2385 rebuild : function (e) { 2386 var p = this.paginator, 2387 sel = this.select, 2388 options = p.get('rowsPerPageOptions'), 2389 opt,cfg,val,i,len; 2390 2391 this.all = null; 2392 2393 for (i = 0, len = options.length; i < len; ++i) { 2394 cfg = options[i]; 2395 opt = sel.options[i] || 2396 sel.appendChild(document.createElement('option')); 2397 val = l.isValue(cfg.value) ? cfg.value : cfg; 2398 opt.text = l.isValue(cfg.text) ? cfg.text : cfg; 2399 2400 if (l.isString(val) && val.toLowerCase() === 'all') { 2401 this.all = opt; 2402 opt.value = p.get('totalRecords'); 2403 } else{ 2404 opt.value = val; 2405 } 2406 2407 } 2408 2409 while (sel.options.length > options.length) { 2410 sel.removeChild(sel.firstChild); 2411 } 2412 2413 this.update(); 2414 }, 2415 2416 /** 2417 * Select the appropriate option if changed. 2418 * @method update 2419 * @param e {CustomEvent} The calling change event 2420 */ 2421 update : function (e) { 2422 if (e && e.prevValue === e.newValue) { 2423 return; 2424 } 2425 2426 var rpp = this.paginator.get('rowsPerPage')+'', 2427 options = this.select.options, 2428 i,len; 2429 2430 for (i = 0, len = options.length; i < len; ++i) { 2431 if (options[i].value === rpp) { 2432 options[i].selected = true; 2433 break; 2434 } 2435 } 2436 }, 2437 2438 /** 2439 * Listener for the select's onchange event. Sent to setRowsPerPage method. 2440 * @method onChange 2441 * @param e {DOMEvent} The change event 2442 */ 2443 onChange : function (e) { 2444 this.paginator.setRowsPerPage( 2445 parseInt(this.select.options[this.select.selectedIndex].value,10)); 2446 }, 2447 2448 /** 2449 * Updates the all option value (and Paginator's rowsPerPage attribute if 2450 * necessary) in response to a change in the Paginator's totalRecords. 2451 * 2452 * @method _handleTotalRecordsChange 2453 * @param e {Event} attribute change event 2454 * @protected 2455 */ 2456 _handleTotalRecordsChange : function (e) { 2457 if (!this.all || (e && e.prevValue === e.newValue)) { 2458 return; 2459 } 2460 2461 this.all.value = e.newValue; 2462 if (this.all.selected) { 2463 this.paginator.set('rowsPerPage',e.newValue); 2464 } 2465 }, 2466 2467 /** 2468 * Removes the select node and clears event listeners 2469 * @method destroy 2470 * @private 2471 */ 2472 destroy : function () { 2473 YAHOO.util.Event.purgeElement(this.select); 2474 this.select.parentNode.removeChild(this.select); 2475 this.select = null; 2476 } 2477 }; 2478 2479 })(); 2480 (function () { 2481 2482 var Paginator = YAHOO.widget.Paginator, 2483 l = YAHOO.lang, 2484 setId = YAHOO.util.Dom.generateId; 2485 2486 /** 2487 * ui Component to generate the jump-to-page dropdown 2488 * 2489 * @namespace YAHOO.widget.Paginator.ui 2490 * @class JumpToPageDropdown 2491 * @for YAHOO.widget.Paginator 2492 * 2493 * @constructor 2494 * @param p {Pagintor} Paginator instance to attach to 2495 */ 2496 Paginator.ui.JumpToPageDropdown = function (p) { 2497 this.paginator = p; 2498 2499 p.subscribe('rowsPerPageChange',this.rebuild,this,true); 2500 p.subscribe('rowsPerPageOptionsChange',this.rebuild,this,true); 2501 p.subscribe('pageChange',this.update,this,true); 2502 p.subscribe('totalRecordsChange',this.rebuild,this,true); 2503 p.subscribe('destroy',this.destroy,this,true); 2504 2505 }; 2506 2507 /** 2508 * Decorates Paginator instances with new attributes. Called during 2509 * Paginator instantiation. 2510 * @method init 2511 * @param p {Paginator} Paginator instance to decorate 2512 * @static 2513 */ 2514 Paginator.ui.JumpToPageDropdown.init = function (p) { 2515 2516 2517 2518 /** 2519 * CSS class assigned to the select node 2520 * @attribute jumpToPageDropdownClass 2521 * @default 'yui-pg-jtp-options' 2522 */ 2523 p.setAttributeConfig('jumpToPageDropdownClass', { 2524 value : 'yui-pg-jtp-options', 2525 validator : l.isString 2526 }); 2527 }; 2528 2529 Paginator.ui.JumpToPageDropdown.prototype = { 2530 2531 /** 2532 * select node 2533 * @property select 2534 * @type HTMLElement 2535 * @private 2536 */ 2537 select : null, 2538 2539 2540 2541 /** 2542 * Generate the select and option nodes and returns the select node. 2543 * @method render 2544 * @param id_base {string} used to create unique ids for generated nodes 2545 * @return {HTMLElement} 2546 */ 2547 render : function (id_base) { 2548 this.select = document.createElement('select'); 2549 setId(this.select, id_base + '-jtp'); 2550 this.select.className = this.paginator.get('jumpToPageDropdownClass'); 2551 this.select.title = 'Jump to page'; 2552 2553 YAHOO.util.Event.on(this.select,'change',this.onChange,this,true); 2554 2555 this.rebuild(); 2556 2557 return this.select; 2558 }, 2559 2560 /** 2561 * (Re)generate the select options. 2562 * @method rebuild 2563 */ 2564 rebuild : function (e) { 2565 var p = this.paginator, 2566 sel = this.select, 2567 numPages = p.getTotalPages(), 2568 opt,i,len; 2569 2570 this.all = null; 2571 2572 for (i = 0, len = numPages; i < len; ++i ) { 2573 opt = sel.options[i] || 2574 sel.appendChild(document.createElement('option')); 2575 2576 opt.innerHTML = i + 1; 2577 2578 opt.value = i + 1; 2579 2580 2581 } 2582 2583 for ( i = numPages, len = sel.options.length ; i < len ; i++ ) { 2584 sel.removeChild(sel.lastChild); 2585 } 2586 2587 this.update(); 2588 }, 2589 2590 /** 2591 * Select the appropriate option if changed. 2592 * @method update 2593 * @param e {CustomEvent} The calling change event 2594 */ 2595 update : function (e) { 2596 2597 if (e && e.prevValue === e.newValue) { 2598 return; 2599 } 2600 2601 var cp = this.paginator.getCurrentPage()+'', 2602 options = this.select.options, 2603 i,len; 2604 2605 for (i = 0, len = options.length; i < len; ++i) { 2606 if (options[i].value === cp) { 2607 options[i].selected = true; 2608 break; 2609 } 2610 } 2611 }, 2612 2613 /** 2614 * Listener for the select's onchange event. Sent to setPage method. 2615 * @method onChange 2616 * @param e {DOMEvent} The change event 2617 */ 2618 onChange : function (e) { 2619 this.paginator.setPage( 2620 parseInt(this.select.options[this.select.selectedIndex].value,false)); 2621 }, 2622 2623 2624 2625 /** 2626 * Removes the select node and clears event listeners 2627 * @method destroy 2628 * @private 2629 */ 2630 destroy : function () { 2631 YAHOO.util.Event.purgeElement(this.select); 2632 this.select.parentNode.removeChild(this.select); 2633 this.select = null; 2634 } 2635 }; 2636 2637 })(); 2638 YAHOO.register("paginator", YAHOO.widget.Paginator, {version: "2.9.0", build: "2800"}); 2639 2640 }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event", "yui2-element", "yui2-skin-sam-paginator"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |