~cdparra/gelee/trunk

« back to all changes in this revision

Viewing changes to webui/ecosystem/extjs/source/widgets/PagingToolbar.js

  • Committer: parra
  • Date: 2010-03-15 02:39:02 UTC
  • Revision ID: svn-v4:ac5bba68-f036-4e09-846e-8f32731cc928:trunk/gelee:1433
merged gelee at svn

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Ext JS Library 3.0 RC2
 
3
 * Copyright(c) 2006-2009, Ext JS, LLC.
 
4
 * licensing@extjs.com
 
5
 * 
 
6
 * http://extjs.com/license
 
7
 */
 
8
 
 
9
/**
 
10
 * @class Ext.PagingToolbar
 
11
 * @extends Ext.Toolbar
 
12
 * <p>As the amount of records increases, the time required for the browser to render
 
13
 * them increases. Paging is used to reduce the amount of data exchanged with the client.
 
14
 * Note: if there are more records/rows than can be viewed in the available screen area, vertical
 
15
 * scrollbars will be added.</p>
 
16
 * <p>Paging is typically handled on the server side (see exception below). The client sends
 
17
 * parameters to the server side, which the server needs to interpret and then respond with the
 
18
 * approprate data.</p>
 
19
 * <p><b>Ext.PagingToolbar</b> is a specialized toolbar that is bound to a {@link Ext.data.Store}
 
20
 * and provides automatic paging control. This Component {@link Ext.data.Store#load load}s blocks
 
21
 * of data into the <tt>{@link #store}</tt> by passing {@link #paramNames parameters} used for
 
22
 * paging criteria.</p>
 
23
 * <p>PagingToolbar is typically used as one of the Grid's toolbars:</p>
 
24
 * <pre><code>
 
25
Ext.QuickTips.init(); // to display button quicktips
 
26
 
 
27
var myStore = new Ext.data.Store({
 
28
    ...
 
29
});
 
30
 
 
31
var myPageSize = 25;  // server script should only send back 25 items
 
32
 
 
33
var grid = new Ext.grid.GridPanel({
 
34
    ...
 
35
    store: myStore,
 
36
    bbar: new Ext.PagingToolbar({
 
37
        {@link #store}: myStore,       // grid and PagingToolbar using same store
 
38
        {@link #displayInfo}: true,
 
39
        {@link #pageSize}: myPageSize,
 
40
        {@link #prependButtons}: true,
 
41
        items: [
 
42
            'text 1'
 
43
        ]
 
44
    })
 
45
});
 
46
 * </code></pre>
 
47
 *
 
48
 * <p>To use paging, pass the paging requirements to the server when the store is first loaded.</p>
 
49
 * <pre><code>
 
50
store.load({
 
51
    params: {
 
52
        start: 0,          // specify params for the first page load if using paging
 
53
        limit: myPageSize,
 
54
        foo:   'bar'
 
55
});
 
56
 * </code></pre>
 
57
 * <p><u>Paging with Local Data</u></p>
 
58
 * <p>Paging can also be accomplished with local data using extensions:</p>
 
59
 * <div class="mdetail-params"><ul>
 
60
 * <li><a href="http://extjs.com/forum/showthread.php?t=57386">Ext.ux.data.PagingStore</a></li>
 
61
 * <li>Paging Memory Proxy (examples/locale/PagingMemoryProxy.js)</li>
 
62
 * </ul></div>
 
63
 * @constructor
 
64
 * Create a new PagingToolbar
 
65
 * @param {Object} config The config object
 
66
 * @xtype paging
 
67
 */
 
68
(function() {
 
69
 
 
70
var T = Ext.Toolbar;
 
71
 
 
72
Ext.PagingToolbar = Ext.extend(Ext.Toolbar, {
 
73
    /**
 
74
     * @cfg {Ext.data.Store} store
 
75
     * The {@link Ext.data.Store} the paging toolbar should use as its data source (required).
 
76
     */
 
77
    /**
 
78
     * @cfg {Boolean} displayInfo
 
79
     * <tt>true</tt> to display the displayMsg (defaults to <tt>false</tt>)
 
80
     */
 
81
    /**
 
82
     * @cfg {Number} pageSize
 
83
     * The number of records to display per page (defaults to <tt>20</tt>)
 
84
     */
 
85
    pageSize: 20,
 
86
    /**
 
87
     * @cfg {Boolean} prependButtons
 
88
     * <tt>true</tt> to insert any configured <tt>items</tt> <i>before</i> the paging buttons.
 
89
     * Defaults to <tt>false</tt>.
 
90
     */
 
91
    /**
 
92
     * @cfg {String} displayMsg
 
93
     * The paging status message to display (defaults to <tt>"Displaying {0} - {1} of {2}"</tt>).
 
94
     * Note that this string is formatted using the braced numbers <tt>{0}-{2}</tt> as tokens
 
95
     * that are replaced by the values for start, end and total respectively. These tokens should
 
96
     * be preserved when overriding this string if showing those values is desired.
 
97
     */
 
98
    displayMsg : 'Displaying {0} - {1} of {2}',
 
99
    /**
 
100
     * @cfg {String} emptyMsg
 
101
     * The message to display when no records are found (defaults to "No data to display")
 
102
     */
 
103
    emptyMsg : 'No data to display',
 
104
    /**
 
105
     * @cfg {String} beforePageText
 
106
     * The text displayed before the input item (defaults to <tt>"Page"</tt>).
 
107
     */
 
108
    beforePageText : "Page",
 
109
    /**
 
110
     * @cfg {String} afterPageText
 
111
     * Customizable piece of the default paging text (defaults to <tt>"of {0}"</tt>). Note that
 
112
     * this string is formatted using <tt>{0}</tt> as a token that is replaced by the number of
 
113
     * total pages. This token should be preserved when overriding this string if showing the
 
114
     * total page count is desired.
 
115
     */
 
116
    afterPageText : "of {0}",
 
117
    /**
 
118
     * @cfg {String} firstText
 
119
     * The quicktip text displayed for the first page button (defaults to <tt>"First Page"</tt>).
 
120
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 
121
     */
 
122
    firstText : "First Page",
 
123
    /**
 
124
     * @cfg {String} prevText
 
125
     * The quicktip text displayed for the previous page button (defaults to <tt>"Previous Page"</tt>).
 
126
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 
127
     */
 
128
    prevText : "Previous Page",
 
129
    /**
 
130
     * @cfg {String} nextText
 
131
     * The quicktip text displayed for the next page button (defaults to <tt>"Next Page"</tt>).
 
132
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 
133
     */
 
134
    nextText : "Next Page",
 
135
    /**
 
136
     * @cfg {String} lastText
 
137
     * The quicktip text displayed for the last page button (defaults to <tt>"Last Page"</tt>).
 
138
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 
139
     */
 
140
    lastText : "Last Page",
 
141
    /**
 
142
     * @cfg {String} lastText
 
143
     * The quicktip text displayed for the Refresh button (defaults to <tt>"Refresh"</tt>).
 
144
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 
145
     */
 
146
    refreshText : "Refresh",
 
147
 
 
148
    /**
 
149
     * Object mapping of parameter names used for load calls.  This property is affected by
 
150
     * See also {@link Ext.data.Store#paramNames}, but is initially set to:
 
151
     * <pre>{start: 'start', limit: 'limit'}</pre>
 
152
     */
 
153
    paramNames : {start: 'start', limit: 'limit'},
 
154
 
 
155
    /**
 
156
     * The number of records to display per page.  See also <tt>{@link #cursor}</tt>.
 
157
     * @type Number
 
158
     * @property pageSize
 
159
     */
 
160
 
 
161
    /**
 
162
     * Indicator for the record position.  This property might be used to get the active page
 
163
     * number for example:<pre><code>
 
164
     * // t is reference to the paging toolbar instance
 
165
     * var activePage = Math.ceil((t.cursor + t.pageSize) / t.pageSize);
 
166
     * </code></pre>
 
167
     * @type Number
 
168
     * @property cursor
 
169
     */
 
170
 
 
171
    initComponent: function(){
 
172
        var pagingItems = [this.first = new T.Button({
 
173
            tooltip: this.firstText,
 
174
            iconCls: "x-tbar-page-first",
 
175
            disabled: true,
 
176
            handler: this.onClick,
 
177
            scope: this
 
178
        }), this.prev = new T.Button({
 
179
            tooltip: this.prevText,
 
180
            iconCls: "x-tbar-page-prev",
 
181
            disabled: true,
 
182
            handler: this.onClick,
 
183
            scope: this
 
184
        }), '-', this.beforePageText,
 
185
        this.inputItem = new T.Item({
 
186
            height: 18,
 
187
            autoEl: {
 
188
                tag: "input",
 
189
                type: "text",
 
190
                size: "3",
 
191
                value: "1",
 
192
                cls: "x-tbar-page-number"
 
193
            }
 
194
        }), this.afterTextItem = new T.TextItem({
 
195
            text: String.format(this.afterPageText, 1)
 
196
        }), '-', this.next = new T.Button({
 
197
            tooltip: this.nextText,
 
198
            iconCls: "x-tbar-page-next",
 
199
            disabled: true,
 
200
            handler: this.onClick,
 
201
            scope: this
 
202
        }), this.last = new T.Button({
 
203
            tooltip: this.lastText,
 
204
            iconCls: "x-tbar-page-last",
 
205
            disabled: true,
 
206
            handler: this.onClick,
 
207
            scope: this
 
208
        }), '-', this.refresh = new T.Button({
 
209
            tooltip: this.refreshText,
 
210
            iconCls: "x-tbar-loading",
 
211
            handler: this.onClick,
 
212
            scope: this
 
213
        })];
 
214
 
 
215
 
 
216
        var userItems = this.items || this.buttons || [];
 
217
        if (this.prependButtons) {
 
218
            this.items = userItems.concat(pagingItems);
 
219
        }else{
 
220
            this.items = pagingItems.concat(userItems);
 
221
        }
 
222
        delete this.buttons;
 
223
        if(this.displayInfo){
 
224
            this.items.push('->');
 
225
            this.items.push(this.displayItem = new T.TextItem({}));
 
226
        }
 
227
        Ext.PagingToolbar.superclass.initComponent.call(this);
 
228
        this.addEvents(
 
229
            /**
 
230
             * @event change
 
231
             * Fires after the active page has been changed.
 
232
             * @param {Ext.PagingToolbar} this
 
233
             * @param {Object} pageData An object that has these properties:<ul>
 
234
             * <li><code>total</code> : Number <div class="sub-desc">The total number of records in the dataset as
 
235
             * returned by the server</div></li>
 
236
             * <li><code>activePage</code> : Number <div class="sub-desc">The current page number</div></li>
 
237
             * <li><code>pages</code> : Number <div class="sub-desc">The total number of pages (calculated from
 
238
             * the total number of records in the dataset as returned by the server and the current {@link #pageSize})</div></li>
 
239
             * </ul>
 
240
             */
 
241
            'change',
 
242
            /**
 
243
             * @event beforechange
 
244
             * Fires just before the active page is changed.
 
245
             * Return false to prevent the active page from being changed.
 
246
             * @param {Ext.PagingToolbar} this
 
247
             * @param {Object} params An object hash of the parameters which the PagingToolbar will send when
 
248
             * loading the required page. This will contain:<ul>
 
249
             * <li><code>start</code> : Number <div class="sub-desc">The starting row number for the next page of records to
 
250
             * be retrieved from the server</div></li>
 
251
             * <li><code>limit</code> : Number <div class="sub-desc">The number of records to be retrieved from the server</div></li>
 
252
             * </ul>
 
253
             * <p>(note: the names of the <b>start</b> and <b>limit</b> properties are determined
 
254
             * by the store's {@link Ext.data.Store#paramNames paramNames} property.)</p>
 
255
             * <p>Parameters may be added as required in the event handler.</p>
 
256
             */
 
257
            'beforechange'
 
258
        );
 
259
        this.on('afterlayout', this.onFirstLayout, this, {single: true});
 
260
        this.cursor = 0;
 
261
        this.bindStore(this.store);
 
262
    },
 
263
 
 
264
    // private
 
265
    onFirstLayout: function(ii) {
 
266
        this.mon(this.inputItem.el, "keydown", this.onPagingKeyDown, this);
 
267
        this.mon(this.inputItem.el, "blur", this.onPagingBlur, this);
 
268
        this.mon(this.inputItem.el, "focus", this.onPagingFocus, this);
 
269
 
 
270
        this.field = this.inputItem.el.dom;
 
271
        if(this.dsLoaded){
 
272
            this.onLoad.apply(this, this.dsLoaded);
 
273
        }
 
274
    },
 
275
 
 
276
    // private
 
277
    updateInfo : function(){
 
278
        if(this.displayItem){
 
279
            var count = this.store.getCount();
 
280
            var msg = count == 0 ?
 
281
                this.emptyMsg :
 
282
                String.format(
 
283
                    this.displayMsg,
 
284
                    this.cursor+1, this.cursor+count, this.store.getTotalCount()
 
285
                );
 
286
            this.displayItem.setText(msg);
 
287
        }
 
288
    },
 
289
 
 
290
    // private
 
291
    onLoad : function(store, r, o){
 
292
        if(!this.rendered){
 
293
            this.dsLoaded = [store, r, o];
 
294
            return;
 
295
        }
 
296
        this.cursor = (o.params && o.params[this.paramNames.start]) ? o.params[this.paramNames.start] : 0;
 
297
        var d = this.getPageData(), ap = d.activePage, ps = d.pages;
 
298
 
 
299
        this.afterTextItem.setText(String.format(this.afterPageText, d.pages));
 
300
        this.field.value = ap;
 
301
        this.first.setDisabled(ap == 1);
 
302
        this.prev.setDisabled(ap == 1);
 
303
        this.next.setDisabled(ap == ps);
 
304
        this.last.setDisabled(ap == ps);
 
305
        this.refresh.enable();
 
306
        this.updateInfo();
 
307
        this.fireEvent('change', this, d);
 
308
    },
 
309
 
 
310
    // private
 
311
    getPageData : function(){
 
312
        var total = this.store.getTotalCount();
 
313
        return {
 
314
            total : total,
 
315
            activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
 
316
            pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
 
317
        };
 
318
    },
 
319
 
 
320
    /**
 
321
     * Change the active page
 
322
     * @param {Integer} page The page to display
 
323
     */
 
324
    changePage: function(page){
 
325
        this.doLoad(((page-1) * this.pageSize).constrain(0, this.store.getTotalCount()));
 
326
    },
 
327
 
 
328
    // private
 
329
    onLoadError : function(){
 
330
        if(!this.rendered){
 
331
            return;
 
332
        }
 
333
        this.refresh.enable();
 
334
    },
 
335
 
 
336
    // private
 
337
    readPage : function(d){
 
338
        var v = this.field.value, pageNum;
 
339
        if (!v || isNaN(pageNum = parseInt(v, 10))) {
 
340
            this.field.value = d.activePage;
 
341
            return false;
 
342
        }
 
343
        return pageNum;
 
344
    },
 
345
 
 
346
    onPagingFocus: function(){
 
347
        this.field.select();
 
348
    },
 
349
 
 
350
    //private
 
351
    onPagingBlur: function(e){
 
352
        this.field.value = this.getPageData().activePage;
 
353
    },
 
354
 
 
355
    // private
 
356
    onPagingKeyDown : function(e){
 
357
        var k = e.getKey(), d = this.getPageData(), pageNum;
 
358
        if (k == e.RETURN) {
 
359
            e.stopEvent();
 
360
            pageNum = this.readPage(d);
 
361
            if(pageNum !== false){
 
362
                pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
 
363
                this.doLoad(pageNum * this.pageSize);
 
364
            }
 
365
        }else if (k == e.HOME || k == e.END){
 
366
            e.stopEvent();
 
367
            pageNum = k == e.HOME ? 1 : d.pages;
 
368
            this.field.value = pageNum;
 
369
        }else if (k == e.UP || k == e.PAGEUP || k == e.DOWN || k == e.PAGEDOWN){
 
370
            e.stopEvent();
 
371
            if((pageNum = this.readPage(d))){
 
372
                var increment = e.shiftKey ? 10 : 1;
 
373
                if(k == e.DOWN || k == e.PAGEDOWN){
 
374
                    increment *= -1;
 
375
                }
 
376
                pageNum += increment;
 
377
                if(pageNum >= 1 & pageNum <= d.pages){
 
378
                    this.field.value = pageNum;
 
379
                }
 
380
            }
 
381
        }
 
382
    },
 
383
 
 
384
    // private
 
385
    beforeLoad : function(){
 
386
        if(this.rendered && this.refresh){
 
387
            this.refresh.disable();
 
388
        }
 
389
    },
 
390
 
 
391
    // private
 
392
    doLoad : function(start){
 
393
        var o = {}, pn = this.paramNames;
 
394
        o[pn.start] = start;
 
395
        o[pn.limit] = this.pageSize;
 
396
        if(this.fireEvent('beforechange', this, o) !== false){
 
397
            this.store.load({params:o});
 
398
        }
 
399
    },
 
400
 
 
401
    // private
 
402
    onClick : function(button){
 
403
        var store = this.store;
 
404
        switch(button){
 
405
            case this.first:
 
406
                this.doLoad(0);
 
407
            break;
 
408
            case this.prev:
 
409
                this.doLoad(Math.max(0, this.cursor-this.pageSize));
 
410
            break;
 
411
            case this.next:
 
412
                this.doLoad(this.cursor+this.pageSize);
 
413
            break;
 
414
            case this.last:
 
415
                var total = store.getTotalCount();
 
416
                var extra = total % this.pageSize;
 
417
                var lastStart = extra ? (total - extra) : total-this.pageSize;
 
418
                this.doLoad(lastStart);
 
419
            break;
 
420
            case this.refresh:
 
421
                this.doLoad(this.cursor);
 
422
            break;
 
423
        }
 
424
    },
 
425
 
 
426
    /**
 
427
     * Binds the paging toolbar to the specified {@link Ext.data.Store}
 
428
     * @param {Store} store The store to bind to this view
 
429
     */
 
430
    bindStore : function(store, initial){
 
431
        if(!initial && this.store){
 
432
            this.store.un("beforeload", this.beforeLoad, this);
 
433
            this.store.un("load", this.onLoad, this);
 
434
            this.store.un("loadexception", this.onLoadError, this);
 
435
            this.store.un("exception", this.onLoadError, this);
 
436
            if(store !== this.store && this.store.autoDestroy){
 
437
                this.store.destroy();
 
438
            }
 
439
        }
 
440
        if(store){
 
441
            store = Ext.StoreMgr.lookup(store);
 
442
            store.on({
 
443
                scope: this,
 
444
                beforeload: this.beforeLoad,
 
445
                load: this.onLoad,
 
446
                loadexception: this.onLoadError,
 
447
                exception: this.onLoadError
 
448
            });
 
449
            this.paramNames.start = store.paramNames.start;
 
450
            this.paramNames.limit = store.paramNames.limit;
 
451
 
 
452
            if (store.getCount() > 0){
 
453
                this.onLoad(store, null, {});
 
454
            }
 
455
        }
 
456
        this.store = store;
 
457
    },
 
458
 
 
459
    /**
 
460
     * Unbinds the paging toolbar from the specified {@link Ext.data.Store} <b>(deprecated)</b>
 
461
     * @param {Ext.data.Store} store The data store to unbind
 
462
     */
 
463
    unbind : function(store){
 
464
        this.bindStore(null);
 
465
    },
 
466
 
 
467
    /**
 
468
     * Binds the paging toolbar to the specified {@link Ext.data.Store} <b>(deprecated)</b>
 
469
     * @param {Ext.data.Store} store The data store to bind
 
470
     */
 
471
    bind : function(store){
 
472
        this.bindStore(store);
 
473
    },
 
474
 
 
475
    // private
 
476
    onDestroy : function(){
 
477
        this.bindStore(null);
 
478
        Ext.PagingToolbar.superclass.onDestroy.call(this);
 
479
    }
 
480
});
 
481
 
 
482
})();
 
483
Ext.reg('paging', Ext.PagingToolbar);
 
 
b'\\ No newline at end of file'