+Roo.htmleditor.BlockTable = function(cfg)
+{
+ if (cfg.node) {
+ this.readElement(cfg.node);
+ this.updateElement(cfg.node);
+ }
+ Roo.apply(this, cfg);
+ if (!cfg.node) {
+ this.rows = [];
+ for(var r = 0; r < this.no_row; r++) {
+ this.rows[r] = [];
+ for(var c = 0; c < this.no_col; c++) {
+ this.rows[r][c] = this.emptyCell();
+ }
+ }
+ }
+
+
+}
+Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
+
+ rows : false,
+ no_col : 1,
+ no_row : 1,
+
+
+ width: '100%',
+
+ // used by context menu
+ friendly_name : 'Table',
+ deleteTitle : 'Delete Table',
+ // context menu is drawn once..
+
+ contextMenu : function(toolbar)
+ {
+
+ var block = function() {
+ return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
+ };
+
+
+ var rooui = typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
+
+ var syncValue = toolbar.editorcore.syncValue;
+
+ var fields = {};
+
+ return [
+ {
+ xtype : 'TextItem',
+ text : "Width: ",
+ xns : rooui.Toolbar //Boostrap?
+ },
+ {
+ xtype : 'ComboBox',
+ allowBlank : false,
+ displayField : 'val',
+ editable : true,
+ listWidth : 100,
+ triggerAction : 'all',
+ typeAhead : true,
+ valueField : 'val',
+ width : 100,
+ name : 'width',
+ listeners : {
+ select : function (combo, r, index)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ var b = block();
+ b.width = r.get('val');
+ b.updateElement();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.form,
+ store : {
+ xtype : 'SimpleStore',
+ data : [
+ ['100%'],
+ ['auto']
+ ],
+ fields : [ 'val'],
+ xns : Roo.data
+ }
+ },
+ // -------- Cols
+
+ {
+ xtype : 'TextItem',
+ text : "Columns: ",
+ xns : rooui.Toolbar //Boostrap?
+ },
+
+ {
+ xtype : 'Button',
+ text: '-',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ block().removeColumn();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ {
+ xtype : 'Button',
+ text: '+',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ block().addColumn();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ // -------- ROWS
+ {
+ xtype : 'TextItem',
+ text : "Rows: ",
+ xns : rooui.Toolbar //Boostrap?
+ },
+
+ {
+ xtype : 'Button',
+ text: '-',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ block().removeRow();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ {
+ xtype : 'Button',
+ text: '+',
+ listeners : {
+ click : function (_self, e)
+ {
+ block().addRow();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ // -------- ROWS
+ {
+ xtype : 'Button',
+ text: 'Reset Column Widths',
+ listeners : {
+
+ click : function (_self, e)
+ {
+ block().resetWidths();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ }
+
+
+
+ ];
+
+ },
+
+
+ /**
+ * create a DomHelper friendly object - for use with
+ * Roo.DomHelper.markup / overwrite / etc..
+ * ?? should it be called with option to hide all editing features?
+ */
+ toObject : function()
+ {
+
+ var ret = {
+ tag : 'table',
+ contenteditable : 'false', // this stops cell selection from picking the table.
+ 'data-block' : 'Table',
+ style : {
+ width: this.width,
+ border : 'solid 1px #000', // ??? hard coded?
+ 'border-collapse' : 'collapse'
+ },
+ cn : [
+ { tag : 'tbody' , cn : [] }
+ ]
+ };
+
+ // do we have a head = not really
+ var ncols = 0;
+ Roo.each(this.rows, function( row ) {
+ var tr = {
+ tag: 'tr',
+ style : {
+ margin: '6px',
+ border : 'solid 1px #000',
+ textAlign : 'left'
+ },
+ cn : [ ]
+ };
+
+ ret.cn[0].cn.push(tr);
+ // does the row have any properties? ?? height?
+ var nc = 0;
+ Roo.each(row, function( cell ) {
+
+ var td = {
+ tag : 'td',
+ contenteditable : 'true',
+ 'data-block' : 'Td',
+ html : cell.html,
+ style : cell.style
+ };
+ if (cell.colspan > 1) {
+ td.colspan = cell.colspan ;
+ nc += cell.colspan;
+ } else {
+ nc++;
+ }
+ if (cell.rowspan > 1) {
+ td.rowspan = cell.rowspan ;
+ }
+
+
+ // widths ?
+ tr.cn.push(td);
+
+
+ }, this);
+ ncols = Math.max(nc, ncols);
+
+
+ }, this);
+ // add the header row..
+
+ ncols++;
+
+
+ return ret;
+
+ },
+
+ readElement : function(node)
+ {
+ node = node ? node : this.node ;
+ this.width = this.getVal(node, true, 'style', 'width') || '100%';
+
+ this.rows = [];
+ this.no_row = 0;
+ var trs = Array.from(node.rows);
+ trs.forEach(function(tr) {
+ var row = [];
+ this.rows.push(row);
+
+ this.no_row++;
+ var no_column = 0;
+ Array.from(tr.cells).forEach(function(td) {
+
+ var add = {
+ colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan')*1 : 1,
+ rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan')*1 : 1,
+ style : td.hasAttribute('style') ? td.getAttribute('style') : '',
+ html : td.innerHTML
+ };
+ no_column += add.colspan;
+
+
+ row.push(add);
+
+
+ },this);
+ this.no_col = Math.max(this.no_col, no_column);
+
+
+ },this);
+
+
+ },
+ normalizeRows: function()
+ {
+ var ret= [];
+ var rid = -1;
+ this.rows.forEach(function(row) {
+ rid++;
+ ret[rid] = [];
+ row = this.normalizeRow(row);
+ var cid = 0;
+ row.forEach(function(c) {
+ while (typeof(ret[rid][cid]) != 'undefined') {
+ cid++;
+ }
+ if (typeof(ret[rid]) == 'undefined') {
+ ret[rid] = [];
+ }
+ ret[rid][cid] = c;
+ c.row = rid;
+ c.col = cid;
+ if (c.rowspan < 2) {
+ return;
+ }
+
+ for(var i = 1 ;i < c.rowspan; i++) {
+ if (typeof(ret[rid+i]) == 'undefined') {
+ ret[rid+i] = [];
+ }
+ ret[rid+i][cid] = c;
+ }
+ });
+ }, this);
+ return ret;
+
+ },
+
+ normalizeRow: function(row)
+ {
+ var ret= [];
+ row.forEach(function(c) {
+ if (c.colspan < 2) {
+ ret.push(c);
+ return;
+ }
+ for(var i =0 ;i < c.colspan; i++) {
+ ret.push(c);
+ }
+ });
+ return ret;
+
+ },
+
+ deleteColumn : function(sel)
+ {
+ if (!sel || sel.type != 'col') {
+ return;
+ }
+ if (this.no_col < 2) {
+ return;
+ }
+
+ this.rows.forEach(function(row) {
+ var cols = this.normalizeRow(row);
+ var col = cols[sel.col];
+ if (col.colspan > 1) {
+ col.colspan --;
+ } else {
+ row.remove(col);
+ }
+
+ }, this);
+ this.no_col--;
+
+ },
+ removeColumn : function()
+ {
+ this.deleteColumn({
+ type: 'col',
+ col : this.no_col-1
+ });
+ this.updateElement();
+ },
+
+
+ addColumn : function()
+ {
+
+ this.rows.forEach(function(row) {
+ row.push(this.emptyCell());
+
+ }, this);
+ this.updateElement();
+ },
+
+ deleteRow : function(sel)
+ {
+ if (!sel || sel.type != 'row') {
+ return;
+ }
+
+ if (this.no_row < 2) {
+ return;
+ }
+
+ var rows = this.normalizeRows();
+
+
+ rows[sel.row].forEach(function(col) {
+ if (col.rowspan > 1) {
+ col.rowspan--;
+ } else {
+ col.remove = 1; // flage it as removed.
+ }
+
+ }, this);
+ var newrows = [];
+ this.rows.forEach(function(row) {
+ newrow = [];
+ row.forEach(function(c) {
+ if (typeof(c.remove) == 'undefined') {
+ newrow.push(c);
+ }
+
+ });
+ if (newrow.length > 0) {
+ newrows.push(row);
+ }
+ });
+ this.rows = newrows;
+
+
+
+ this.no_row--;
+ this.updateElement();
+
+ },
+ removeRow : function()
+ {
+ this.deleteRow({
+ type: 'row',
+ row : this.no_row-1
+ });
+
+ },
+
+
+ addRow : function()
+ {
+
+ var row = [];
+ for (var i = 0; i < this.no_col; i++ ) {
+
+ row.push(this.emptyCell());
+
+ }
+ this.rows.push(row);
+ this.updateElement();
+
+ },
+
+ // the default cell object... at present...
+ emptyCell : function() {
+ return (new Roo.htmleditor.BlockTd({})).toObject();
+
+
+ },
+
+ removeNode : function()
+ {
+ return this.node;
+ },
+
+
+
+ resetWidths : function()
+ {
+ Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
+ var nn = Roo.htmleditor.Block.factory(n);
+ nn.width = '';
+ nn.updateElement(n);
+ });
+ }
+
+
+
+
+})
+
+/**
+ *
+ * editing a TD?
+ *
+ * since selections really work on the table cell, then editing really should work from there
+ *
+ * The original plan was to support merging etc... - but that may not be needed yet..
+ *
+ * So this simple version will support:
+ * add/remove cols
+ * adjust the width +/-
+ * reset the width...
+ *
+ *
+ */
+
+
+
+
+/**
+ * @class Roo.htmleditor.BlockTable
+ * Block that manages a table
+ *
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.BlockTd = function(cfg)
+{
+ if (cfg.node) {
+ this.readElement(cfg.node);
+ this.updateElement(cfg.node);
+ }
+ Roo.apply(this, cfg);
+
+
+
+}
+Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
+
+ node : false,
+
+ width: '',
+ textAlign : 'left',
+ valign : 'top',
+
+ colspan : 1,
+ rowspan : 1,
+
+
+ // used by context menu
+ friendly_name : 'Table Cell',
+ deleteTitle : false, // use our customer delete
+
+ // context menu is drawn once..
+
+ contextMenu : function(toolbar)
+ {
+
+ var cell = function() {
+ return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
+ };
+
+ var table = function() {
+ return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
+ };
+
+ var lr = false;
+ var saveSel = function()
+ {
+ lr = toolbar.editorcore.getSelection().getRangeAt(0);
+ }
+ var restoreSel = function()
+ {
+ if (lr) {
+ (function() {
+ toolbar.editorcore.focus();
+ var cr = toolbar.editorcore.getSelection();
+ cr.removeAllRanges();
+ cr.addRange(lr);
+ toolbar.editorcore.onEditorEvent();
+ }).defer(10, this);
+
+
+ }
+ }
+
+ var rooui = typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
+
+ var syncValue = toolbar.editorcore.syncValue;
+
+ var fields = {};
+
+ return [
+ {
+ xtype : 'Button',
+ text : 'Edit Table',
+ listeners : {
+ click : function() {
+ var t = toolbar.tb.selectedNode.closest('table');
+ toolbar.editorcore.selectNode(t);
+ toolbar.editorcore.onEditorEvent();
+ }
+ }
+
+ },
+
+
+
+ {
+ xtype : 'TextItem',
+ text : "Column Width: ",
+ xns : rooui.Toolbar
+
+ },
+ {
+ xtype : 'Button',
+ text: '-',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ cell().shrinkColumn();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ {
+ xtype : 'Button',
+ text: '+',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ cell().growColumn();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+
+ {
+ xtype : 'TextItem',
+ text : "Vertical Align: ",
+ xns : rooui.Toolbar //Boostrap?
+ },
+ {
+ xtype : 'ComboBox',
+ allowBlank : false,
+ displayField : 'val',
+ editable : true,
+ listWidth : 100,
+ triggerAction : 'all',
+ typeAhead : true,
+ valueField : 'val',
+ width : 100,
+ name : 'valign',
+ listeners : {
+ select : function (combo, r, index)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ var b = cell();
+ b.valign = r.get('val');
+ b.updateElement();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.form,
+ store : {
+ xtype : 'SimpleStore',
+ data : [
+ ['top'],
+ ['middle'],
+ ['bottom'] // there are afew more...
+ ],
+ fields : [ 'val'],
+ xns : Roo.data
+ }
+ },
+
+ {
+ xtype : 'TextItem',
+ text : "Merge Cells: ",
+ xns : rooui.Toolbar
+
+ },
+
+
+ {
+ xtype : 'Button',
+ text: 'Right',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ cell().mergeRight();
+ //block().growColumn();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+
+ {
+ xtype : 'Button',
+ text: 'Below',
+ listeners : {
+ click : function (_self, e)
+ {
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ cell().mergeBelow();
+ //block().growColumn();
+ syncValue();
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ {
+ xtype : 'TextItem',
+ text : "| ",
+ xns : rooui.Toolbar
+
+ },
+
+ {
+ xtype : 'Button',
+ text: 'Split',
+ listeners : {
+ click : function (_self, e)
+ {
+ //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ cell().split();
+ syncValue();
+ toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+ toolbar.editorcore.onEditorEvent();
+
+ }
+ },
+ xns : rooui.Toolbar
+ },
+ {
+ xtype : 'Fill',
+ xns : rooui.Toolbar
+
+ },
+
+
+ {
+ xtype : 'Button',
+ text: 'Delete',
+
+ xns : rooui.Toolbar,
+ menu : {
+ xtype : 'Menu',
+ xns : rooui.menu,
+ items : [
+ {
+ xtype : 'Item',
+ html: 'Column',
+ listeners : {
+ click : function (_self, e)
+ {
+ var t = table();
+
+ cell().deleteColumn();
+ syncValue();
+ toolbar.editorcore.selectNode(t.node);
+ toolbar.editorcore.onEditorEvent();
+ }
+ },
+ xns : rooui.menu
+ },
+ {
+ xtype : 'Item',
+ html: 'Row',
+ listeners : {
+ click : function (_self, e)
+ {
+ var t = table();
+ cell().deleteRow();
+ syncValue();
+
+ toolbar.editorcore.selectNode(t.node);
+ toolbar.editorcore.onEditorEvent();
+
+ }
+ },
+ xns : rooui.menu
+ },
+ {
+ xtype : 'Separator',
+ xns : rooui.menu
+ },
+ {
+ xtype : 'Item',
+ html: 'Table',
+ listeners : {
+ click : function (_self, e)
+ {
+ var t = table();
+ var nn = t.node.nextSibling || t.node.previousSibling;
+ t.node.parentNode.removeChild(t.node);
+ if (nn) {
+ toolbar.editorcore.selectNode(nn, true);
+ }
+ toolbar.editorcore.onEditorEvent();
+
+ }
+ },
+ xns : rooui.menu
+ }
+ ]
+ }
+ }
+
+ // align... << fixme
+
+ ];
+
+ },
+
+
+ /**
+ * create a DomHelper friendly object - for use with
+ * Roo.DomHelper.markup / overwrite / etc..
+ * ?? should it be called with option to hide all editing features?
+ */
+ /**
+ * create a DomHelper friendly object - for use with
+ * Roo.DomHelper.markup / overwrite / etc..
+ * ?? should it be called with option to hide all editing features?
+ */
+ toObject : function()
+ {
+
+ var ret = {
+ tag : 'td',
+ contenteditable : 'true', // this stops cell selection from picking the table.
+ 'data-block' : 'Td',
+ valign : this.valign,
+ style : {
+ 'text-align' : this.textAlign,
+ border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
+ 'border-collapse' : 'collapse',
+ padding : '6px', // 8 for desktop / 4 for mobile
+ 'vertical-align': this.valign
+ },
+ html : this.html
+ };
+ if (this.width != '') {
+ ret.width = this.width;
+ ret.style.width = this.width;
+ }
+
+
+ if (this.colspan > 1) {
+ ret.colspan = this.colspan ;
+ }
+ if (this.rowspan > 1) {
+ ret.rowspan = this.rowspan ;
+ }
+
+
+
+ return ret;
+
+ },
+
+ readElement : function(node)
+ {
+ node = node ? node : this.node ;
+ this.width = node.style.width;
+ this.colspan = Math.max(1,1*node.getAttribute('colspan'));
+ this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
+ this.html = node.innerHTML;
+
+
+ },
+
+ // the default cell object... at present...
+ emptyCell : function() {
+ return {
+ colspan : 1,
+ rowspan : 1,
+ textAlign : 'left',
+ html : " " // is this going to be editable now?
+ };
+
+ },
+
+ removeNode : function()
+ {
+ return this.node.closest('table');
+
+ },
+
+ cellData : false,
+
+ colWidths : false,
+
+ toTableArray : function()
+ {
+ var ret = [];
+ var tab = this.node.closest('tr').closest('table');
+ Array.from(tab.rows).forEach(function(r, ri){
+ ret[ri] = [];
+ });
+ var rn = 0;
+ this.colWidths = [];
+ var all_auto = true;
+ Array.from(tab.rows).forEach(function(r, ri){
+
+ var cn = 0;
+ Array.from(r.cells).forEach(function(ce, ci){
+ var c = {
+ cell : ce,
+ row : rn,
+ col: cn,
+ colspan : ce.colSpan,
+ rowspan : ce.rowSpan
+ };
+ if (ce.isEqualNode(this.node)) {
+ this.cellData = c;
+ }
+ // if we have been filled up by a row?
+ if (typeof(ret[rn][cn]) != 'undefined') {
+ while(typeof(ret[rn][cn]) != 'undefined') {
+ cn++;
+ }
+ c.col = cn;
+ }
+
+ if (typeof(this.colWidths[cn]) == 'undefined') {
+ this.colWidths[cn] = ce.style.width;
+ if (this.colWidths[cn] != '') {
+ all_auto = false;
+ }
+ }
+
+
+ if (c.colspan < 2 && c.rowspan < 2 ) {
+ ret[rn][cn] = c;
+ cn++;
+ return;
+ }
+ for(var j = 0; j < c.rowspan; j++) {
+ if (typeof(ret[rn+j]) == 'undefined') {
+ continue; // we have a problem..
+ }
+ ret[rn+j][cn] = c;
+ for(var i = 0; i < c.colspan; i++) {
+ ret[rn+j][cn+i] = c;
+ }
+ }
+
+ cn += c.colspan;
+ }, this);
+ rn++;
+ }, this);
+
+ // initalize widths.?
+ // either all widths or no widths..
+ if (all_auto) {
+ this.colWidths[0] = false; // no widths flag.
+ }
+
+
+ return ret;
+
+ },
+
+
+
+
+ mergeRight: function()
+ {
+
+ // get the contents of the next cell along..
+ var tr = this.node.closest('tr');
+ var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
+ if (i >= tr.childNodes.length - 1) {
+ return; // no cells on right to merge with.
+ }
+ var table = this.toTableArray();
+
+ if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
+ return; // nothing right?
+ }
+ var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
+ // right cell - must be same rowspan and on the same row.
+ if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
+ return; // right hand side is not same rowspan.
+ }
+
+
+
+ this.node.innerHTML += ' ' + rc.cell.innerHTML;
+ tr.removeChild(rc.cell);
+ this.colspan += rc.colspan;
+ this.node.setAttribute('colspan', this.colspan);
+
+ },
+
+
+ mergeBelow : function()
+ {
+ var table = this.toTableArray();
+ if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
+ return; // no row below
+ }
+ if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
+ return; // nothing right?
+ }
+ var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
+
+ if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
+ return; // right hand side is not same rowspan.
+ }
+ this.node.innerHTML = this.node.innerHTML + rc.cell.innerHTML ;
+ rc.cell.parentNode.removeChild(rc.cell);
+ this.rowspan += rc.rowspan;
+ this.node.setAttribute('rowspan', this.rowspan);
+ },
+
+ split: function()
+ {
+ if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
+ return;
+ }
+ var table = this.toTableArray();
+ var cd = this.cellData;
+ this.rowspan = 1;
+ this.colspan = 1;
+
+ for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
+
+
+
+ for(var c = cd.col; c < cd.col + cd.colspan; c++) {
+ if (r == cd.row && c == cd.col) {
+ this.node.removeAttribute('rowspan');
+ this.node.removeAttribute('colspan');
+ continue;
+ }
+
+ var ntd = this.node.cloneNode(); // which col/row should be 0..
+ ntd.removeAttribute('id'); //
+ //ntd.style.width = '';
+ ntd.innerHTML = '';
+ table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1 };
+ }
+
+ }
+ this.redrawAllCells(table);
+
+
+
+ },
+
+
+
+ redrawAllCells: function(table)
+ {
+
+
+ var tab = this.node.closest('tr').closest('table');
+ var ctr = tab.rows[0].parentNode;
+ Array.from(tab.rows).forEach(function(r, ri){
+
+ Array.from(r.cells).forEach(function(ce, ci){
+ ce.parentNode.removeChild(ce);
+ });
+ r.parentNode.removeChild(r);
+ });
+ for(var r = 0 ; r < table.length; r++) {
+ var re = tab.rows[r];
+
+ var re = tab.ownerDocument.createElement('tr');
+ ctr.appendChild(re);
+ for(var c = 0 ; c < table[r].length; c++) {
+ if (table[r][c].cell === false) {
+ continue;
+ }
+
+ re.appendChild(table[r][c].cell);
+
+ table[r][c].cell = false;
+ }
+ }
+
+ },
+ updateWidths : function(table)
+ {
+ for(var r = 0 ; r < table.length; r++) {
+
+ for(var c = 0 ; c < table[r].length; c++) {
+ if (table[r][c].cell === false) {
+ continue;
+ }
+
+ if (this.colWidths[0] != false && table[r][c].colspan < 2) {
+ var el = Roo.htmleditor.Block.factory(table[r][c].cell);
+ el.width = Math.floor(this.colWidths[c]) +'%';
+ el.updateElement(el.node);
+ }
+ table[r][c].cell = false; // done
+ }
+ }
+ },
+ normalizeWidths : function(table)
+ {
+
+ if (this.colWidths[0] === false) {
+ var nw = 100.0 / this.colWidths.length;
+ this.colWidths.forEach(function(w,i) {
+ this.colWidths[i] = nw;
+ },this);
+ return;
+ }
+
+ var t = 0, missing = [];
+
+ this.colWidths.forEach(function(w,i) {
+ //if you mix % and
+ this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
+ var add = this.colWidths[i];
+ if (add > 0) {
+ t+=add;
+ return;
+ }
+ missing.push(i);
+
+
+ },this);
+ var nc = this.colWidths.length;
+ if (missing.length) {
+ var mult = (nc - missing.length) / (1.0 * nc);
+ var t = mult * t;
+ var ew = (100 -t) / (1.0 * missing.length);
+ this.colWidths.forEach(function(w,i) {
+ if (w > 0) {
+ this.colWidths[i] = w * mult;
+ return;
+ }
+
+ this.colWidths[i] = ew;
+ }, this);
+ // have to make up numbers..
+
+ }
+ // now we should have all the widths..
+
+
+ },
+
+ shrinkColumn : function()
+ {
+ var table = this.toTableArray();
+ this.normalizeWidths(table);
+ var col = this.cellData.col;
+ var nw = this.colWidths[col] * 0.8;
+ if (nw < 5) {
+ return;
+ }
+ var otherAdd = (this.colWidths[col] * 0.2) / (this.colWidths.length -1);
+ this.colWidths.forEach(function(w,i) {
+ if (i == col) {
+ this.colWidths[i] = nw;
+ return;
+ }
+ this.colWidths[i] += otherAdd
+ }, this);
+ this.updateWidths(table);
+
+ },
+ growColumn : function()
+ {
+ var table = this.toTableArray();
+ this.normalizeWidths(table);
+ var col = this.cellData.col;
+ var nw = this.colWidths[col] * 1.2;
+ if (nw > 90) {
+ return;
+ }
+ var otherSub = (this.colWidths[col] * 0.2) / (this.colWidths.length -1);
+ this.colWidths.forEach(function(w,i) {
+ if (i == col) {
+ this.colWidths[i] = nw;
+ return;
+ }
+ this.colWidths[i] -= otherSub
+ }, this);
+ this.updateWidths(table);
+
+ },
+ deleteRow : function()
+ {
+ // delete this rows 'tr'
+ // if any of the cells in this row have a rowspan > 1 && row!= this row..
+ // then reduce the rowspan.
+ var table = this.toTableArray();
+ // this.cellData.row;
+ for (var i =0;i< table[this.cellData.row].length ; i++) {
+ var c = table[this.cellData.row][i];
+ if (c.row != this.cellData.row) {
+
+ c.rowspan--;
+ c.cell.setAttribute('rowspan', c.rowspan);
+ continue;
+ }
+ if (c.rowspan > 1) {
+ c.rowspan--;
+ c.cell.setAttribute('rowspan', c.rowspan);
+ }
+ }
+ table.splice(this.cellData.row,1);
+ this.redrawAllCells(table);
+
+ },
+ deleteColumn : function()
+ {
+ var table = this.toTableArray();
+
+ for (var i =0;i< table.length ; i++) {
+ var c = table[i][this.cellData.col];
+ if (c.col != this.cellData.col) {
+ table[i][this.cellData.col].colspan--;
+ } else if (c.colspan > 1) {
+ c.colspan--;
+ c.cell.setAttribute('colspan', c.colspan);
+ }
+ table[i].splice(this.cellData.col,1);
+ }
+
+ this.redrawAllCells(table);
+ }
+
+
+
+
+})
+
+//<script type="text/javascript">
+
+/*
+ * Based Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ * LGPL
+ *
+ */
+
+/**
+ * @class Roo.HtmlEditorCore
+ * @extends Roo.Component
+ * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
+ *
+ * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
+ */
+
+Roo.HtmlEditorCore = function(config){