Roo/bootstrap/Table.js
[roojs1] / Roo / bootstrap / Table.js
1 /*
2  * - LGPL
3  *
4  * table
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.Table
10  * @extends Roo.bootstrap.Component
11  * Bootstrap Table class
12  * @cfg {String} cls table class
13  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
14  * @cfg {String} bgcolor Specifies the background color for a table
15  * @cfg {Number} border Specifies whether the table cells should have borders or not
16  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
17  * @cfg {Number} cellspacing Specifies the space between cells
18  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
19  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
20  * @cfg {String} sortable Specifies that the table should be sortable
21  * @cfg {String} summary Specifies a summary of the content of a table
22  * @cfg {Number} width Specifies the width of a table
23  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
24  * 
25  * @cfg {boolean} striped Should the rows be alternative striped
26  * @cfg {boolean} bordered Add borders to the table
27  * @cfg {boolean} hover Add hover highlighting
28  * @cfg {boolean} condensed Format condensed
29  * @cfg {boolean} responsive Format condensed
30  * @cfg {Boolean} loadMask (true|false) default false
31  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
32  * @cfg {Boolean} thead (true|false) generate thead, default true
33  * @cfg {Boolean} RowSelection (true|false) default false
34  * @cfg {Boolean} CellSelection (true|false) default false
35  *
36  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
37  
38  * 
39  * @constructor
40  * Create a new Table
41  * @param {Object} config The config object
42  */
43
44 Roo.bootstrap.Table = function(config){
45     Roo.bootstrap.Table.superclass.constructor.call(this, config);
46     
47     if (this.sm) {
48         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
49         this.sm = this.selModel;
50         this.sm.xmodule = this.xmodule || false;
51     }
52     if (this.cm && typeof(this.cm.config) == 'undefined') {
53         this.colModel = new Roo.grid.ColumnModel(this.cm);
54         this.cm = this.colModel;
55         this.cm.xmodule = this.xmodule || false;
56     }
57     if (this.store) {
58         this.store= Roo.factory(this.store, Roo.data);
59         this.ds = this.store;
60         this.ds.xmodule = this.xmodule || false;
61          
62     }
63     if (this.footer && this.store) {
64         this.footer.dataSource = this.ds;
65         this.footer = Roo.factory(this.footer);
66     }
67     
68     /** @private */
69     this.addEvents({
70         /**
71          * @event cellclick
72          * Fires when a cell is clicked
73          * @param {Roo.bootstrap.Table} this
74          * @param {Roo.Element} el
75          * @param {Number} rowIndex
76          * @param {Number} columnIndex
77          * @param {Roo.EventObject} e
78          */
79         "cellclick" : true,
80         /**
81          * @event celldblclick
82          * Fires when a cell is double clicked
83          * @param {Roo.bootstrap.Table} this
84          * @param {Roo.Element} el
85          * @param {Number} rowIndex
86          * @param {Number} columnIndex
87          * @param {Roo.EventObject} e
88          */
89         "celldblclick" : true,
90         /**
91          * @event rowclick
92          * Fires when a row is clicked
93          * @param {Roo.bootstrap.Table} this
94          * @param {Roo.Element} el
95          * @param {Number} rowIndex
96          * @param {Roo.EventObject} e
97          */
98         "rowclick" : true,
99         /**
100          * @event rowdblclick
101          * Fires when a row is double clicked
102          * @param {Roo.bootstrap.Table} this
103          * @param {Roo.Element} el
104          * @param {Number} rowIndex
105          * @param {Roo.EventObject} e
106          */
107         "rowdblclick" : true,
108         /**
109          * @event rowclass
110          * Fires when a row is rendered, so you can change add a style to it.
111          * @param {Roo.bootstrap.Table} this
112          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
113          */
114         'rowclass' : true
115         
116     });
117 };
118
119 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
120     
121     cls: false,
122     align: false,
123     bgcolor: false,
124     border: false,
125     cellpadding: false,
126     cellspacing: false,
127     frame: false,
128     rules: false,
129     sortable: false,
130     summary: false,
131     width: false,
132     striped : false,
133     bordered: false,
134     hover:  false,
135     condensed : false,
136     responsive : false,
137     sm : false,
138     cm : false,
139     store : false,
140     loadMask : false,
141     tfoot : true,
142     thead : true,
143     RowSelection : false,
144     CellSelection : false,
145     layout : false,
146     
147     
148     getAutoCreate : function(){
149         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
150         
151         cfg = {
152             tag: 'table',
153             cls : 'table',
154             cn : []
155         }
156             
157         if (this.striped) {
158             cfg.cls += ' table-striped';
159         }
160         
161         if (this.hover) {
162             cfg.cls += ' table-hover';
163         }
164         if (this.bordered) {
165             cfg.cls += ' table-bordered';
166         }
167         if (this.condensed) {
168             cfg.cls += ' table-condensed';
169         }
170         if (this.responsive) {
171             cfg.cls += ' table-responsive';
172         }
173         
174         if (this.cls) {
175             cfg.cls+=  ' ' +this.cls;
176         }
177         
178         // this lot should be simplifed...
179         
180         if (this.align) {
181             cfg.align=this.align;
182         }
183         if (this.bgcolor) {
184             cfg.bgcolor=this.bgcolor;
185         }
186         if (this.border) {
187             cfg.border=this.border;
188         }
189         if (this.cellpadding) {
190             cfg.cellpadding=this.cellpadding;
191         }
192         if (this.cellspacing) {
193             cfg.cellspacing=this.cellspacing;
194         }
195         if (this.frame) {
196             cfg.frame=this.frame;
197         }
198         if (this.rules) {
199             cfg.rules=this.rules;
200         }
201         if (this.sortable) {
202             cfg.sortable=this.sortable;
203         }
204         if (this.summary) {
205             cfg.summary=this.summary;
206         }
207         if (this.width) {
208             cfg.width=this.width;
209         }
210         if (this.layout) {
211             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
212         }
213         
214         if(this.store || this.cm){
215             if(this.thead){
216                 cfg.cn.push(this.renderHeader());
217             }
218             
219             cfg.cn.push(this.renderBody());
220             
221             if(this.tfoot){
222                 cfg.cn.push(this.renderFooter());
223             }
224             
225             cfg.cls+=  ' TableGrid';
226         }
227         
228         return { cn : [ cfg ] };
229     },
230     
231     initEvents : function()
232     {   
233         if(!this.store || !this.cm){
234             return;
235         }
236         
237         Roo.log('initEvents with ds!!!!');
238         
239         var _this = this;
240         
241         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
242             e.on('click', _this.sort, _this);
243         });
244         
245         this.el.on("click", this.onClick, this);
246         this.el.on("dblclick", this.onDblClick, this);
247         
248         this.parent().el.setStyle('position', 'relative');
249         if (this.footer) {
250             this.footer.parentId = this.id;
251             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
252         }
253         
254         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
255         
256         this.store.on('load', this.onLoad, this);
257         this.store.on('beforeload', this.onBeforeLoad, this);
258         
259     },
260     
261     onClick : function(e, el)
262     {
263         var cell = Roo.get(el);
264         var row = cell.findParent('tr', false, true);
265         var cellIndex = cell.dom.cellIndex;
266         var rowIndex = row.dom.rowIndex;
267         
268         if(this.CellSelection){
269             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
270         }
271         
272         if(this.RowSelection){
273             this.fireEvent('rowclick', this, row, rowIndex, e);
274         }
275         
276         
277     },
278     
279     onDblClick : function(e,el)
280     {
281         var cell = Roo.get(el);;
282         var row = cell.findParent('tr', false, true);
283         var cellIndex = cell.dom.cellIndex;
284         var rowIndex = row.dom.rowIndex;
285         
286         if(this.CellSelection){
287             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
288         }
289         
290         if(this.RowSelection){
291             this.fireEvent('rowdblclick', this, row, rowIndex, e);
292         }
293     },
294     
295     sort : function(e,el)
296     {
297         var col = Roo.get(el)
298         
299         if(!col.hasClass('sortable')){
300             return;
301         }
302         
303         var sort = col.attr('sort');
304         var dir = 'ASC';
305         
306         if(col.hasClass('glyphicon-arrow-up')){
307             dir = 'DESC';
308         }
309         
310         this.store.sortInfo = {field : sort, direction : dir};
311         
312         if (this.footer) {
313             Roo.log("calling footer first");
314             this.footer.onClick('first');
315         } else {
316         
317             this.store.load({ params : { start : 0 } });
318         }
319     },
320     
321     renderHeader : function()
322     {
323         var header = {
324             tag: 'thead',
325             cn : []
326         };
327         
328         var cm = this.cm;
329         
330         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
331             
332             var config = cm.config[i];
333             
334             if(typeof(config.hidden) != 'undefined' && config.hidden){
335                 continue;
336             }
337                     
338             var c = {
339                 tag: 'th',
340                 style : '',
341                 html: cm.getColumnHeader(i)
342             };
343             
344             if(typeof(config.dataIndex) != 'undefined'){
345                 c.sort = config.dataIndex;
346             }
347             
348             if(typeof(config.sortable) != 'undefined' && config.sortable){
349                 c.cls = 'sortable';
350             }
351             
352 //            if(typeof(config.align) != 'undefined' && config.align.length){
353 //                c.style += ' text-align:' + config.align + ';';
354 //            }
355             
356             if(typeof(config.width) != 'undefined'){
357                 c.style += ' width:' + config.width + 'px;';
358             }
359             
360             header.cn.push(c)
361         }
362         
363         return header;
364     },
365     
366     renderBody : function()
367     {
368         var body = {
369             tag: 'tbody',
370             cn : [
371                 {
372                     tag: 'tr',
373                     cn : [
374                         {
375                             tag : 'td',
376                             colspan :  this.cm.getColumnCount()
377                         }
378                     ]
379                 }
380             ]
381         };
382         
383         return body;
384     },
385     
386     renderFooter : function()
387     {
388         var footer = {
389             tag: 'tfoot',
390             cn : [
391                 {
392                     tag: 'tr',
393                     cn : [
394                         {
395                             tag : 'td',
396                             colspan :  this.cm.getColumnCount()
397                         }
398                     ]
399                 }
400             ]
401         };
402         
403         return footer;
404     },
405     
406     onLoad : function()
407     {
408         Roo.log('ds onload');
409         this.clear();
410         
411         var _this = this;
412         var cm = this.cm;
413         
414         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
415             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
416             
417             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
418                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
419             }
420             
421             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
422                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
423             }
424         });
425         
426         var tbody = this.el.select('tbody', true).first();
427         
428         var renders = [];
429                     
430         if(this.store.getCount() > 0){
431             this.store.data.each(function(d,rowIndex){
432                 var row = {
433                     tag : 'tr',
434                     cn : []
435                 };
436                 
437                 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
438                     var config = cm.config[i];
439                     
440                     if(typeof(config.hidden) != 'undefined' && config.hidden){
441                         continue;
442                     }
443                     
444                     var renderer = cm.getRenderer(i);
445                     var value = '';
446                     var id = Roo.id();
447                     
448                     if(typeof(renderer) !== 'undefined'){
449                         value = renderer(d.data[cm.getDataIndex(i)], false, d);
450                     }
451                     
452                     if(typeof(value) === 'object'){
453                         renders.push({
454                             container : id,
455                             cfg : value 
456                         })
457                     }
458                     
459                     var rowcfg = {
460                         record: d,
461                         rowIndex : rowIndex,
462                         colIndex : i,
463                         rowClass : ''
464                     }
465
466                     _this.fireEvent('rowclass', this, rowcfg);
467                     
468                     var td = {
469                         tag: 'td',
470                         id: id,
471                         cls : rowcfg.rowClass,
472                         style: '',
473                         html: (typeof(value) === 'object') ? '' : value
474                     };
475                     
476                     if(typeof(config.align) != 'undefined' && config.align.length){
477                         td.style += ' text-align:' + config.align + ';';
478                     }
479                     
480                     if(typeof(config.width) != 'undefined'){
481                         td.style += ' width:' +  config.width + 'px;';
482                     }
483                     
484                     
485                     row.cn.push(td);
486                    
487                 }
488                 
489                 tbody.createChild(row);
490                 
491             });
492         }
493         
494         
495         if(renders.length){
496             var _this = this;
497             Roo.each(renders, function(r){
498                 _this.renderColumn(r);
499             })
500         }
501
502         //if(this.loadMask){
503         //    this.maskEl.hide();
504         //}
505     },
506     
507     onBeforeLoad : function()
508     {
509         //Roo.log('ds onBeforeLoad');
510         
511         //this.clear();
512         
513         //if(this.loadMask){
514         //    this.maskEl.show();
515         //}
516     },
517     
518     clear : function()
519     {
520         this.el.select('tbody', true).first().dom.innerHTML = '';
521     },
522     
523     getSelectionModel : function(){
524         if(!this.selModel){
525             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
526         }
527         return this.selModel;
528     },
529     
530     renderColumn : function(r)
531     {
532         var _this = this;
533         
534         var cn = Roo.apply(r.cfg);
535         
536         var t = cn.render(r.container);
537         
538         if(r.cfg.cn){
539             Roo.each(r.cfg.cn, function(c){
540                 var child = {
541                     container: t.getChildContainer(),
542                     cfg: c
543                 }
544                 _this.renderColumn(child);
545             })
546         }
547     }
548    
549 });
550
551  
552
553