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