Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Paging.html
diff --git a/docs/source/Paging.html b/docs/source/Paging.html
new file mode 100644 (file)
index 0000000..3c2c691
--- /dev/null
@@ -0,0 +1,577 @@
+<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-toolbar.Paging-method-constructor'><span id='Ext-toolbar.Paging'>/**
+</span></span> * @class Ext.toolbar.Paging
+ * @extends Ext.toolbar.Toolbar
+ * &lt;p&gt;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.&lt;/p&gt;
+ * &lt;p&gt;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.&lt;/p&gt;
+ * &lt;p&gt;&lt;b&gt;Ext.toolbar.Paging&lt;/b&gt; 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 &lt;tt&gt;{@link #store}&lt;/tt&gt; by passing {@link Ext.data.Store#paramNames paramNames} used for
+ * paging criteria.&lt;/p&gt;
+ *
+ * {@img Ext.toolbar.Paging/Ext.toolbar.Paging.png Ext.toolbar.Paging component}
+ *
+ * &lt;p&gt;PagingToolbar is typically used as one of the Grid's toolbars:&lt;/p&gt;
+ * &lt;pre&gt;&lt;code&gt;
+ *    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()
+ *    });
+ * &lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;To use paging, pass the paging requirements to the server when the store is first loaded.&lt;/p&gt;
+ * &lt;pre&gt;&lt;code&gt;
+store.load({
+    params: {
+        // specify params for the first page load if using paging
+        start: 0,          
+        limit: myPageSize,
+        // other params
+        foo:   'bar'
+    }
+});
+ * &lt;/code&gt;&lt;/pre&gt;
+ * 
+ * &lt;p&gt;If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:&lt;/p&gt;
+ * &lt;pre&gt;&lt;code&gt;
+var myStore = new Ext.data.Store({
+    {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25},
+    ...
+});
+ * &lt;/code&gt;&lt;/pre&gt;
+ * 
+ * &lt;p&gt;The packet sent back from the server would have this form:&lt;/p&gt;
+ * &lt;pre&gt;&lt;code&gt;
+{
+    &quot;success&quot;: true,
+    &quot;results&quot;: 2000, 
+    &quot;rows&quot;: [ // &lt;b&gt;*Note:&lt;/b&gt; this must be an Array 
+        { &quot;id&quot;:  1, &quot;name&quot;: &quot;Bill&quot;, &quot;occupation&quot;: &quot;Gardener&quot; },
+        { &quot;id&quot;:  2, &quot;name&quot;:  &quot;Ben&quot;, &quot;occupation&quot;: &quot;Horticulturalist&quot; },
+        ...
+        { &quot;id&quot;: 25, &quot;name&quot;:  &quot;Sue&quot;, &quot;occupation&quot;: &quot;Botanist&quot; }
+    ]
+}
+ * &lt;/code&gt;&lt;/pre&gt;
+ * &lt;p&gt;&lt;u&gt;Paging with Local Data&lt;/u&gt;&lt;/p&gt;
+ * &lt;p&gt;Paging can also be accomplished with local data using extensions:&lt;/p&gt;
+ * &lt;div class=&quot;mdetail-params&quot;&gt;&lt;ul&gt;
+ * &lt;li&gt;&lt;a href=&quot;http://sencha.com/forum/showthread.php?t=71532&quot;&gt;Ext.ux.data.PagingStore&lt;/a&gt;&lt;/li&gt;
+ * &lt;li&gt;Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)&lt;/li&gt;
+ * &lt;/ul&gt;&lt;/div&gt;
+ * @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'],
+<span id='Ext-toolbar.Paging-cfg-store'>    /**
+</span>     * @cfg {Ext.data.Store} store
+     * The {@link Ext.data.Store} the paging toolbar should use as its data source (required).
+     */
+<span id='Ext-toolbar.Paging-cfg-displayInfo'>    /**
+</span>     * @cfg {Boolean} displayInfo
+     * &lt;tt&gt;true&lt;/tt&gt; to display the displayMsg (defaults to &lt;tt&gt;false&lt;/tt&gt;)
+     */
+    displayInfo: false,
+<span id='Ext-toolbar.Paging-cfg-prependButtons'>    /**
+</span>     * @cfg {Boolean} prependButtons
+     * &lt;tt&gt;true&lt;/tt&gt; to insert any configured &lt;tt&gt;items&lt;/tt&gt; &lt;i&gt;before&lt;/i&gt; the paging buttons.
+     * Defaults to &lt;tt&gt;false&lt;/tt&gt;.
+     */
+    prependButtons: false,
+<span id='Ext-toolbar.Paging-cfg-displayMsg'>    /**
+</span>     * @cfg {String} displayMsg
+     * The paging status message to display (defaults to &lt;tt&gt;'Displaying {0} - {1} of {2}'&lt;/tt&gt;).
+     * Note that this string is formatted using the braced numbers &lt;tt&gt;{0}-{2}&lt;/tt&gt; 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}',
+<span id='Ext-toolbar.Paging-cfg-emptyMsg'>    /**
+</span>     * @cfg {String} emptyMsg
+     * The message to display when no records are found (defaults to 'No data to display')
+     */
+    emptyMsg : 'No data to display',
+<span id='Ext-toolbar.Paging-cfg-beforePageText'>    /**
+</span>     * @cfg {String} beforePageText
+     * The text displayed before the input item (defaults to &lt;tt&gt;'Page'&lt;/tt&gt;).
+     */
+    beforePageText : 'Page',
+<span id='Ext-toolbar.Paging-cfg-afterPageText'>    /**
+</span>     * @cfg {String} afterPageText
+     * Customizable piece of the default paging text (defaults to &lt;tt&gt;'of {0}'&lt;/tt&gt;). Note that
+     * this string is formatted using &lt;tt&gt;{0}&lt;/tt&gt; 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}',
+<span id='Ext-toolbar.Paging-cfg-firstText'>    /**
+</span>     * @cfg {String} firstText
+     * The quicktip text displayed for the first page button (defaults to &lt;tt&gt;'First Page'&lt;/tt&gt;).
+     * &lt;b&gt;Note&lt;/b&gt;: quick tips must be initialized for the quicktip to show.
+     */
+    firstText : 'First Page',
+<span id='Ext-toolbar.Paging-cfg-prevText'>    /**
+</span>     * @cfg {String} prevText
+     * The quicktip text displayed for the previous page button (defaults to &lt;tt&gt;'Previous Page'&lt;/tt&gt;).
+     * &lt;b&gt;Note&lt;/b&gt;: quick tips must be initialized for the quicktip to show.
+     */
+    prevText : 'Previous Page',
+<span id='Ext-toolbar.Paging-cfg-nextText'>    /**
+</span>     * @cfg {String} nextText
+     * The quicktip text displayed for the next page button (defaults to &lt;tt&gt;'Next Page'&lt;/tt&gt;).
+     * &lt;b&gt;Note&lt;/b&gt;: quick tips must be initialized for the quicktip to show.
+     */
+    nextText : 'Next Page',
+<span id='Ext-toolbar.Paging-cfg-lastText'>    /**
+</span>     * @cfg {String} lastText
+     * The quicktip text displayed for the last page button (defaults to &lt;tt&gt;'Last Page'&lt;/tt&gt;).
+     * &lt;b&gt;Note&lt;/b&gt;: quick tips must be initialized for the quicktip to show.
+     */
+    lastText : 'Last Page',
+<span id='Ext-toolbar.Paging-cfg-refreshText'>    /**
+</span>     * @cfg {String} refreshText
+     * The quicktip text displayed for the Refresh button (defaults to &lt;tt&gt;'Refresh'&lt;/tt&gt;).
+     * &lt;b&gt;Note&lt;/b&gt;: quick tips must be initialized for the quicktip to show.
+     */
+    refreshText : 'Refresh',
+<span id='Ext-toolbar.Paging-cfg-inputItemWidth'>    /**
+</span>     * @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,
+    
+<span id='Ext-toolbar.Paging-method-getPagingItems'>    /**
+</span>     * 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('-&gt;');
+            me.items.push({xtype: 'tbtext', itemId: 'displayItem'});
+        }
+        
+        me.callParent();
+        
+        me.addEvents(
+<span id='Ext-toolbar.Paging-event-change'>            /**
+</span>             * @event change
+             * Fires after the active page has been changed.
+             * @param {Ext.toolbar.Paging} this
+             * @param {Object} pageData An object that has these properties:&lt;ul&gt;
+             * &lt;li&gt;&lt;code&gt;total&lt;/code&gt; : Number &lt;div class=&quot;sub-desc&quot;&gt;The total number of records in the dataset as
+             * returned by the server&lt;/div&gt;&lt;/li&gt;
+             * &lt;li&gt;&lt;code&gt;currentPage&lt;/code&gt; : Number &lt;div class=&quot;sub-desc&quot;&gt;The current page number&lt;/div&gt;&lt;/li&gt;
+             * &lt;li&gt;&lt;code&gt;pageCount&lt;/code&gt; : Number &lt;div class=&quot;sub-desc&quot;&gt;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})&lt;/div&gt;&lt;/li&gt;
+             * &lt;li&gt;&lt;code&gt;toRecord&lt;/code&gt; : Number &lt;div class=&quot;sub-desc&quot;&gt;The starting record index for the current page&lt;/div&gt;&lt;/li&gt;
+             * &lt;li&gt;&lt;code&gt;fromRecord&lt;/code&gt; : Number &lt;div class=&quot;sub-desc&quot;&gt;The ending record index for the current page&lt;/div&gt;&lt;/li&gt;
+             * &lt;/ul&gt;
+             */
+            'change',
+<span id='Ext-toolbar.Paging-event-beforechange'>            /**
+</span>             * @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 &gt;= 1 &amp;&amp; pageNum &lt;= pageData.pages) {
+                    field.setValue(pageNum);
+                }
+            }
+        }
+    },
+
+    // private
+    beforeLoad : function(){
+        if(this.rendered &amp;&amp; this.refresh){
+            this.refresh.disable();
+        }
+    },
+
+    // private
+    doLoad : function(start){
+        if(this.fireEvent('beforechange', this, o) !== false){
+            this.store.load();
+        }
+    },
+
+<span id='Ext-toolbar.Paging-method-moveFirst'>    /**
+</span>     * 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);
+        }
+    },
+
+<span id='Ext-toolbar.Paging-method-movePrevious'>    /**
+</span>     * 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();
+        }
+    },
+
+<span id='Ext-toolbar.Paging-method-moveNext'>    /**
+</span>     * 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();
+        }
+    },
+
+<span id='Ext-toolbar.Paging-method-moveLast'>    /**
+</span>     * 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);
+        }
+    },
+
+<span id='Ext-toolbar.Paging-method-doRefresh'>    /**
+</span>     * 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);
+        }
+    },
+
+<span id='Ext-toolbar.Paging-method-bindStore'>    /**
+</span>     * 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 &amp;&amp; me.store) {
+            if(store !== me.store &amp;&amp; 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;
+    },
+
+<span id='Ext-toolbar.Paging-method-unbind'>    /**
+</span>     * Unbinds the paging toolbar from the specified {@link Ext.data.Store} &lt;b&gt;(deprecated)&lt;/b&gt;
+     * @param {Ext.data.Store} store The data store to unbind
+     */
+    unbind : function(store){
+        this.bindStore(null);
+    },
+
+<span id='Ext-toolbar.Paging-method-bind'>    /**
+</span>     * Binds the paging toolbar to the specified {@link Ext.data.Store} &lt;b&gt;(deprecated)&lt;/b&gt;
+     * @param {Ext.data.Store} store The data store to bind
+     */
+    bind : function(store){
+        this.bindStore(store);
+    },
+
+    // private
+    onDestroy : function(){
+        this.bindStore(null);
+        this.callParent();
+    }
+});
+</pre></pre></body></html>
\ No newline at end of file