5 * since selections really work on the table cell, then editing really should work from there
7 * The original plan was to support merging etc... - but that may not be needed yet..
9 * So this simple version will support:
11 * adjust the width +/-
21 * @class Roo.htmleditor.BlockTable
22 * Block that manages a table
25 * Create a new Filter.
26 * @param {Object} config Configuration options
29 Roo.htmleditor.BlockTd = function(cfg)
32 this.readElement(cfg.node);
33 this.updateElement(cfg.node);
40 Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
52 // used by context menu
53 friendly_name : 'Table Cell',
54 deleteTitle : false, // use our customer delete
56 // context menu is drawn once..
58 contextMenu : function(toolbar)
61 var cell = function() {
62 return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
65 var table = function() {
66 return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
70 var saveSel = function()
72 lr = toolbar.editorcore.getSelection().getRangeAt(0);
74 var restoreSel = function()
78 toolbar.editorcore.focus();
79 var cr = toolbar.editorcore.getSelection();
82 toolbar.editorcore.onEditorEvent();
89 var rooui = typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
91 var syncValue = toolbar.editorcore.syncValue;
101 var t = toolbar.tb.selectedNode.closest('table');
102 toolbar.editorcore.selectNode(t);
103 toolbar.editorcore.onEditorEvent();
113 text : "Column Width: ",
121 click : function (_self, e)
123 toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
124 cell().shrinkColumn();
126 toolbar.editorcore.onEditorEvent();
135 click : function (_self, e)
137 toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
140 toolbar.editorcore.onEditorEvent();
148 text : "Vertical Align: ",
149 xns : rooui.Toolbar //Boostrap?
154 displayField : 'val',
157 triggerAction : 'all',
163 select : function (combo, r, index)
165 toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
167 b.valign = r.get('val');
170 toolbar.editorcore.onEditorEvent();
175 xtype : 'SimpleStore',
179 ['bottom'] // there are afew more...
188 text : "Merge Cells: ",
198 click : function (_self, e)
200 toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
202 //block().growColumn();
204 toolbar.editorcore.onEditorEvent();
214 click : function (_self, e)
216 toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
218 //block().growColumn();
220 toolbar.editorcore.onEditorEvent();
236 click : function (_self, e)
238 //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
241 toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
242 toolbar.editorcore.onEditorEvent();
268 click : function (_self, e)
272 cell().deleteColumn();
274 toolbar.editorcore.selectNode(t.node);
275 toolbar.editorcore.onEditorEvent();
284 click : function (_self, e)
290 toolbar.editorcore.selectNode(t.node);
291 toolbar.editorcore.onEditorEvent();
305 click : function (_self, e)
308 var nn = t.node.nextSibling || t.node.previousSibling;
309 t.node.parentNode.removeChild(t.node);
311 toolbar.editorcore.selectNode(nn, true);
313 toolbar.editorcore.onEditorEvent();
331 * create a DomHelper friendly object - for use with
332 * Roo.DomHelper.markup / overwrite / etc..
333 * ?? should it be called with option to hide all editing features?
336 * create a DomHelper friendly object - for use with
337 * Roo.DomHelper.markup / overwrite / etc..
338 * ?? should it be called with option to hide all editing features?
340 toObject : function()
344 contenteditable : 'true', // this stops cell selection from picking the table.
346 valign : this.valign,
348 'text-align' : this.textAlign,
349 border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
350 'border-collapse' : 'collapse',
351 padding : '6px', // 8 for desktop / 4 for mobile
352 'vertical-align': this.valign
356 if (this.width != '') {
357 ret.width = this.width;
358 ret.style.width = this.width;
362 if (this.colspan > 1) {
363 ret.colspan = this.colspan ;
365 if (this.rowspan > 1) {
366 ret.rowspan = this.rowspan ;
375 readElement : function(node)
377 node = node ? node : this.node ;
378 this.width = node.style.width;
379 this.colspan = Math.max(1,1*node.getAttribute('colspan'));
380 this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
381 this.html = node.innerHTML;
382 if (node.style.textAlign != '') {
383 this.textAlign = node.style.textAlign;
389 // the default cell object... at present...
390 emptyCell : function() {
395 html : " " // is this going to be editable now?
400 removeNode : function()
402 return this.node.closest('table');
410 toTableArray : function()
413 var tab = this.node.closest('tr').closest('table');
414 Array.from(tab.rows).forEach(function(r, ri){
420 Array.from(tab.rows).forEach(function(r, ri){
423 Array.from(r.cells).forEach(function(ce, ci){
428 colspan : ce.colSpan,
431 if (ce.isEqualNode(this.node)) {
434 // if we have been filled up by a row?
435 if (typeof(ret[rn][cn]) != 'undefined') {
436 while(typeof(ret[rn][cn]) != 'undefined') {
442 if (typeof(this.colWidths[cn]) == 'undefined' && c.colspan < 2) {
443 this.colWidths[cn] = ce.style.width;
444 if (this.colWidths[cn] != '') {
450 if (c.colspan < 2 && c.rowspan < 2 ) {
455 for(var j = 0; j < c.rowspan; j++) {
456 if (typeof(ret[rn+j]) == 'undefined') {
457 continue; // we have a problem..
460 for(var i = 0; i < c.colspan; i++) {
470 // initalize widths.?
471 // either all widths or no widths..
473 this.colWidths[0] = false; // no widths flag.
484 mergeRight: function()
487 // get the contents of the next cell along..
488 var tr = this.node.closest('tr');
489 var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
490 if (i >= tr.childNodes.length - 1) {
491 return; // no cells on right to merge with.
493 var table = this.toTableArray();
495 if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
496 return; // nothing right?
498 var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
499 // right cell - must be same rowspan and on the same row.
500 if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
501 return; // right hand side is not same rowspan.
506 this.node.innerHTML += ' ' + rc.cell.innerHTML;
507 tr.removeChild(rc.cell);
508 this.colspan += rc.colspan;
509 this.node.setAttribute('colspan', this.colspan);
511 var table = this.toTableArray();
512 this.normalizeWidths(table);
513 this.updateWidths(table);
517 mergeBelow : function()
519 var table = this.toTableArray();
520 if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
521 return; // no row below
523 if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
524 return; // nothing right?
526 var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
528 if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
529 return; // right hand side is not same rowspan.
531 this.node.innerHTML = this.node.innerHTML + rc.cell.innerHTML ;
532 rc.cell.parentNode.removeChild(rc.cell);
533 this.rowspan += rc.rowspan;
534 this.node.setAttribute('rowspan', this.rowspan);
539 if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
542 var table = this.toTableArray();
543 var cd = this.cellData;
547 for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
550 for(var c = cd.col; c < cd.col + cd.colspan; c++) {
551 if (r == cd.row && c == cd.col) {
552 this.node.removeAttribute('rowspan');
553 this.node.removeAttribute('colspan');
556 var ntd = this.node.cloneNode(); // which col/row should be 0..
557 ntd.removeAttribute('id');
558 ntd.style.width = this.colWidths[c];
560 table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1 };
564 this.redrawAllCells(table);
570 redrawAllCells: function(table)
574 var tab = this.node.closest('tr').closest('table');
575 var ctr = tab.rows[0].parentNode;
576 Array.from(tab.rows).forEach(function(r, ri){
578 Array.from(r.cells).forEach(function(ce, ci){
579 ce.parentNode.removeChild(ce);
581 r.parentNode.removeChild(r);
583 for(var r = 0 ; r < table.length; r++) {
584 var re = tab.rows[r];
586 var re = tab.ownerDocument.createElement('tr');
588 for(var c = 0 ; c < table[r].length; c++) {
589 if (table[r][c].cell === false) {
593 re.appendChild(table[r][c].cell);
595 table[r][c].cell = false;
600 updateWidths : function(table)
602 for(var r = 0 ; r < table.length; r++) {
604 for(var c = 0 ; c < table[r].length; c++) {
605 if (table[r][c].cell === false) {
609 if (this.colWidths[0] != false && table[r][c].colspan < 2) {
610 var el = Roo.htmleditor.Block.factory(table[r][c].cell);
611 el.width = Math.floor(this.colWidths[c]) +'%';
612 el.updateElement(el.node);
614 if (this.colWidths[0] != false && table[r][c].colspan > 1) {
615 var el = Roo.htmleditor.Block.factory(table[r][c].cell);
617 for(var i = 0; i < table[r][c].colspan; i ++) {
618 width += Math.floor(this.colWidths[c + i]);
620 el.width = width +'%';
621 el.updateElement(el.node);
623 table[r][c].cell = false; // done
627 normalizeWidths : function(table)
629 if (this.colWidths[0] === false) {
630 var nw = 100.0 / this.colWidths.length;
631 this.colWidths.forEach(function(w,i) {
632 this.colWidths[i] = nw;
637 var t = 0, missing = [];
639 this.colWidths.forEach(function(w,i) {
641 this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
642 var add = this.colWidths[i];
651 var nc = this.colWidths.length;
652 if (missing.length) {
653 var mult = (nc - missing.length) / (1.0 * nc);
655 var ew = (100 -t) / (1.0 * missing.length);
656 this.colWidths.forEach(function(w,i) {
658 this.colWidths[i] = w * mult;
662 this.colWidths[i] = ew;
664 // have to make up numbers..
667 // now we should have all the widths..
672 shrinkColumn : function()
674 var table = this.toTableArray();
675 this.normalizeWidths(table);
676 var col = this.cellData.col;
677 var nw = this.colWidths[col] * 0.8;
681 var otherAdd = (this.colWidths[col] * 0.2) / (this.colWidths.length -1);
682 this.colWidths.forEach(function(w,i) {
684 this.colWidths[i] = nw;
687 this.colWidths[i] += otherAdd
689 this.updateWidths(table);
692 growColumn : function()
694 var table = this.toTableArray();
695 this.normalizeWidths(table);
696 var col = this.cellData.col;
697 var nw = this.colWidths[col] * 1.2;
701 var otherSub = (this.colWidths[col] * 0.2) / (this.colWidths.length -1);
702 this.colWidths.forEach(function(w,i) {
704 this.colWidths[i] = nw;
707 this.colWidths[i] -= otherSub
709 this.updateWidths(table);
712 deleteRow : function()
714 // delete this rows 'tr'
715 // if any of the cells in this row have a rowspan > 1 && row!= this row..
716 // then reduce the rowspan.
717 var table = this.toTableArray();
718 // this.cellData.row;
719 for (var i =0;i< table[this.cellData.row].length ; i++) {
720 var c = table[this.cellData.row][i];
721 if (c.row != this.cellData.row) {
724 c.cell.setAttribute('rowspan', c.rowspan);
729 c.cell.setAttribute('rowspan', c.rowspan);
732 table.splice(this.cellData.row,1);
733 this.redrawAllCells(table);
736 deleteColumn : function()
738 var table = this.toTableArray();
740 for (var i =0;i< table.length ; i++) {
741 var c = table[i][this.cellData.col];
742 if (c.col != this.cellData.col) {
743 table[i][this.cellData.col].colspan--;
744 } else if (c.colspan > 1) {
746 c.cell.setAttribute('colspan', c.colspan);
748 table[i].splice(this.cellData.col,1);
751 this.redrawAllCells(table);