X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/docs/source/Paging.html diff --git a/docs/source/Paging.html b/docs/source/Paging.html new file mode 100644 index 00000000..3c2c6915 --- /dev/null +++ b/docs/source/Paging.html @@ -0,0 +1,577 @@ +
\ No newline at end of file/** + * @class Ext.toolbar.Paging + * @extends Ext.toolbar.Toolbar + * <p>As the amount of records increases, the time required for the browser to render + * them increases. Paging is used to reduce the amount of data exchanged with the client. + * Note: if there are more records/rows than can be viewed in the available screen area, vertical + * scrollbars will be added.</p> + * <p>Paging is typically handled on the server side (see exception below). The client sends + * parameters to the server side, which the server needs to interpret and then respond with the + * appropriate data.</p> + * <p><b>Ext.toolbar.Paging</b> is a specialized toolbar that is bound to a {@link Ext.data.Store} + * and provides automatic paging control. This Component {@link Ext.data.Store#load load}s blocks + * of data into the <tt>{@link #store}</tt> by passing {@link Ext.data.Store#paramNames paramNames} used for + * paging criteria.</p> + * + * {@img Ext.toolbar.Paging/Ext.toolbar.Paging.png Ext.toolbar.Paging component} + * + * <p>PagingToolbar is typically used as one of the Grid's toolbars:</p> + * <pre><code> + * var itemsPerPage = 2; // set the number of items you want per page + * + * var store = Ext.create('Ext.data.Store', { + * id:'simpsonsStore', + * autoLoad: false, + * fields:['name', 'email', 'phone'], + * pageSize: itemsPerPage, // items per page + * proxy: { + * type: 'ajax', + * url: 'pagingstore.js', // url that will load data with respect to start and limit params + * reader: { + * type: 'json', + * root: 'items', + * totalProperty: 'total' + * } + * } + * }); + * + * // specify segment of data you want to load using params + * store.load({ + * params:{ + * start:0, + * limit: itemsPerPage + * } + * }); + * + * Ext.create('Ext.grid.Panel', { + * title: 'Simpsons', + * store: store, + * columns: [ + * {header: 'Name', dataIndex: 'name'}, + * {header: 'Email', dataIndex: 'email', flex:1}, + * {header: 'Phone', dataIndex: 'phone'} + * ], + * width: 400, + * height: 125, + * dockedItems: [{ + * xtype: 'pagingtoolbar', + * store: store, // same store GridPanel is using + * dock: 'bottom', + * displayInfo: true + * }], + * renderTo: Ext.getBody() + * }); + * </code></pre> + * + * <p>To use paging, pass the paging requirements to the server when the store is first loaded.</p> + * <pre><code> +store.load({ + params: { + // specify params for the first page load if using paging + start: 0, + limit: myPageSize, + // other params + foo: 'bar' + } +}); + * </code></pre> + * + * <p>If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:</p> + * <pre><code> +var myStore = new Ext.data.Store({ + {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25}, + ... +}); + * </code></pre> + * + * <p>The packet sent back from the server would have this form:</p> + * <pre><code> +{ + "success": true, + "results": 2000, + "rows": [ // <b>*Note:</b> this must be an Array + { "id": 1, "name": "Bill", "occupation": "Gardener" }, + { "id": 2, "name": "Ben", "occupation": "Horticulturalist" }, + ... + { "id": 25, "name": "Sue", "occupation": "Botanist" } + ] +} + * </code></pre> + * <p><u>Paging with Local Data</u></p> + * <p>Paging can also be accomplished with local data using extensions:</p> + * <div class="mdetail-params"><ul> + * <li><a href="http://sencha.com/forum/showthread.php?t=71532">Ext.ux.data.PagingStore</a></li> + * <li>Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)</li> + * </ul></div> + * @constructor Create a new PagingToolbar + * @param {Object} config The config object + * @xtype pagingtoolbar + */ +Ext.define('Ext.toolbar.Paging', { + extend: 'Ext.toolbar.Toolbar', + alias: 'widget.pagingtoolbar', + alternateClassName: 'Ext.PagingToolbar', + requires: ['Ext.toolbar.TextItem', 'Ext.form.field.Number'], + /** + * @cfg {Ext.data.Store} store + * The {@link Ext.data.Store} the paging toolbar should use as its data source (required). + */ + /** + * @cfg {Boolean} displayInfo + * <tt>true</tt> to display the displayMsg (defaults to <tt>false</tt>) + */ + displayInfo: false, + /** + * @cfg {Boolean} prependButtons + * <tt>true</tt> to insert any configured <tt>items</tt> <i>before</i> the paging buttons. + * Defaults to <tt>false</tt>. + */ + prependButtons: false, + /** + * @cfg {String} displayMsg + * The paging status message to display (defaults to <tt>'Displaying {0} - {1} of {2}'</tt>). + * Note that this string is formatted using the braced numbers <tt>{0}-{2}</tt> as tokens + * that are replaced by the values for start, end and total respectively. These tokens should + * be preserved when overriding this string if showing those values is desired. + */ + displayMsg : 'Displaying {0} - {1} of {2}', + /** + * @cfg {String} emptyMsg + * The message to display when no records are found (defaults to 'No data to display') + */ + emptyMsg : 'No data to display', + /** + * @cfg {String} beforePageText + * The text displayed before the input item (defaults to <tt>'Page'</tt>). + */ + beforePageText : 'Page', + /** + * @cfg {String} afterPageText + * Customizable piece of the default paging text (defaults to <tt>'of {0}'</tt>). Note that + * this string is formatted using <tt>{0}</tt> as a token that is replaced by the number of + * total pages. This token should be preserved when overriding this string if showing the + * total page count is desired. + */ + afterPageText : 'of {0}', + /** + * @cfg {String} firstText + * The quicktip text displayed for the first page button (defaults to <tt>'First Page'</tt>). + * <b>Note</b>: quick tips must be initialized for the quicktip to show. + */ + firstText : 'First Page', + /** + * @cfg {String} prevText + * The quicktip text displayed for the previous page button (defaults to <tt>'Previous Page'</tt>). + * <b>Note</b>: quick tips must be initialized for the quicktip to show. + */ + prevText : 'Previous Page', + /** + * @cfg {String} nextText + * The quicktip text displayed for the next page button (defaults to <tt>'Next Page'</tt>). + * <b>Note</b>: quick tips must be initialized for the quicktip to show. + */ + nextText : 'Next Page', + /** + * @cfg {String} lastText + * The quicktip text displayed for the last page button (defaults to <tt>'Last Page'</tt>). + * <b>Note</b>: quick tips must be initialized for the quicktip to show. + */ + lastText : 'Last Page', + /** + * @cfg {String} refreshText + * The quicktip text displayed for the Refresh button (defaults to <tt>'Refresh'</tt>). + * <b>Note</b>: quick tips must be initialized for the quicktip to show. + */ + refreshText : 'Refresh', + /** + * @cfg {Number} inputItemWidth + * The width in pixels of the input field used to display and change the current page number (defaults to 30). + */ + inputItemWidth : 30, + + /** + * Gets the standard paging items in the toolbar + * @private + */ + getPagingItems: function() { + var me = this; + + return [{ + itemId: 'first', + tooltip: me.firstText, + overflowText: me.firstText, + iconCls: Ext.baseCSSPrefix + 'tbar-page-first', + disabled: true, + handler: me.moveFirst, + scope: me + },{ + itemId: 'prev', + tooltip: me.prevText, + overflowText: me.prevText, + iconCls: Ext.baseCSSPrefix + 'tbar-page-prev', + disabled: true, + handler: me.movePrevious, + scope: me + }, + '-', + me.beforePageText, + { + xtype: 'numberfield', + itemId: 'inputItem', + name: 'inputItem', + cls: Ext.baseCSSPrefix + 'tbar-page-number', + allowDecimals: false, + minValue: 1, + hideTrigger: true, + enableKeyEvents: true, + selectOnFocus: true, + submitValue: false, + width: me.inputItemWidth, + margins: '-1 2 3 2', + listeners: { + scope: me, + keydown: me.onPagingKeyDown, + blur: me.onPagingBlur + } + },{ + xtype: 'tbtext', + itemId: 'afterTextItem', + text: Ext.String.format(me.afterPageText, 1) + }, + '-', + { + itemId: 'next', + tooltip: me.nextText, + overflowText: me.nextText, + iconCls: Ext.baseCSSPrefix + 'tbar-page-next', + disabled: true, + handler: me.moveNext, + scope: me + },{ + itemId: 'last', + tooltip: me.lastText, + overflowText: me.lastText, + iconCls: Ext.baseCSSPrefix + 'tbar-page-last', + disabled: true, + handler: me.moveLast, + scope: me + }, + '-', + { + itemId: 'refresh', + tooltip: me.refreshText, + overflowText: me.refreshText, + iconCls: Ext.baseCSSPrefix + 'tbar-loading', + handler: me.doRefresh, + scope: me + }]; + }, + + initComponent : function(){ + var me = this, + pagingItems = me.getPagingItems(), + userItems = me.items || me.buttons || []; + + if (me.prependButtons) { + me.items = userItems.concat(pagingItems); + } else { + me.items = pagingItems.concat(userItems); + } + delete me.buttons; + + if (me.displayInfo) { + me.items.push('->'); + me.items.push({xtype: 'tbtext', itemId: 'displayItem'}); + } + + me.callParent(); + + me.addEvents( + /** + * @event change + * Fires after the active page has been changed. + * @param {Ext.toolbar.Paging} this + * @param {Object} pageData An object that has these properties:<ul> + * <li><code>total</code> : Number <div class="sub-desc">The total number of records in the dataset as + * returned by the server</div></li> + * <li><code>currentPage</code> : Number <div class="sub-desc">The current page number</div></li> + * <li><code>pageCount</code> : Number <div class="sub-desc">The total number of pages (calculated from + * the total number of records in the dataset as returned by the server and the current {@link #pageSize})</div></li> + * <li><code>toRecord</code> : Number <div class="sub-desc">The starting record index for the current page</div></li> + * <li><code>fromRecord</code> : Number <div class="sub-desc">The ending record index for the current page</div></li> + * </ul> + */ + 'change', + /** + * @event beforechange + * Fires just before the active page is changed. + * Return false to prevent the active page from being changed. + * @param {Ext.toolbar.Paging} this + * @param {Number} page The page number that will be loaded on change + */ + 'beforechange' + ); + me.on('afterlayout', me.onLoad, me, {single: true}); + + me.bindStore(me.store, true); + }, + // private + updateInfo : function(){ + var me = this, + displayItem = me.child('#displayItem'), + store = me.store, + pageData = me.getPageData(), + count, msg; + + if (displayItem) { + count = store.getCount(); + if (count === 0) { + msg = me.emptyMsg; + } else { + msg = Ext.String.format( + me.displayMsg, + pageData.fromRecord, + pageData.toRecord, + pageData.total + ); + } + displayItem.setText(msg); + me.doComponentLayout(); + } + }, + + // private + onLoad : function(){ + var me = this, + pageData, + currPage, + pageCount, + afterText; + + if (!me.rendered) { + return; + } + + pageData = me.getPageData(); + currPage = pageData.currentPage; + pageCount = pageData.pageCount; + afterText = Ext.String.format(me.afterPageText, isNaN(pageCount) ? 1 : pageCount); + + me.child('#afterTextItem').setText(afterText); + me.child('#inputItem').setValue(currPage); + me.child('#first').setDisabled(currPage === 1); + me.child('#prev').setDisabled(currPage === 1); + me.child('#next').setDisabled(currPage === pageCount); + me.child('#last').setDisabled(currPage === pageCount); + me.child('#refresh').enable(); + me.updateInfo(); + me.fireEvent('change', me, pageData); + }, + + // private + getPageData : function(){ + var store = this.store, + totalCount = store.getTotalCount(); + + return { + total : totalCount, + currentPage : store.currentPage, + pageCount: Math.ceil(totalCount / store.pageSize), + //pageCount : store.getPageCount(), + fromRecord: ((store.currentPage - 1) * store.pageSize) + 1, + toRecord: Math.min(store.currentPage * store.pageSize, totalCount) + + }; + }, + + // private + onLoadError : function(){ + if (!this.rendered) { + return; + } + this.child('#refresh').enable(); + }, + + // private + readPageFromInput : function(pageData){ + var v = this.child('#inputItem').getValue(), + pageNum = parseInt(v, 10); + + if (!v || isNaN(pageNum)) { + this.child('#inputItem').setValue(pageData.currentPage); + return false; + } + return pageNum; + }, + + onPagingFocus : function(){ + this.child('#inputItem').select(); + }, + + //private + onPagingBlur : function(e){ + var curPage = this.getPageData().currentPage; + this.child('#inputItem').setValue(curPage); + }, + + // private + onPagingKeyDown : function(field, e){ + var k = e.getKey(), + pageData = this.getPageData(), + increment = e.shiftKey ? 10 : 1, + pageNum, + me = this; + + if (k == e.RETURN) { + e.stopEvent(); + pageNum = me.readPageFromInput(pageData); + if (pageNum !== false) { + pageNum = Math.min(Math.max(1, pageNum), pageData.total); + if(me.fireEvent('beforechange', me, pageNum) !== false){ + me.store.loadPage(pageNum); + } + } + } else if (k == e.HOME || k == e.END) { + e.stopEvent(); + pageNum = k == e.HOME ? 1 : pageData.pageCount; + field.setValue(pageNum); + } else if (k == e.UP || k == e.PAGEUP || k == e.DOWN || k == e.PAGEDOWN) { + e.stopEvent(); + pageNum = me.readPageFromInput(pageData); + if (pageNum) { + if (k == e.DOWN || k == e.PAGEDOWN) { + increment *= -1; + } + pageNum += increment; + if (pageNum >= 1 && pageNum <= pageData.pages) { + field.setValue(pageNum); + } + } + } + }, + + // private + beforeLoad : function(){ + if(this.rendered && this.refresh){ + this.refresh.disable(); + } + }, + + // private + doLoad : function(start){ + if(this.fireEvent('beforechange', this, o) !== false){ + this.store.load(); + } + }, + + /** + * Move to the first page, has the same effect as clicking the 'first' button. + */ + moveFirst : function(){ + var me = this; + if(me.fireEvent('beforechange', me, 1) !== false){ + me.store.loadPage(1); + } + }, + + /** + * Move to the previous page, has the same effect as clicking the 'previous' button. + */ + movePrevious : function(){ + var me = this, + prev = me.store.currentPage - 1; + + if(me.fireEvent('beforechange', me, prev) !== false){ + me.store.previousPage(); + } + }, + + /** + * Move to the next page, has the same effect as clicking the 'next' button. + */ + moveNext : function(){ + var me = this; + if(me.fireEvent('beforechange', me, me.store.currentPage + 1) !== false){ + me.store.nextPage(); + } + }, + + /** + * Move to the last page, has the same effect as clicking the 'last' button. + */ + moveLast : function(){ + var me = this, + last = this.getPageData().pageCount; + + if(me.fireEvent('beforechange', me, last) !== false){ + me.store.loadPage(last); + } + }, + + /** + * Refresh the current page, has the same effect as clicking the 'refresh' button. + */ + doRefresh : function(){ + var me = this, + current = me.store.currentPage; + + if(me.fireEvent('beforechange', me, current) !== false){ + me.store.loadPage(current); + } + }, + + /** + * Binds the paging toolbar to the specified {@link Ext.data.Store} + * @param {Store} store The store to bind to this toolbar + * @param {Boolean} initial (Optional) true to not remove listeners + */ + bindStore : function(store, initial){ + var me = this; + + if (!initial && me.store) { + if(store !== me.store && me.store.autoDestroy){ + me.store.destroy(); + }else{ + me.store.un('beforeload', me.beforeLoad, me); + me.store.un('load', me.onLoad, me); + me.store.un('exception', me.onLoadError, me); + } + if(!store){ + me.store = null; + } + } + if (store) { + store = Ext.data.StoreManager.lookup(store); + store.on({ + scope: me, + beforeload: me.beforeLoad, + load: me.onLoad, + exception: me.onLoadError + }); + } + me.store = store; + }, + + /** + * Unbinds the paging toolbar from the specified {@link Ext.data.Store} <b>(deprecated)</b> + * @param {Ext.data.Store} store The data store to unbind + */ + unbind : function(store){ + this.bindStore(null); + }, + + /** + * Binds the paging toolbar to the specified {@link Ext.data.Store} <b>(deprecated)</b> + * @param {Ext.data.Store} store The data store to bind + */ + bind : function(store){ + this.bindStore(store); + }, + + // private + onDestroy : function(){ + this.bindStore(null); + this.callParent(); + } +}); +