55d82712dbcfb0c0acab8c7f5b00bf0e65a3a80d
[roojs1] / Roo / PagingToolbar.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12 /**
13  * @class Roo.PagingToolbar
14  * @extends Roo.Toolbar
15  * @children   Roo.Toolbar.Item Roo.form.Field
16  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17  * @constructor
18  * Create a new PagingToolbar
19  * @param {Object} config The config object
20  */
21 Roo.PagingToolbar = function(el, ds, config)
22 {
23     // old args format still supported... - xtype is prefered..
24     if (typeof(el) == 'object' && el.xtype) {
25         // created from xtype...
26         config = el;
27         ds = el.dataSource;
28         el = config.container;
29     }
30     var items = [];
31     if (config.items) {
32         items = config.items;
33         config.items = [];
34     }
35     
36     Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
37     this.ds = ds;
38     this.cursor = 0;
39     this.renderButtons(this.el);
40     this.bind(ds);
41     
42     // supprot items array.
43    
44     Roo.each(items, function(e) {
45         this.add(Roo.factory(e));
46     },this);
47     
48 };
49
50 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
51     /**
52      * @cfg {Roo.data.Store} dataSource
53      * The underlying data store providing the paged data
54      */
55     /**
56      * @cfg {String/HTMLElement/Element} container
57      * container The id or element that will contain the toolbar
58      */
59     /**
60      * @cfg {Boolean} displayInfo
61      * True to display the displayMsg (defaults to false)
62      */
63     /**
64      * @cfg {Number} pageSize
65      * The number of records to display per page (defaults to 20)
66      */
67     pageSize: 20,
68     /**
69      * @cfg {String} displayMsg
70      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
71      */
72     displayMsg : 'Displaying {0} - {1} of {2}',
73     /**
74      * @cfg {String} emptyMsg
75      * The message to display when no records are found (defaults to "No data to display")
76      */
77     emptyMsg : 'No data to display',
78     /**
79      * Customizable piece of the default paging text (defaults to "Page")
80      * @type String
81      */
82     beforePageText : "Page",
83     /**
84      * Customizable piece of the default paging text (defaults to "of %0")
85      * @type String
86      */
87     afterPageText : "of {0}",
88     /**
89      * Customizable piece of the default paging text (defaults to "First Page")
90      * @type String
91      */
92     firstText : "First Page",
93     /**
94      * Customizable piece of the default paging text (defaults to "Previous Page")
95      * @type String
96      */
97     prevText : "Previous Page",
98     /**
99      * Customizable piece of the default paging text (defaults to "Next Page")
100      * @type String
101      */
102     nextText : "Next Page",
103     /**
104      * Customizable piece of the default paging text (defaults to "Last Page")
105      * @type String
106      */
107     lastText : "Last Page",
108     /**
109      * Customizable piece of the default paging text (defaults to "Refresh")
110      * @type String
111      */
112     refreshText : "Refresh",
113
114     // private
115     renderButtons : function(el){
116         Roo.PagingToolbar.superclass.render.call(this, el);
117         this.first = this.addButton({
118             tooltip: this.firstText,
119             cls: "x-btn-icon x-grid-page-first",
120             disabled: true,
121             handler: this.onClick.createDelegate(this, ["first"])
122         });
123         this.prev = this.addButton({
124             tooltip: this.prevText,
125             cls: "x-btn-icon x-grid-page-prev",
126             disabled: true,
127             handler: this.onClick.createDelegate(this, ["prev"])
128         });
129         //this.addSeparator();
130         this.add(this.beforePageText);
131         this.field = Roo.get(this.addDom({
132            tag: "input",
133            type: "text",
134            size: "3",
135            value: "1",
136            cls: "x-grid-page-number"
137         }).el);
138         this.field.on("keydown", this.onPagingKeydown, this);
139         this.field.on("focus", function(){this.dom.select();});
140         this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
141         this.field.setHeight(18);
142         //this.addSeparator();
143         this.next = this.addButton({
144             tooltip: this.nextText,
145             cls: "x-btn-icon x-grid-page-next",
146             disabled: true,
147             handler: this.onClick.createDelegate(this, ["next"])
148         });
149         this.last = this.addButton({
150             tooltip: this.lastText,
151             cls: "x-btn-icon x-grid-page-last",
152             disabled: true,
153             handler: this.onClick.createDelegate(this, ["last"])
154         });
155         //this.addSeparator();
156         this.loading = this.addButton({
157             tooltip: this.refreshText,
158             cls: "x-btn-icon x-grid-loading",
159             handler: this.onClick.createDelegate(this, ["refresh"])
160         });
161
162         if(this.displayInfo){
163             this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
164         }
165     },
166
167     // private
168     updateInfo : function(){
169         if(this.displayEl){
170             var count = this.ds.getCount();
171             var msg = count == 0 ?
172                 this.emptyMsg :
173                 String.format(
174                     this.displayMsg,
175                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
176                 );
177             this.displayEl.update(msg);
178         }
179     },
180
181     // private
182     onLoad : function(ds, r, o){
183        this.cursor = o.params ? o.params.start : 0;
184        var d = this.getPageData(), ap = d.activePage, ps = d.pages;
185
186        this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
187        this.field.dom.value = ap;
188        this.first.setDisabled(ap == 1);
189        this.prev.setDisabled(ap == 1);
190        this.next.setDisabled(ap == ps);
191        this.last.setDisabled(ap == ps);
192        this.loading.enable();
193        this.updateInfo();
194     },
195
196     // private
197     getPageData : function(){
198         var total = this.ds.getTotalCount();
199         return {
200             total : total,
201             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
202             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
203         };
204     },
205
206     // private
207     onLoadError : function(){
208         this.loading.enable();
209     },
210
211     // private
212     onPagingKeydown : function(e){
213         var k = e.getKey();
214         var d = this.getPageData();
215         if(k == e.RETURN){
216             var v = this.field.dom.value, pageNum;
217             if(!v || isNaN(pageNum = parseInt(v, 10))){
218                 this.field.dom.value = d.activePage;
219                 return;
220             }
221             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
222             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
223             e.stopEvent();
224         }
225         else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
226         {
227           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
228           this.field.dom.value = pageNum;
229           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
230           e.stopEvent();
231         }
232         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
233         {
234           var v = this.field.dom.value, pageNum; 
235           var increment = (e.shiftKey) ? 10 : 1;
236           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
237             increment *= -1;
238           }
239           if(!v || isNaN(pageNum = parseInt(v, 10))) {
240             this.field.dom.value = d.activePage;
241             return;
242           }
243           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
244           {
245             this.field.dom.value = parseInt(v, 10) + increment;
246             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
247             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
248           }
249           e.stopEvent();
250         }
251     },
252
253     // private
254     beforeLoad : function(){
255         if(this.loading){
256             this.loading.disable();
257         }
258     },
259
260     // private
261     onClick : function(which){
262         var ds = this.ds;
263         switch(which){
264             case "first":
265                 ds.load({params:{start: 0, limit: this.pageSize}});
266             break;
267             case "prev":
268                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
269             break;
270             case "next":
271                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
272             break;
273             case "last":
274                 var total = ds.getTotalCount();
275                 var extra = total % this.pageSize;
276                 var lastStart = extra ? (total - extra) : total-this.pageSize;
277                 ds.load({params:{start: lastStart, limit: this.pageSize}});
278             break;
279             case "refresh":
280                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
281             break;
282         }
283     },
284
285     /**
286      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
287      * @param {Roo.data.Store} store The data store to unbind
288      */
289     unbind : function(ds){
290         ds.un("beforeload", this.beforeLoad, this);
291         ds.un("load", this.onLoad, this);
292         ds.un("loadexception", this.onLoadError, this);
293         ds.un("remove", this.updateInfo, this);
294         ds.un("add", this.updateInfo, this);
295         this.ds = undefined;
296     },
297
298     /**
299      * Binds the paging toolbar to the specified {@link Roo.data.Store}
300      * @param {Roo.data.Store} store The data store to bind
301      */
302     bind : function(ds){
303         ds.on("beforeload", this.beforeLoad, this);
304         ds.on("load", this.onLoad, this);
305         ds.on("loadexception", this.onLoadError, this);
306         ds.on("remove", this.updateInfo, this);
307         ds.on("add", this.updateInfo, this);
308         this.ds = ds;
309     }
310 });