sync
[roojs1] / Roo / htmleditor / BlockTable.js
1  
2
3 /**
4  * @class Roo.htmleditor.BlockTable
5  * Block that manages a table
6  * 
7  * @constructor
8  * Create a new Filter.
9  * @param {Object} config Configuration options
10  */
11
12 Roo.htmleditor.BlockTable = function(cfg)
13 {
14     if (cfg.node) {
15         this.readElement(cfg.node);
16         this.updateElement(cfg.node);
17     }
18     Roo.apply(this, cfg);
19     if (!cfg.node) {
20         this.rows = [];
21         for(var r = 0; r < this.no_row; r++) {
22             this.rows[r] = []
23             for(var c = 0; c < this.no_col; c++) {
24                 this.rows[r][c] = this.emptyCell();
25             }
26         }
27     }
28     
29     
30 }
31 Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
32  
33     rows : false,
34     no_col : 1,
35     no_row : 1,
36     
37     
38     width: '100%',
39     
40     // used by context menu
41     friendly_name : 'Table',
42     deleteTitle : 'Delete Table',
43     // context menu is drawn once..
44     
45     contextMenu : function(toolbar)
46     {
47         
48         var block = function() {
49             return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
50         };
51         
52         
53         var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
54         
55         var syncValue = toolbar.editorcore.syncValue;
56         
57         var fields = {};
58         
59         return [
60             {
61                 xtype : 'ComboBox',
62                 allowBlank : false,
63                 displayField : 'val',
64                 editable : true,
65                 listWidth : 100,
66                 triggerAction : 'all',
67                 typeAhead : true,
68                 valueField : 'val',
69                 width : 100,
70                 name : 'width',
71                 listeners : {
72                     select : function (combo, r, index)
73                     {
74                         var b = block();
75                         b.width = r.get('val');
76                         b.updateElement();
77                         syncValue();
78                         
79                     }
80                 },
81                 xns : rooui.form,
82                 store : {
83                     xtype : 'SimpleStore',
84                     data : [
85                         ['100%'],
86                         ['auto']
87                     ],
88                     fields : [ 'val'],
89                     xns : Roo.data
90                 }
91             },
92             // -------- Cols
93             
94             {
95                 xtype : 'TextItem',
96                 text : "Columns: ",
97                 xns : rooui.Toolbar  //Boostrap?
98             },
99          
100             {
101                 xtype : 'Button',
102                 text: '-',
103                 listeners : {
104                     click : function (_self, e)
105                     {
106                         block().removeColumn();
107                         syncValue();
108                     }
109                 },
110                 xns : rooui.Toolbar
111             },
112             {
113                 xtype : 'Button',
114                 text: '+',
115                 listeners : {
116                     click : function (_self, e)
117                     {
118                         block().addColumn();
119                         syncValue();
120                     }
121                 },
122                 xns : rooui.Toolbar
123             },
124             // -------- ROWS
125             {
126                 xtype : 'TextItem',
127                 text : "Rows: ",
128                 xns : rooui.Toolbar  //Boostrap?
129             },
130          
131             {
132                 xtype : 'Button',
133                 text: '-',
134                 listeners : {
135                     click : function (_self, e)
136                     {
137                         block().removeRow();
138                         syncValue();
139                     }
140                 },
141                 xns : rooui.Toolbar
142             },
143             {
144                 xtype : 'Button',
145                 text: '+',
146                 listeners : {
147                     click : function (_self, e)
148                     {
149                         block().addRow();
150                         syncValue();
151                     }
152                 },
153                 xns : rooui.Toolbar
154             },
155             // -------- ROWS
156             {
157                 xtype : 'Button',
158                 text: 'Reset Column Widths',
159                 listeners : {
160                     
161                     click : function (_self, e)
162                     {
163                         block().resetWidths();
164                         syncValue();
165                     }
166                 },
167                 xns : rooui.Toolbar
168             } 
169             
170             
171             
172         ];
173         
174     },
175     
176     
177   /**
178      * create a DomHelper friendly object - for use with
179      * Roo.DomHelper.markup / overwrite / etc..
180      * ?? should it be called with option to hide all editing features?
181      */
182     toObject : function()
183     {
184         
185         var ret = {
186             tag : 'table',
187             contenteditable : 'false', // this stops cell selection from picking the table.
188             'data-block' : 'Table',
189             style : {
190                 width:  this.width,
191                 border : 'solid 1px #000', // ??? hard coded?
192                 'border-collapse' : 'collapse',
193             },
194             cn : [
195                 { tag : 'tbody' , cn : [] }
196             ]
197         };
198         
199         // do we have a head = not really 
200         var ncols = 0;
201         Roo.each(this.rows, function( row ) {
202             var tr = {
203                 tag: 'tr',
204                 style : {
205                     margin: '6px',
206                     border : 'solid 1px #000',
207                     textAlign : 'left',
208                 },
209                 cn : [ ]
210             };
211             
212             ret.cn[0].cn.push(tr);
213             // does the row have any properties? ?? height?
214             var nc = 0;
215             Roo.each(row, function( cell ) {
216                 
217                 var td = {
218                     tag : 'td',
219                     contenteditable :  'true',
220                     'data-block' : 'Td',
221                     html : cell.html,
222                     style : cell.style
223                 };
224                 if (cell.colspan > 1) {
225                     td.colspan = cell.colspan ;
226                     nc += cell.colspan;
227                 } else {
228                     nc++;
229                 }
230                 if (cell.rowspan > 1) {
231                     td.rowspan = cell.rowspan ;
232                 }
233                 
234                 
235                 // widths ?
236                 tr.cn.push(td);
237                     
238                 
239             }, this);
240             ncols = Math.max(nc, ncols);
241             
242             
243         }, this);
244         // add the header row..
245         
246         ncols++;
247          
248         
249         return ret;
250          
251     },
252     
253     readElement : function(node)
254     {
255         node  = node ? node : this.node ;
256         this.width = this.getVal(node, true, 'style', 'width') || '100%';
257         
258         this.rows = [];
259         this.no_row = 0;
260         var trs = Array.from(node.getElementsByTagName('tr'));
261         trs.forEach(function(tr) {
262             var row =  []  
263             this.rows.push(row);
264             if (Roo.get(tr).hasClass('roo-html-editor-el')) { // ??? this is for our 'row' selection'
265                 return;
266             }
267             this.no_row++;
268             var no_column = 0;
269             Array.from(tr.getElementsByTagName('td')).forEach(function(td) {
270                 if (Roo.get(td).hasClass('roo-html-editor-el')) { // ??? this is for our 'row' selection'
271                     return;
272                 }
273                 var add = {
274                     colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan') : 1,
275                     rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan') : 1,
276                     style : td.hasAttribute('style') ? td.getAttribute('style') : '',
277                     html : td.innerHTML
278                 }
279                 no_column += add.colspan;
280                      
281                 
282                 row.push(add);
283                 
284                 
285             },this);
286             this.no_col = Math.max(this.no_col, no_column);
287             
288             
289         },this);
290         
291         
292     },
293     normalizeRows: function()
294     {
295         var ret= [];
296         var rid = -1;
297         this.rows.forEach(function(row) {
298             rid++;
299             ret[rid] = [];
300             row = this.normalizeRow(row);
301             var cid = 0;
302             row.forEach(function(c) {
303                 while (typeof(ret[rid][cid]) != 'undefined') {
304                     cid++;
305                 }
306                 if (typeof(ret[rid]) == 'undefined') {
307                     ret[rid] = [];
308                 }
309                 ret[rid][cid] = c;
310                 c.row = rid;
311                 c.col = cid;
312                 if (c.rowspan < 2) {
313                     return;
314                 }
315                 
316                 for(var i = 1 ;i < c.rowspan; i++) {
317                     if (typeof(ret[rid+i]) == 'undefined') {
318                         ret[rid+i] = [];
319                     }
320                     ret[rid+i][cid] = c;
321                 }
322             });
323         }, this);
324         return ret;
325     
326     },
327     
328     normalizeRow: function(row)
329     {
330         var ret= [];
331         row.forEach(function(c) {
332             if (c.colspan < 2) {
333                 ret.push(c);
334                 return;
335             }
336             for(var i =0 ;i < c.colspan; i++) {
337                 ret.push(c);
338             }
339         });
340         return ret;
341     
342     },
343     
344     deleteColumn : function(sel)
345     {
346         if (!sel || sel.type != 'col') {
347             return;
348         }
349         if (this.no_col < 2) {
350             return;
351         }
352         
353         this.rows.forEach(function(row) {
354             var cols = this.normalizeRow(row);
355             var col = cols[sel.col];
356             if (col.colspan > 1) {
357                 col.colspan --;
358             } else {
359                 row.remove(col);
360             }
361             
362         }, this);
363         this.no_col--;
364         
365     },
366     removeColumn : function()
367     {
368         this.deleteColumn({
369             type: 'col',
370             col : this.no_col-1
371         });
372         this.updateElement();
373     },
374     
375      
376     addColumn : function()
377     {
378         
379         this.rows.forEach(function(row) {
380             row.push(this.emptyCell());
381            
382         }, this);
383         this.updateElement();
384     },
385     
386     deleteRow : function(sel)
387     {
388         if (!sel || sel.type != 'row') {
389             return;
390         }
391         
392         if (this.no_row < 2) {
393             return;
394         }
395         
396         var rows = this.normalizeRows();
397         
398         
399         rows[sel.row].forEach(function(col) {
400             if (col.rowspan > 1) {
401                 col.rowspan--;
402             } else {
403                 col.remove = 1; // flage it as removed.
404             }
405             
406         }, this);
407         var newrows = [];
408         this.rows.forEach(function(row) {
409             newrow = [];
410             row.forEach(function(c) {
411                 if (typeof(c.remove) == 'undefined') {
412                     newrow.push(c);
413                 }
414                 
415             });
416             if (newrow.length > 0) {
417                 newrows.push(row);
418             }
419         });
420         this.rows =  newrows;
421         
422         
423         
424         this.no_row--;
425         this.updateElement();
426         
427     },
428     removeRow : function()
429     {
430         this.deleteRow({
431             type: 'row',
432             row : this.no_row-1
433         });
434         
435     },
436     
437      
438     addRow : function()
439     {
440         
441         row = [];
442         for (var i = 0; i < this.no_col; i++ ) {
443             
444             row.push(this.emptyCell());
445            
446         }
447         this.rows.push(row);
448         this.updateElement();
449         
450     },
451      
452     // the default cell object... at present...
453     emptyCell : function() {
454         return (new Roo.htmleditor.BlockTd({})).toObject();
455         
456      
457     },
458     
459     removeNode : function()
460     {
461         return this.node;
462     },
463     
464     
465     
466     resetWidths : function()
467     {
468         Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
469             var nn = Roo.htmleditor.Block.factory(n);
470             nn.width = '';
471             nn.updateElement(n);
472         });
473     }
474     
475     
476     
477     
478 })
479