paginator.js
2393 lines
| 69.4 KiB
| application/javascript
|
JavascriptLexer
r547 | /* | |||
r1073 | Copyright (c) 2010, Yahoo! Inc. All rights reserved. | |||
r547 | Code licensed under the BSD License: | |||
r1073 | http://developer.yahoo.com/yui/license.html | |||
version: 2.8.2r1 | ||||
r547 | */ | |||
(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: | ||||
* <ul> | ||||
* <li>rowsPerPage : <em>n</em> (int)</li> | ||||
* <li>totalRecords : <em>n</em> (int or Paginator.VALUE_UNLIMITED)</li> | ||||
* <li>containers : <em>id | el | arr</em> (HTMLElement reference, its id, or an array of either)</li> | ||||
* </ul> | ||||
* | ||||
* @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: | ||||
* <ul> | ||||
* <li>paginator - the Paginator instance</li> | ||||
* <li>page</li> | ||||
* <li>totalRecords</li> | ||||
* <li>recordOffset - index of the first record on the new page</li> | ||||
* <li>rowsPerPage</li> | ||||
* <li>records - array containing [start index, end index] for the records on the new page</li> | ||||
* <li>before - object literal with all these keys for the current state</li> | ||||
* </ul> | ||||
* @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, | ||||
'<span class="yui-pg-ui yui-pg-ui-$1"></span>'); | ||||
// 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 | ||||
*/ | ||||
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); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* 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; | ||||
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) { | ||||
rpp = Math.min(rpp,rppOptions[i]); | ||||
} | ||||
} | ||||
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: | ||||
* <ul> | ||||
* <li>paginator - instance of the Paginator</li> | ||||
* <li>page - number</li> | ||||
* <li>totalRecords - number</li> | ||||
* <li>recordOffset - number</li> | ||||
* <li>rowsPerPage - number</li> | ||||
* <li>records - [ start_index, end_index ]</li> | ||||
* <li>before - (OPTIONAL) { state object literal for current state }</li> | ||||
* </ul> | ||||
* @method getState | ||||
* @return {object} | ||||
* @param changes {object} OPTIONAL object literal with proposed values | ||||
* Supported change keys include: | ||||
* <ul> | ||||
* <li>rowsPerPage</li> | ||||
* <li>totalRecords</li> | ||||
* <li>recordOffset OR</li> | ||||
* <li>page</li> | ||||
* </ul> | ||||
*/ | ||||
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; | ||||
/** | ||||
* 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: | ||||
* <ul> | ||||
* <li>currentPage</li> | ||||
* <li>totalPages</li> | ||||
* <li>startIndex</li> | ||||
* <li>endIndex</li> | ||||
* <li>startRecord</li> | ||||
* <li>endRecord</li> | ||||
* <li>totalRecords</li> | ||||
* </ul> | ||||
* @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.id = id_base + '-page-report'; | ||||
this.span.className = this.paginator.get('pageReportClass'); | ||||
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; | ||||
/** | ||||
* 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 | ||||
}); | ||||
}; | ||||
/** | ||||
* 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'); | ||||
this.container.id = 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'), | ||||
range = Paginator.ui.PageLinks.calculateRange( | ||||
currentPage, | ||||
p.getTotalPages(), | ||||
p.get('pageLinks')), | ||||
start = range[0], | ||||
end = range[1], | ||||
content = '', | ||||
linkTemplate,i; | ||||
linkTemplate = '<a href="#" class="' + p.get('pageLinkClass') + | ||||
'" page="'; | ||||
for (i = start; i <= end; ++i) { | ||||
if (i === currentPage) { | ||||
content += | ||||
'<span class="' + p.get('currentPageClass') + ' ' + | ||||
p.get('pageLinkClass') + '">' + | ||||
labelBuilder(i,p) + '</span>'; | ||||
} else { | ||||
content += | ||||
linkTemplate + i + '">' + labelBuilder(i,p) + '</a>'; | ||||
} | ||||
} | ||||
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; | ||||
/** | ||||
* 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 | ||||
}); | ||||
}; | ||||
// 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'); | ||||
this.link = document.createElement('a'); | ||||
this.span = document.createElement('span'); | ||||
this.link.id = id_base + '-first-link'; | ||||
this.link.href = '#'; | ||||
this.link.className = c; | ||||
this.link.innerHTML = label; | ||||
YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); | ||||
this.span.id = 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; | ||||
/** | ||||
* 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 | ||||
}); | ||||
}; | ||||
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(); | ||||
this.link = document.createElement('a'); | ||||
this.span = document.createElement('span'); | ||||
this.na = this.span.cloneNode(false); | ||||
this.link.id = id_base + '-last-link'; | ||||
this.link.href = '#'; | ||||
this.link.className = c; | ||||
this.link.innerHTML = label; | ||||
YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); | ||||
this.span.id = id_base + '-last-span'; | ||||
this.span.className = c; | ||||
this.span.innerHTML = label; | ||||
this.na.id = 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; | ||||
/** | ||||
* 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 | ||||
}); | ||||
}; | ||||
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(); | ||||
this.link = document.createElement('a'); | ||||
this.span = document.createElement('span'); | ||||
this.link.id = id_base + '-next-link'; | ||||
this.link.href = '#'; | ||||
this.link.className = c; | ||||
this.link.innerHTML = label; | ||||
YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); | ||||
this.span.id = 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; | ||||
/** | ||||
* 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 | ||||
}); | ||||
}; | ||||
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'); | ||||
this.link = document.createElement('a'); | ||||
this.span = document.createElement('span'); | ||||
this.link.id = id_base + '-prev-link'; | ||||
this.link.href = '#'; | ||||
this.link.className = c; | ||||
this.link.innerHTML = label; | ||||
YAHOO.util.Event.on(this.link,'click',this.onClick,this,true); | ||||
this.span.id = 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; | ||||
/** | ||||
* 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<br> | ||||
* { 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'); | ||||
this.select.id = 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.innerHTML = 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; | ||||
} | ||||
}; | ||||
})(); | ||||
r1073 | YAHOO.register("paginator", YAHOO.widget.Paginator, {version: "2.8.2r1", build: "7"}); | |||