All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wings.js.yui.paginator.paginator-debug.js Maven / Gradle / Ivy

The newest version!
/*
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 2.9.0
*/
(function () {
/**
 * The Paginator widget provides a set of controls to navigate through paged
 * data.
 *
 * @module paginator
 * @uses YAHOO.util.EventProvider
 * @uses YAHOO.util.AttributeProvider
 */

var Dom        = YAHOO.util.Dom,
    lang       = YAHOO.lang,
    isObject   = lang.isObject,
    isFunction = lang.isFunction,
    isArray    = lang.isArray,
    isString   = lang.isString;

/**
 * Instantiate a Paginator, passing a configuration object to the contructor.
 * The configuration object should contain the following properties:
 * 
    *
  • rowsPerPage : n (int)
  • *
  • totalRecords : n (int or Paginator.VALUE_UNLIMITED)
  • *
  • containers : id | el | arr (HTMLElement reference, its id, or an array of either)
  • *
* * @namespace YAHOO.widget * @class Paginator * @constructor * @param config {Object} Object literal to set instance and ui component * configuration. */ function Paginator(config) { var UNLIMITED = Paginator.VALUE_UNLIMITED, attrib, initialPage, records, perPage, startIndex; config = isObject(config) ? config : {}; this.initConfig(); this.initEvents(); // Set the basic config keys first this.set('rowsPerPage',config.rowsPerPage,true); if (Paginator.isNumeric(config.totalRecords)) { this.set('totalRecords',config.totalRecords,true); } this.initUIComponents(); // Update the other config values for (attrib in config) { if (config.hasOwnProperty(attrib)) { this.set(attrib,config[attrib],true); } } // Calculate the initial record offset initialPage = this.get('initialPage'); records = this.get('totalRecords'); perPage = this.get('rowsPerPage'); if (initialPage > 1 && perPage !== UNLIMITED) { startIndex = (initialPage - 1) * perPage; if (records === UNLIMITED || startIndex < records) { this.set('recordOffset',startIndex,true); } } } // Static members lang.augmentObject(Paginator, { /** * Incrementing index used to give instances unique ids. * @static * @property Paginator.id * @type number * @private */ id : 0, /** * Base of id strings used for ui components. * @static * @property Paginator.ID_BASE * @type string * @private */ ID_BASE : 'yui-pg', /** * Used to identify unset, optional configurations, or used explicitly in * the case of totalRecords to indicate unlimited pagination. * @static * @property Paginator.VALUE_UNLIMITED * @type number * @final */ VALUE_UNLIMITED : -1, /** * Default template used by Paginator instances. Update this if you want * all new Paginators to use a different default template. * @static * @property Paginator.TEMPLATE_DEFAULT * @type string */ TEMPLATE_DEFAULT : "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}", /** * Common alternate pagination format, including page links, links for * previous, next, first and last pages as well as a rows-per-page * dropdown. Offered as a convenience. * @static * @property Paginator.TEMPLATE_ROWS_PER_PAGE * @type string */ TEMPLATE_ROWS_PER_PAGE : "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}", /** * Storage object for UI Components * @static * @property Paginator.ui */ ui : {}, /** * Similar to YAHOO.lang.isNumber, but allows numeric strings. This is * is used for attribute validation in conjunction with getters that return * numbers. * * @method Paginator.isNumeric * @param v {Number|String} value to be checked for number or numeric string * @returns {Boolean} true if the input is coercable into a finite number * @static */ isNumeric : function (v) { return isFinite(+v); }, /** * Return a number or null from input * * @method Paginator.toNumber * @param n {Number|String} a number or numeric string * @return Number * @static */ toNumber : function (n) { return isFinite(+n) ? +n : null; } },true); // Instance members and methods Paginator.prototype = { // Instance members /** * Array of nodes in which to render pagination controls. This is set via * the "containers" attribute. * @property _containers * @type Array(HTMLElement) * @private */ _containers : [], /** * Flag used to indicate multiple attributes are being updated via setState * @property _batch * @type boolean * @protected */ _batch : false, /** * Used by setState to indicate when a page change has occurred * @property _pageChanged * @type boolean * @protected */ _pageChanged : false, /** * Temporary state cache used by setState to keep track of the previous * state for eventual pageChange event firing * @property _state * @type Object * @protected */ _state : null, // Instance methods /** * Initialize the Paginator's attributes (see YAHOO.util.Element class * AttributeProvider). * @method initConfig * @private */ initConfig : function () { var UNLIMITED = Paginator.VALUE_UNLIMITED; /** * REQUIRED. Number of records constituting a "page" * @attribute rowsPerPage * @type integer */ this.setAttributeConfig('rowsPerPage', { value : 0, validator : Paginator.isNumeric, setter : Paginator.toNumber }); /** * REQUIRED. Node references or ids of nodes in which to render the * pagination controls. * @attribute containers * @type {string|HTMLElement|Array(string|HTMLElement)} */ this.setAttributeConfig('containers', { value : null, validator : function (val) { if (!isArray(val)) { val = [val]; } for (var i = 0, len = val.length; i < len; ++i) { if (isString(val[i]) || (isObject(val[i]) && val[i].nodeType === 1)) { continue; } return false; } return true; }, method : function (val) { val = Dom.get(val); if (!isArray(val)) { val = [val]; } this._containers = val; } }); /** * Total number of records to paginate through * @attribute totalRecords * @type integer * @default 0 */ this.setAttributeConfig('totalRecords', { value : 0, validator : Paginator.isNumeric, setter : Paginator.toNumber }); /** * Zero based index of the record considered first on the current page. * For page based interactions, don't modify this attribute directly; * use setPage(n). * @attribute recordOffset * @type integer * @default 0 */ this.setAttributeConfig('recordOffset', { value : 0, validator : function (val) { var total = this.get('totalRecords'); if (Paginator.isNumeric(val)) { val = +val; return total === UNLIMITED || total > val || (total === 0 && val === 0); } return false; }, setter : Paginator.toNumber }); /** * Page to display on initial paint * @attribute initialPage * @type integer * @default 1 */ this.setAttributeConfig('initialPage', { value : 1, validator : Paginator.isNumeric, setter : Paginator.toNumber }); /** * Template used to render controls. The string will be used as * innerHTML on all specified container nodes. Bracketed keys * (e.g. {pageLinks}) in the string will be replaced with an instance * of the so named ui component. * @see Paginator.TEMPLATE_DEFAULT * @see Paginator.TEMPLATE_ROWS_PER_PAGE * @attribute template * @type string */ this.setAttributeConfig('template', { value : Paginator.TEMPLATE_DEFAULT, validator : isString }); /** * Class assigned to the element(s) containing pagination controls. * @attribute containerClass * @type string * @default 'yui-pg-container' */ this.setAttributeConfig('containerClass', { value : 'yui-pg-container', validator : isString }); /** * Display pagination controls even when there is only one page. Set * to false to forgo rendering and/or hide the containers when there * is only one page of data. Note if you are using the rowsPerPage * dropdown ui component, visibility will be maintained as long as the * number of records exceeds the smallest page size. * @attribute alwaysVisible * @type boolean * @default true */ this.setAttributeConfig('alwaysVisible', { value : true, validator : lang.isBoolean }); /** * Update the UI immediately upon interaction. If false, changeRequest * subscribers or other external code will need to explicitly set the * new values in the paginator to trigger repaint. * @attribute updateOnChange * @type boolean * @default false * @deprecated use changeRequest listener that calls setState */ this.setAttributeConfig('updateOnChange', { value : false, validator : lang.isBoolean }); // Read only attributes /** * Unique id assigned to this instance * @attribute id * @type integer * @final */ this.setAttributeConfig('id', { value : Paginator.id++, readOnly : true }); /** * Indicator of whether the DOM nodes have been initially created * @attribute rendered * @type boolean * @final */ this.setAttributeConfig('rendered', { value : false, readOnly : true }); }, /** * Initialize registered ui components onto this instance. * @method initUIComponents * @private */ initUIComponents : function () { var ui = Paginator.ui, name,UIComp; for (name in ui) { if (ui.hasOwnProperty(name)) { UIComp = ui[name]; if (isObject(UIComp) && isFunction(UIComp.init)) { UIComp.init(this); } } } }, /** * Initialize this instance's CustomEvents. * @method initEvents * @private */ initEvents : function () { /** * Event fired when the Paginator is initially rendered * @event render */ this.createEvent('render'); /** * Event fired when the Paginator is initially rendered * @event rendered * @deprecated use render event */ this.createEvent('rendered'); // backward compatibility /** * Event fired when a change in pagination values is requested, * either by interacting with the various ui components or via the * setStartIndex(n) etc APIs. * Subscribers will receive the proposed state as the first parameter. * The proposed state object will contain the following keys: *
    *
  • paginator - the Paginator instance
  • *
  • page
  • *
  • totalRecords
  • *
  • recordOffset - index of the first record on the new page
  • *
  • rowsPerPage
  • *
  • records - array containing [start index, end index] for the records on the new page
  • *
  • before - object literal with all these keys for the current state
  • *
* @event changeRequest */ this.createEvent('changeRequest'); /** * Event fired when attribute changes have resulted in the calculated * current page changing. * @event pageChange */ this.createEvent('pageChange'); /** * Event that fires before the destroy event. * @event beforeDestroy */ this.createEvent('beforeDestroy'); /** * Event used to trigger cleanup of ui components * @event destroy */ this.createEvent('destroy'); this._selfSubscribe(); }, /** * Subscribes to instance attribute change events to automate certain * behaviors. * @method _selfSubscribe * @protected */ _selfSubscribe : function () { // Listen for changes to totalRecords and alwaysVisible this.subscribe('totalRecordsChange',this.updateVisibility,this,true); this.subscribe('alwaysVisibleChange',this.updateVisibility,this,true); // Fire the pageChange event when appropriate this.subscribe('totalRecordsChange',this._handleStateChange,this,true); this.subscribe('recordOffsetChange',this._handleStateChange,this,true); this.subscribe('rowsPerPageChange',this._handleStateChange,this,true); // Update recordOffset when totalRecords is reduced below this.subscribe('totalRecordsChange',this._syncRecordOffset,this,true); }, /** * Sets recordOffset to the starting index of the previous page when * totalRecords is reduced below the current recordOffset. * @method _syncRecordOffset * @param e {Event} totalRecordsChange event * @protected */ _syncRecordOffset : function (e) { var v = e.newValue,rpp,state; if (e.prevValue !== v) { if (v !== Paginator.VALUE_UNLIMITED) { rpp = this.get('rowsPerPage'); if (rpp && this.get('recordOffset') >= v) { state = this.getState({ totalRecords : e.prevValue, recordOffset : this.get('recordOffset') }); this.set('recordOffset', state.before.recordOffset); this._firePageChange(state); } } } }, /** * Fires the pageChange event when the state attributes have changed in * such a way as to locate the current recordOffset on a new page. * @method _handleStateChange * @param e {Event} the attribute change event * @protected */ _handleStateChange : function (e) { if (e.prevValue !== e.newValue) { var change = this._state || {}, state; change[e.type.replace(/Change$/,'')] = e.prevValue; state = this.getState(change); if (state.page !== state.before.page) { if (this._batch) { this._pageChanged = true; } else { this._firePageChange(state); } } } }, /** * Fires a pageChange event in the form of a standard attribute change * event with additional properties prevState and newState. * @method _firePageChange * @param state {Object} the result of getState(oldState) * @protected */ _firePageChange : function (state) { if (isObject(state)) { var current = state.before; delete state.before; this.fireEvent('pageChange',{ type : 'pageChange', prevValue : state.page, newValue : current.page, prevState : state, newState : current }); } }, /** * Render the pagination controls per the format attribute into the * specified container nodes. * @method render * @return the Paginator instance * @chainable */ render : function () { if (this.get('rendered')) { return this; } var template = this.get('template'), state = this.getState(), // ex. yui-pg0-1 (first paginator, second container) id_base = Paginator.ID_BASE + this.get('id') + '-', i, len; // Assemble the containers, keeping them hidden for (i = 0, len = this._containers.length; i < len; ++i) { this._renderTemplate(this._containers[i],template,id_base+i,true); } // Show the containers if appropriate this.updateVisibility(); // Set render attribute manually to support its readOnly contract if (this._containers.length) { this.setAttributeConfig('rendered', { value: true }); this.fireEvent('render', state); // For backward compatibility this.fireEvent('rendered', state); } return this; }, /** * Creates the individual ui components and renders them into a container. * * @method _renderTemplate * @param container {HTMLElement} where to add the ui components * @param template {String} the template to use as a guide for rendering * @param id_base {String} id base for the container's ui components * @param hide {Boolean} leave the container hidden after assembly * @protected */ _renderTemplate : function (container, template, id_base, hide) { var containerClass = this.get('containerClass'), markers, i, len; if (!container) { return; } // Hide the container while its contents are rendered Dom.setStyle(container,'display','none'); Dom.addClass(container, containerClass); // Place the template innerHTML, adding marker spans to the template // html to indicate drop zones for ui components container.innerHTML = template.replace(/\{([a-z0-9_ \-]+)\}/gi, ''); // Replace each marker with the ui component's render() output markers = Dom.getElementsByClassName('yui-pg-ui','span',container); for (i = 0, len = markers.length; i < len; ++i) { this.renderUIComponent(markers[i], id_base); } if (!hide) { // Show the container allowing page reflow Dom.setStyle(container,'display',''); } }, /** * Replaces a marker node with a rendered UI component, determined by the * yui-pg-ui-(UI component class name) in the marker's className. e.g. * yui-pg-ui-PageLinks => new YAHOO.widget.Paginator.ui.PageLinks(this) * * @method renderUIComponent * @param marker {HTMLElement} the marker node to replace * @param id_base {String} string base the component's generated id * @return the Paginator instance * @chainable */ renderUIComponent : function (marker, id_base) { var par = marker.parentNode, name = /yui-pg-ui-(\w+)/.exec(marker.className), UIComp = name && Paginator.ui[name[1]], comp; if (isFunction(UIComp)) { comp = new UIComp(this); if (isFunction(comp.render)) { par.replaceChild(comp.render(id_base),marker); } } return this; }, /** * Removes controls from the page and unhooks events. * @method destroy */ destroy : function () { this.fireEvent('beforeDestroy'); this.fireEvent('destroy'); this.setAttributeConfig('rendered',{value:false}); this.unsubscribeAll(); }, /** * Hides the containers if there is only one page of data and attribute * alwaysVisible is false. Conversely, it displays the containers if either * there is more than one page worth of data or alwaysVisible is turned on. * @method updateVisibility */ updateVisibility : function (e) { var alwaysVisible = this.get('alwaysVisible'), totalRecords, visible, rpp, rppOptions, i, len, opt; if (!e || e.type === 'alwaysVisibleChange' || !alwaysVisible) { totalRecords = this.get('totalRecords'); visible = true; rpp = this.get('rowsPerPage'); rppOptions = this.get('rowsPerPageOptions'); if (isArray(rppOptions)) { for (i = 0, len = rppOptions.length; i < len; ++i) { opt = rppOptions[i]; // account for value 'all' if (lang.isNumber(opt || opt.value)) { rpp = Math.min(rpp, (opt.value || opt)); } } } if (totalRecords !== Paginator.VALUE_UNLIMITED && totalRecords <= rpp) { visible = false; } visible = visible || alwaysVisible; for (i = 0, len = this._containers.length; i < len; ++i) { Dom.setStyle(this._containers[i],'display', visible ? '' : 'none'); } } }, /** * Get the configured container nodes * @method getContainerNodes * @return {Array} array of HTMLElement nodes */ getContainerNodes : function () { return this._containers; }, /** * Get the total number of pages in the data set according to the current * rowsPerPage and totalRecords values. If totalRecords is not set, or * set to YAHOO.widget.Paginator.VALUE_UNLIMITED, returns * YAHOO.widget.Paginator.VALUE_UNLIMITED. * @method getTotalPages * @return {number} */ getTotalPages : function () { var records = this.get('totalRecords'), perPage = this.get('rowsPerPage'); // rowsPerPage not set. Can't calculate if (!perPage) { return null; } if (records === Paginator.VALUE_UNLIMITED) { return Paginator.VALUE_UNLIMITED; } return Math.ceil(records/perPage); }, /** * Does the requested page have any records? * @method hasPage * @param page {number} the page in question * @return {boolean} */ hasPage : function (page) { if (!lang.isNumber(page) || page < 1) { return false; } var totalPages = this.getTotalPages(); return (totalPages === Paginator.VALUE_UNLIMITED || totalPages >= page); }, /** * Get the page number corresponding to the current record offset. * @method getCurrentPage * @return {number} */ getCurrentPage : function () { var perPage = this.get('rowsPerPage'); if (!perPage || !this.get('totalRecords')) { return 0; } return Math.floor(this.get('recordOffset') / perPage) + 1; }, /** * Are there records on the next page? * @method hasNextPage * @return {boolean} */ hasNextPage : function () { var currentPage = this.getCurrentPage(), totalPages = this.getTotalPages(); return currentPage && (totalPages === Paginator.VALUE_UNLIMITED || currentPage < totalPages); }, /** * Get the page number of the next page, or null if the current page is the * last page. * @method getNextPage * @return {number} */ getNextPage : function () { return this.hasNextPage() ? this.getCurrentPage() + 1 : null; }, /** * Is there a page before the current page? * @method hasPreviousPage * @return {boolean} */ hasPreviousPage : function () { return (this.getCurrentPage() > 1); }, /** * Get the page number of the previous page, or null if the current page * is the first page. * @method getPreviousPage * @return {number} */ getPreviousPage : function () { return (this.hasPreviousPage() ? this.getCurrentPage() - 1 : 1); }, /** * Get the start and end record indexes of the specified page. * @method getPageRecords * @param page {number} (optional) The page (current page if not specified) * @return {Array} [start_index, end_index] */ getPageRecords : function (page) { if (!lang.isNumber(page)) { page = this.getCurrentPage(); } var perPage = this.get('rowsPerPage'), records = this.get('totalRecords'), start, end; if (!page || !perPage) { return null; } start = (page - 1) * perPage; if (records !== Paginator.VALUE_UNLIMITED) { if (start >= records) { return null; } end = Math.min(start + perPage, records) - 1; } else { end = start + perPage - 1; } return [start,end]; }, /** * Set the current page to the provided page number if possible. * @method setPage * @param newPage {number} the new page number * @param silent {boolean} whether to forcibly avoid firing the * changeRequest event */ setPage : function (page,silent) { if (this.hasPage(page) && page !== this.getCurrentPage()) { if (this.get('updateOnChange') || silent) { this.set('recordOffset', (page - 1) * this.get('rowsPerPage')); } else { this.fireEvent('changeRequest',this.getState({'page':page})); } } }, /** * Get the number of rows per page. * @method getRowsPerPage * @return {number} the current setting of the rowsPerPage attribute */ getRowsPerPage : function () { return this.get('rowsPerPage'); }, /** * Set the number of rows per page. * @method setRowsPerPage * @param rpp {number} the new number of rows per page * @param silent {boolean} whether to forcibly avoid firing the * changeRequest event */ setRowsPerPage : function (rpp,silent) { if (Paginator.isNumeric(rpp) && +rpp > 0 && +rpp !== this.get('rowsPerPage')) { if (this.get('updateOnChange') || silent) { this.set('rowsPerPage',rpp); } else { this.fireEvent('changeRequest', this.getState({'rowsPerPage':+rpp})); } } }, /** * Get the total number of records. * @method getTotalRecords * @return {number} the current setting of totalRecords attribute */ getTotalRecords : function () { return this.get('totalRecords'); }, /** * Set the total number of records. * @method setTotalRecords * @param total {number} the new total number of records * @param silent {boolean} whether to forcibly avoid firing the changeRequest event */ setTotalRecords : function (total,silent) { if (Paginator.isNumeric(total) && +total >= 0 && +total !== this.get('totalRecords')) { if (this.get('updateOnChange') || silent) { this.set('totalRecords',total); } else { this.fireEvent('changeRequest', this.getState({'totalRecords':+total})); } } }, /** * Get the index of the first record on the current page * @method getStartIndex * @return {number} the index of the first record on the current page */ getStartIndex : function () { return this.get('recordOffset'); }, /** * Move the record offset to a new starting index. This will likely cause * the calculated current page to change. You should probably use setPage. * @method setStartIndex * @param offset {number} the new record offset * @param silent {boolean} whether to forcibly avoid firing the changeRequest event */ setStartIndex : function (offset,silent) { if (Paginator.isNumeric(offset) && +offset >= 0 && +offset !== this.get('recordOffset')) { if (this.get('updateOnChange') || silent) { this.set('recordOffset',offset); } else { this.fireEvent('changeRequest', this.getState({'recordOffset':+offset})); } } }, /** * Get an object literal describing the current state of the paginator. If * an object literal of proposed values is passed, the proposed state will * be returned as an object literal with the following keys: *
    *
  • paginator - instance of the Paginator
  • *
  • page - number
  • *
  • totalRecords - number
  • *
  • recordOffset - number
  • *
  • rowsPerPage - number
  • *
  • records - [ start_index, end_index ]
  • *
  • before - (OPTIONAL) { state object literal for current state }
  • *
* @method getState * @return {object} * @param changes {object} OPTIONAL object literal with proposed values * Supported change keys include: *
    *
  • rowsPerPage
  • *
  • totalRecords
  • *
  • recordOffset OR
  • *
  • page
  • *
*/ getState : function (changes) { var UNLIMITED = Paginator.VALUE_UNLIMITED, M = Math, max = M.max, ceil = M.ceil, currentState, state, offset; function normalizeOffset(offset,total,rpp) { if (offset <= 0 || total === 0) { return 0; } if (total === UNLIMITED || total > offset) { return offset - (offset % rpp); } return total - (total % rpp || rpp); } currentState = { paginator : this, totalRecords : this.get('totalRecords'), rowsPerPage : this.get('rowsPerPage'), records : this.getPageRecords() }; currentState.recordOffset = normalizeOffset( this.get('recordOffset'), currentState.totalRecords, currentState.rowsPerPage); currentState.page = ceil(currentState.recordOffset / currentState.rowsPerPage) + 1; if (!changes) { return currentState; } state = { paginator : this, before : currentState, rowsPerPage : changes.rowsPerPage || currentState.rowsPerPage, totalRecords : (Paginator.isNumeric(changes.totalRecords) ? max(changes.totalRecords,UNLIMITED) : +currentState.totalRecords) }; if (state.totalRecords === 0) { state.recordOffset = state.page = 0; } else { offset = Paginator.isNumeric(changes.page) ? (changes.page - 1) * state.rowsPerPage : Paginator.isNumeric(changes.recordOffset) ? +changes.recordOffset : currentState.recordOffset; state.recordOffset = normalizeOffset(offset, state.totalRecords, state.rowsPerPage); state.page = ceil(state.recordOffset / state.rowsPerPage) + 1; } state.records = [ state.recordOffset, state.recordOffset + state.rowsPerPage - 1 ]; // limit upper index to totalRecords - 1 if (state.totalRecords !== UNLIMITED && state.recordOffset < state.totalRecords && state.records && state.records[1] > state.totalRecords - 1) { state.records[1] = state.totalRecords - 1; } return state; }, /** * Convenience method to facilitate setting state attributes rowsPerPage, * totalRecords, recordOffset in batch. Also supports calculating * recordOffset from state.page if state.recordOffset is not provided. * Fires only a single pageChange event, if appropriate. * This will not fire a changeRequest event. * @method setState * @param state {Object} Object literal of attribute:value pairs to set */ setState : function (state) { if (isObject(state)) { // get flux state based on current state with before state as well this._state = this.getState({}); // use just the state props from the input obj state = { page : state.page, rowsPerPage : state.rowsPerPage, totalRecords : state.totalRecords, recordOffset : state.recordOffset }; // calculate recordOffset from page if recordOffset not specified. // not using lang.isNumber for support of numeric strings if (state.page && state.recordOffset === undefined) { state.recordOffset = (state.page - 1) * (state.rowsPerPage || this.get('rowsPerPage')); } this._batch = true; this._pageChanged = false; for (var k in state) { if (state.hasOwnProperty(k) && this._configs.hasOwnProperty(k)) { this.set(k,state[k]); } } this._batch = false; if (this._pageChanged) { this._pageChanged = false; this._firePageChange(this.getState(this._state)); } } } }; lang.augmentProto(Paginator, YAHOO.util.AttributeProvider); YAHOO.widget.Paginator = Paginator; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the textual report of current pagination status. * E.g. "Now viewing page 1 of 13". * * @namespace YAHOO.widget.Paginator.ui * @class CurrentPageReport * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.CurrentPageReport = function (p) { this.paginator = p; p.subscribe('recordOffsetChange', this.update,this,true); p.subscribe('rowsPerPageChange', this.update,this,true); p.subscribe('totalRecordsChange',this.update,this,true); p.subscribe('pageReportTemplateChange', this.update,this,true); p.subscribe('destroy',this.destroy,this,true); //TODO: make this work p.subscribe('pageReportClassChange', this.update,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.CurrentPageReport.init = function (p) { /** * CSS class assigned to the span containing the info. * @attribute pageReportClass * @default 'yui-pg-current' */ p.setAttributeConfig('pageReportClass', { value : 'yui-pg-current', validator : l.isString }); /** * Used as innerHTML for the span. Place holders in the form of {name} * will be replaced with the so named value from the key:value map * generated by the function held in the pageReportValueGenerator attribute. * @attribute pageReportTemplate * @default '({currentPage} of {totalPages})' * @see pageReportValueGenerator attribute */ p.setAttributeConfig('pageReportTemplate', { value : '({currentPage} of {totalPages})', validator : l.isString }); /** * Function to generate the value map used to populate the * pageReportTemplate. The function is passed the Paginator instance as a * parameter. The default function returns a map with the following keys: *
    *
  • currentPage
  • *
  • totalPages
  • *
  • startIndex
  • *
  • endIndex
  • *
  • startRecord
  • *
  • endRecord
  • *
  • totalRecords
  • *
* @attribute pageReportValueGenarator */ p.setAttributeConfig('pageReportValueGenerator', { value : function (paginator) { var curPage = paginator.getCurrentPage(), records = paginator.getPageRecords(); return { 'currentPage' : records ? curPage : 0, 'totalPages' : paginator.getTotalPages(), 'startIndex' : records ? records[0] : 0, 'endIndex' : records ? records[1] : 0, 'startRecord' : records ? records[0] + 1 : 0, 'endRecord' : records ? records[1] + 1 : 0, 'totalRecords': paginator.get('totalRecords') }; }, validator : l.isFunction }); }; /** * Replace place holders in a string with the named values found in an * object literal. * @static * @method sprintf * @param template {string} The content string containing place holders * @param values {object} The key:value pairs used to replace the place holders * @return {string} */ Paginator.ui.CurrentPageReport.sprintf = function (template, values) { return template.replace(/\{([\w\s\-]+)\}/g, function (x,key) { return (key in values) ? values[key] : ''; }); }; Paginator.ui.CurrentPageReport.prototype = { /** * Span node containing the formatted info * @property span * @type HTMLElement * @private */ span : null, /** * Generate the span containing info formatted per the pageReportTemplate * attribute. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { this.span = document.createElement('span'); this.span.className = this.paginator.get('pageReportClass'); setId(this.span, id_base + '-page-report'); this.update(); return this.span; }, /** * Regenerate the content of the span if appropriate. Calls * CurrentPageReport.sprintf with the value of the pageReportTemplate * attribute and the value map returned from pageReportValueGenerator * function. * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } this.span.innerHTML = Paginator.ui.CurrentPageReport.sprintf( this.paginator.get('pageReportTemplate'), this.paginator.get('pageReportValueGenerator')(this.paginator)); }, /** * Removes the link/span node and clears event listeners * removal. * @method destroy * @private */ destroy : function () { this.span.parentNode.removeChild(this.span); this.span = null; } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the page links * * @namespace YAHOO.widget.Paginator.ui * @class PageLinks * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.PageLinks = function (p) { this.paginator = p; p.subscribe('recordOffsetChange',this.update,this,true); p.subscribe('rowsPerPageChange',this.update,this,true); p.subscribe('totalRecordsChange',this.update,this,true); p.subscribe('pageLinksChange', this.rebuild,this,true); p.subscribe('pageLinkClassChange', this.rebuild,this,true); p.subscribe('currentPageClassChange', this.rebuild,this,true); p.subscribe('destroy',this.destroy,this,true); //TODO: Make this work p.subscribe('pageLinksContainerClassChange', this.rebuild,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.PageLinks.init = function (p) { /** * CSS class assigned to each page link/span. * @attribute pageLinkClass * @default 'yui-pg-page' */ p.setAttributeConfig('pageLinkClass', { value : 'yui-pg-page', validator : l.isString }); /** * CSS class assigned to the current page span. * @attribute currentPageClass * @default 'yui-pg-current-page' */ p.setAttributeConfig('currentPageClass', { value : 'yui-pg-current-page', validator : l.isString }); /** * CSS class assigned to the span containing the page links. * @attribute pageLinksContainerClass * @default 'yui-pg-pages' */ p.setAttributeConfig('pageLinksContainerClass', { value : 'yui-pg-pages', validator : l.isString }); /** * Maximum number of page links to display at one time. * @attribute pageLinks * @default 10 */ p.setAttributeConfig('pageLinks', { value : 10, validator : Paginator.isNumeric }); /** * Function used generate the innerHTML for each page link/span. The * function receives as parameters the page number and a reference to the * paginator object. * @attribute pageLabelBuilder * @default function (page, paginator) { return page; } */ p.setAttributeConfig('pageLabelBuilder', { value : function (page, paginator) { return page; }, validator : l.isFunction }); /** * Function used generate the title for each page link. The * function receives as parameters the page number and a reference to the * paginator object. * @attribute pageTitleBuilder * @default function (page, paginator) { return page; } */ p.setAttributeConfig('pageTitleBuilder', { value : function (page, paginator) { return "Page " + page; }, validator : l.isFunction }); }; /** * Calculates start and end page numbers given a current page, attempting * to keep the current page in the middle * @static * @method calculateRange * @param {int} currentPage The current page * @param {int} totalPages (optional) Maximum number of pages * @param {int} numPages (optional) Preferred number of pages in range * @return {Array} [start_page_number, end_page_number] */ Paginator.ui.PageLinks.calculateRange = function (currentPage,totalPages,numPages) { var UNLIMITED = Paginator.VALUE_UNLIMITED, start, end, delta; // Either has no pages, or unlimited pages. Show none. if (!currentPage || numPages === 0 || totalPages === 0 || (totalPages === UNLIMITED && numPages === UNLIMITED)) { return [0,-1]; } // Limit requested pageLinks if there are fewer totalPages if (totalPages !== UNLIMITED) { numPages = numPages === UNLIMITED ? totalPages : Math.min(numPages,totalPages); } // Determine start and end, trying to keep current in the middle start = Math.max(1,Math.ceil(currentPage - (numPages/2))); if (totalPages === UNLIMITED) { end = start + numPages - 1; } else { end = Math.min(totalPages, start + numPages - 1); } // Adjust the start index when approaching the last page delta = numPages - (end - start + 1); start = Math.max(1, start - delta); return [start,end]; }; Paginator.ui.PageLinks.prototype = { /** * Current page * @property current * @type number * @private */ current : 0, /** * Span node containing the page links * @property container * @type HTMLElement * @private */ container : null, /** * Generate the nodes and return the container node containing page links * appropriate to the current pagination state. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { var p = this.paginator; // Set up container this.container = document.createElement('span'); setId(this.container, id_base + '-pages'); this.container.className = p.get('pageLinksContainerClass'); YAHOO.util.Event.on(this.container,'click',this.onClick,this,true); // Call update, flagging a need to rebuild this.update({newValue : null, rebuild : true}); return this.container; }, /** * Update the links if appropriate * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var p = this.paginator, currentPage = p.getCurrentPage(); // Replace content if there's been a change if (this.current !== currentPage || !currentPage || e.rebuild) { var labelBuilder = p.get('pageLabelBuilder'), titleBuilder = p.get('pageTitleBuilder'), range = Paginator.ui.PageLinks.calculateRange( currentPage, p.getTotalPages(), p.get('pageLinks')), start = range[0], end = range[1], content = '', linkTemplate,i,spanTemplate; linkTemplate = '{label}'; spanTemplate = '{label}'; for (i = start; i <= end; ++i) { if (i === currentPage) { content += l.substitute(spanTemplate, { 'class' : p.get('currentPageClass') + ' ' + p.get('pageLinkClass'), 'label' : labelBuilder(i,p) }); } else { content += l.substitute(linkTemplate, { 'class' : p.get('pageLinkClass'), 'page' : i, 'label' : labelBuilder(i,p), 'title' : titleBuilder(i,p) }); } } this.container.innerHTML = content; } }, /** * Force a rebuild of the page links. * @method rebuild * @param e {CustomEvent} The calling change event */ rebuild : function (e) { e.rebuild = true; this.update(e); }, /** * Removes the page links container node and clears event listeners * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.container,true); this.container.parentNode.removeChild(this.container); this.container = null; }, /** * Listener for the container's onclick event. Looks for qualifying link * clicks, and pulls the page number from the link's page attribute. * Sends link's page attribute to the Paginator's setPage method. * @method onClick * @param e {DOMEvent} The click event */ onClick : function (e) { var t = YAHOO.util.Event.getTarget(e); if (t && YAHOO.util.Dom.hasClass(t, this.paginator.get('pageLinkClass'))) { YAHOO.util.Event.stopEvent(e); this.paginator.setPage(parseInt(t.getAttribute('page'),10)); } } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the link to jump to the first page. * * @namespace YAHOO.widget.Paginator.ui * @class FirstPageLink * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.FirstPageLink = function (p) { this.paginator = p; p.subscribe('recordOffsetChange',this.update,this,true); p.subscribe('rowsPerPageChange',this.update,this,true); p.subscribe('totalRecordsChange',this.update,this,true); p.subscribe('destroy',this.destroy,this,true); // TODO: make this work p.subscribe('firstPageLinkLabelChange',this.update,this,true); p.subscribe('firstPageLinkClassChange',this.update,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.FirstPageLink.init = function (p) { /** * Used as innerHTML for the first page link/span. * @attribute firstPageLinkLabel * @default '<< first' */ p.setAttributeConfig('firstPageLinkLabel', { value : '<< first', validator : l.isString }); /** * CSS class assigned to the link/span * @attribute firstPageLinkClass * @default 'yui-pg-first' */ p.setAttributeConfig('firstPageLinkClass', { value : 'yui-pg-first', validator : l.isString }); /** * Used as title for the first page link. * @attribute firstPageLinkTitle * @default 'First Page' */ p.setAttributeConfig('firstPageLinkTitle', { value : 'First Page', validator : l.isString }); }; // Instance members and methods Paginator.ui.FirstPageLink.prototype = { /** * The currently placed HTMLElement node * @property current * @type HTMLElement * @private */ current : null, /** * Link node * @property link * @type HTMLElement * @private */ link : null, /** * Span node (inactive link) * @property span * @type HTMLElement * @private */ span : null, /** * Generate the nodes and return the appropriate node given the current * pagination state. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { var p = this.paginator, c = p.get('firstPageLinkClass'), label = p.get('firstPageLinkLabel'), title = p.get('firstPageLinkTitle'); this.link = document.createElement('a'); this.span = document.createElement('span'); setId(this.link, id_base + '-first-link'); this.link.href = '#'; this.link.className = c; this.link.innerHTML = label; this.link.title = title; YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); setId(this.span, id_base + '-first-span'); this.span.className = c; this.span.innerHTML = label; this.current = p.getCurrentPage() > 1 ? this.link : this.span; return this.current; }, /** * Swap the link and span nodes if appropriate. * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var par = this.current ? this.current.parentNode : null; if (this.paginator.getCurrentPage() > 1) { if (par && this.current === this.span) { par.replaceChild(this.link,this.current); this.current = this.link; } } else { if (par && this.current === this.link) { par.replaceChild(this.span,this.current); this.current = this.span; } } }, /** * Removes the link/span node and clears event listeners * removal. * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.link); this.current.parentNode.removeChild(this.current); this.link = this.span = null; }, /** * Listener for the link's onclick event. Pass new value to setPage method. * @method onClick * @param e {DOMEvent} The click event */ onClick : function (e) { YAHOO.util.Event.stopEvent(e); this.paginator.setPage(1); } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the link to jump to the last page. * * @namespace YAHOO.widget.Paginator.ui * @class LastPageLink * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.LastPageLink = function (p) { this.paginator = p; p.subscribe('recordOffsetChange',this.update,this,true); p.subscribe('rowsPerPageChange',this.update,this,true); p.subscribe('totalRecordsChange',this.update,this,true); p.subscribe('destroy',this.destroy,this,true); // TODO: make this work p.subscribe('lastPageLinkLabelChange',this.update,this,true); p.subscribe('lastPageLinkClassChange', this.update,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param paginator {Paginator} Paginator instance to decorate * @static */ Paginator.ui.LastPageLink.init = function (p) { /** * Used as innerHTML for the last page link/span. * @attribute lastPageLinkLabel * @default 'last >>' */ p.setAttributeConfig('lastPageLinkLabel', { value : 'last >>', validator : l.isString }); /** * CSS class assigned to the link/span * @attribute lastPageLinkClass * @default 'yui-pg-last' */ p.setAttributeConfig('lastPageLinkClass', { value : 'yui-pg-last', validator : l.isString }); /** * Used as title for the last page link. * @attribute lastPageLinkTitle * @default 'Last Page' */ p.setAttributeConfig('lastPageLinkTitle', { value : 'Last Page', validator : l.isString }); }; Paginator.ui.LastPageLink.prototype = { /** * Currently placed HTMLElement node * @property current * @type HTMLElement * @private */ current : null, /** * Link HTMLElement node * @property link * @type HTMLElement * @private */ link : null, /** * Span node (inactive link) * @property span * @type HTMLElement * @private */ span : null, /** * Empty place holder node for when the last page link is inappropriate to * display in any form (unlimited paging). * @property na * @type HTMLElement * @private */ na : null, /** * Generate the nodes and return the appropriate node given the current * pagination state. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { var p = this.paginator, c = p.get('lastPageLinkClass'), label = p.get('lastPageLinkLabel'), last = p.getTotalPages(), title = p.get('lastPageLinkTitle'); this.link = document.createElement('a'); this.span = document.createElement('span'); this.na = this.span.cloneNode(false); setId(this.link, id_base + '-last-link'); this.link.href = '#'; this.link.className = c; this.link.innerHTML = label; this.link.title = title; YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); setId(this.span, id_base + '-last-span'); this.span.className = c; this.span.innerHTML = label; setId(this.na, id_base + '-last-na'); switch (last) { case Paginator.VALUE_UNLIMITED : this.current = this.na; break; case p.getCurrentPage() : this.current = this.span; break; default : this.current = this.link; } return this.current; }, /** * Swap the link, span, and na nodes if appropriate. * @method update * @param e {CustomEvent} The calling change event (ignored) */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var par = this.current ? this.current.parentNode : null, after = this.link; if (par) { switch (this.paginator.getTotalPages()) { case Paginator.VALUE_UNLIMITED : after = this.na; break; case this.paginator.getCurrentPage() : after = this.span; break; } if (this.current !== after) { par.replaceChild(after,this.current); this.current = after; } } }, /** * Removes the link/span node and clears event listeners * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.link); this.current.parentNode.removeChild(this.current); this.link = this.span = null; }, /** * Listener for the link's onclick event. Passes to setPage method. * @method onClick * @param e {DOMEvent} The click event */ onClick : function (e) { YAHOO.util.Event.stopEvent(e); this.paginator.setPage(this.paginator.getTotalPages()); } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the link to jump to the next page. * * @namespace YAHOO.widget.Paginator.ui * @class NextPageLink * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.NextPageLink = function (p) { this.paginator = p; p.subscribe('recordOffsetChange', this.update,this,true); p.subscribe('rowsPerPageChange', this.update,this,true); p.subscribe('totalRecordsChange', this.update,this,true); p.subscribe('destroy',this.destroy,this,true); // TODO: make this work p.subscribe('nextPageLinkLabelChange', this.update,this,true); p.subscribe('nextPageLinkClassChange', this.update,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.NextPageLink.init = function (p) { /** * Used as innerHTML for the next page link/span. * @attribute nextPageLinkLabel * @default 'next >' */ p.setAttributeConfig('nextPageLinkLabel', { value : 'next >', validator : l.isString }); /** * CSS class assigned to the link/span * @attribute nextPageLinkClass * @default 'yui-pg-next' */ p.setAttributeConfig('nextPageLinkClass', { value : 'yui-pg-next', validator : l.isString }); /** * Used as title for the next page link. * @attribute nextPageLinkTitle * @default 'Next Page' */ p.setAttributeConfig('nextPageLinkTitle', { value : 'Next Page', validator : l.isString }); }; Paginator.ui.NextPageLink.prototype = { /** * Currently placed HTMLElement node * @property current * @type HTMLElement * @private */ current : null, /** * Link node * @property link * @type HTMLElement * @private */ link : null, /** * Span node (inactive link) * @property span * @type HTMLElement * @private */ span : null, /** * Generate the nodes and return the appropriate node given the current * pagination state. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { var p = this.paginator, c = p.get('nextPageLinkClass'), label = p.get('nextPageLinkLabel'), last = p.getTotalPages(), title = p.get('nextPageLinkTitle'); this.link = document.createElement('a'); this.span = document.createElement('span'); setId(this.link, id_base + '-next-link'); this.link.href = '#'; this.link.className = c; this.link.innerHTML = label; this.link.title = title; YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); setId(this.span, id_base + '-next-span'); this.span.className = c; this.span.innerHTML = label; this.current = p.getCurrentPage() === last ? this.span : this.link; return this.current; }, /** * Swap the link and span nodes if appropriate. * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var last = this.paginator.getTotalPages(), par = this.current ? this.current.parentNode : null; if (this.paginator.getCurrentPage() !== last) { if (par && this.current === this.span) { par.replaceChild(this.link,this.current); this.current = this.link; } } else if (this.current === this.link) { if (par) { par.replaceChild(this.span,this.current); this.current = this.span; } } }, /** * Removes the link/span node and clears event listeners * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.link); this.current.parentNode.removeChild(this.current); this.link = this.span = null; }, /** * Listener for the link's onclick event. Passes to setPage method. * @method onClick * @param e {DOMEvent} The click event */ onClick : function (e) { YAHOO.util.Event.stopEvent(e); this.paginator.setPage(this.paginator.getNextPage()); } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the link to jump to the previous page. * * @namespace YAHOO.widget.Paginator.ui * @class PreviousPageLink * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.PreviousPageLink = function (p) { this.paginator = p; p.subscribe('recordOffsetChange',this.update,this,true); p.subscribe('rowsPerPageChange',this.update,this,true); p.subscribe('totalRecordsChange',this.update,this,true); p.subscribe('destroy',this.destroy,this,true); // TODO: make this work p.subscribe('previousPageLinkLabelChange',this.update,this,true); p.subscribe('previousPageLinkClassChange',this.update,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.PreviousPageLink.init = function (p) { /** * Used as innerHTML for the previous page link/span. * @attribute previousPageLinkLabel * @default '< prev' */ p.setAttributeConfig('previousPageLinkLabel', { value : '< prev', validator : l.isString }); /** * CSS class assigned to the link/span * @attribute previousPageLinkClass * @default 'yui-pg-previous' */ p.setAttributeConfig('previousPageLinkClass', { value : 'yui-pg-previous', validator : l.isString }); /** * Used as title for the previous page link. * @attribute previousPageLinkTitle * @default 'Previous Page' */ p.setAttributeConfig('previousPageLinkTitle', { value : 'Previous Page', validator : l.isString }); }; Paginator.ui.PreviousPageLink.prototype = { /** * Currently placed HTMLElement node * @property current * @type HTMLElement * @private */ current : null, /** * Link node * @property link * @type HTMLElement * @private */ link : null, /** * Span node (inactive link) * @property span * @type HTMLElement * @private */ span : null, /** * Generate the nodes and return the appropriate node given the current * pagination state. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { var p = this.paginator, c = p.get('previousPageLinkClass'), label = p.get('previousPageLinkLabel'), title = p.get('previousPageLinkTitle'); this.link = document.createElement('a'); this.span = document.createElement('span'); setId(this.link, id_base + '-prev-link'); this.link.href = '#'; this.link.className = c; this.link.innerHTML = label; this.link.title = title; YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); setId(this.span, id_base + '-prev-span'); this.span.className = c; this.span.innerHTML = label; this.current = p.getCurrentPage() > 1 ? this.link : this.span; return this.current; }, /** * Swap the link and span nodes if appropriate. * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var par = this.current ? this.current.parentNode : null; if (this.paginator.getCurrentPage() > 1) { if (par && this.current === this.span) { par.replaceChild(this.link,this.current); this.current = this.link; } } else { if (par && this.current === this.link) { par.replaceChild(this.span,this.current); this.current = this.span; } } }, /** * Removes the link/span node and clears event listeners * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.link); this.current.parentNode.removeChild(this.current); this.link = this.span = null; }, /** * Listener for the link's onclick event. Passes to setPage method. * @method onClick * @param e {DOMEvent} The click event */ onClick : function (e) { YAHOO.util.Event.stopEvent(e); this.paginator.setPage(this.paginator.getPreviousPage()); } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the rows-per-page dropdown * * @namespace YAHOO.widget.Paginator.ui * @class RowsPerPageDropdown * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.RowsPerPageDropdown = function (p) { this.paginator = p; p.subscribe('rowsPerPageChange',this.update,this,true); p.subscribe('rowsPerPageOptionsChange',this.rebuild,this,true); p.subscribe('totalRecordsChange',this._handleTotalRecordsChange,this,true); p.subscribe('destroy',this.destroy,this,true); // TODO: make this work p.subscribe('rowsPerPageDropdownClassChange',this.rebuild,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.RowsPerPageDropdown.init = function (p) { /** * Array of available rows-per-page sizes. Converted into select options. * Array values may be positive integers or object literals in the form
* { value : NUMBER, text : STRING } * @attribute rowsPerPageOptions * @default [] */ p.setAttributeConfig('rowsPerPageOptions', { value : [], validator : l.isArray }); /** * CSS class assigned to the select node * @attribute rowsPerPageDropdownClass * @default 'yui-pg-rpp-options' */ p.setAttributeConfig('rowsPerPageDropdownClass', { value : 'yui-pg-rpp-options', validator : l.isString }); }; Paginator.ui.RowsPerPageDropdown.prototype = { /** * select node * @property select * @type HTMLElement * @private */ select : null, /** * option node for the optional All value * * @property all * @type HTMLElement * @protected */ all : null, /** * Generate the select and option nodes and returns the select node. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { this.select = document.createElement('select'); setId(this.select, id_base + '-rpp'); this.select.className = this.paginator.get('rowsPerPageDropdownClass'); this.select.title = 'Rows per page'; YAHOO.util.Event.on(this.select,'change',this.onChange,this,true); this.rebuild(); return this.select; }, /** * (Re)generate the select options. * @method rebuild */ rebuild : function (e) { var p = this.paginator, sel = this.select, options = p.get('rowsPerPageOptions'), opt,cfg,val,i,len; this.all = null; for (i = 0, len = options.length; i < len; ++i) { cfg = options[i]; opt = sel.options[i] || sel.appendChild(document.createElement('option')); val = l.isValue(cfg.value) ? cfg.value : cfg; opt.text = l.isValue(cfg.text) ? cfg.text : cfg; if (l.isString(val) && val.toLowerCase() === 'all') { this.all = opt; opt.value = p.get('totalRecords'); } else{ opt.value = val; } } while (sel.options.length > options.length) { sel.removeChild(sel.firstChild); } this.update(); }, /** * Select the appropriate option if changed. * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var rpp = this.paginator.get('rowsPerPage')+'', options = this.select.options, i,len; for (i = 0, len = options.length; i < len; ++i) { if (options[i].value === rpp) { options[i].selected = true; break; } } }, /** * Listener for the select's onchange event. Sent to setRowsPerPage method. * @method onChange * @param e {DOMEvent} The change event */ onChange : function (e) { this.paginator.setRowsPerPage( parseInt(this.select.options[this.select.selectedIndex].value,10)); }, /** * Updates the all option value (and Paginator's rowsPerPage attribute if * necessary) in response to a change in the Paginator's totalRecords. * * @method _handleTotalRecordsChange * @param e {Event} attribute change event * @protected */ _handleTotalRecordsChange : function (e) { if (!this.all || (e && e.prevValue === e.newValue)) { return; } this.all.value = e.newValue; if (this.all.selected) { this.paginator.set('rowsPerPage',e.newValue); } }, /** * Removes the select node and clears event listeners * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.select); this.select.parentNode.removeChild(this.select); this.select = null; } }; })(); (function () { var Paginator = YAHOO.widget.Paginator, l = YAHOO.lang, setId = YAHOO.util.Dom.generateId; /** * ui Component to generate the jump-to-page dropdown * * @namespace YAHOO.widget.Paginator.ui * @class JumpToPageDropdown * @for YAHOO.widget.Paginator * * @constructor * @param p {Pagintor} Paginator instance to attach to */ Paginator.ui.JumpToPageDropdown = function (p) { this.paginator = p; p.subscribe('rowsPerPageChange',this.rebuild,this,true); p.subscribe('rowsPerPageOptionsChange',this.rebuild,this,true); p.subscribe('pageChange',this.update,this,true); p.subscribe('totalRecordsChange',this.rebuild,this,true); p.subscribe('destroy',this.destroy,this,true); }; /** * Decorates Paginator instances with new attributes. Called during * Paginator instantiation. * @method init * @param p {Paginator} Paginator instance to decorate * @static */ Paginator.ui.JumpToPageDropdown.init = function (p) { /** * CSS class assigned to the select node * @attribute jumpToPageDropdownClass * @default 'yui-pg-jtp-options' */ p.setAttributeConfig('jumpToPageDropdownClass', { value : 'yui-pg-jtp-options', validator : l.isString }); }; Paginator.ui.JumpToPageDropdown.prototype = { /** * select node * @property select * @type HTMLElement * @private */ select : null, /** * Generate the select and option nodes and returns the select node. * @method render * @param id_base {string} used to create unique ids for generated nodes * @return {HTMLElement} */ render : function (id_base) { this.select = document.createElement('select'); setId(this.select, id_base + '-jtp'); this.select.className = this.paginator.get('jumpToPageDropdownClass'); this.select.title = 'Jump to page'; YAHOO.util.Event.on(this.select,'change',this.onChange,this,true); this.rebuild(); return this.select; }, /** * (Re)generate the select options. * @method rebuild */ rebuild : function (e) { var p = this.paginator, sel = this.select, numPages = p.getTotalPages(), opt,i,len; this.all = null; for (i = 0, len = numPages; i < len; ++i ) { opt = sel.options[i] || sel.appendChild(document.createElement('option')); opt.innerHTML = i + 1; opt.value = i + 1; } for ( i = numPages, len = sel.options.length ; i < len ; i++ ) { sel.removeChild(sel.lastChild); } this.update(); }, /** * Select the appropriate option if changed. * @method update * @param e {CustomEvent} The calling change event */ update : function (e) { if (e && e.prevValue === e.newValue) { return; } var cp = this.paginator.getCurrentPage()+'', options = this.select.options, i,len; for (i = 0, len = options.length; i < len; ++i) { if (options[i].value === cp) { options[i].selected = true; break; } } }, /** * Listener for the select's onchange event. Sent to setPage method. * @method onChange * @param e {DOMEvent} The change event */ onChange : function (e) { this.paginator.setPage( parseInt(this.select.options[this.select.selectedIndex].value,false)); }, /** * Removes the select node and clears event listeners * @method destroy * @private */ destroy : function () { YAHOO.util.Event.purgeElement(this.select); this.select.parentNode.removeChild(this.select); this.select = null; } }; })(); YAHOO.register("paginator", YAHOO.widget.Paginator, {version: "2.9.0", build: "2800"});




© 2015 - 2024 Weber Informatics LLC | Privacy Policy