Mercurial > public > sg101
view media/js/tiny_mce/plugins/table/editor_plugin_src.js @ 133:c515b7401078
Use the new common way to apply markItUp to textareas and to get the smiley and markdown help dialogs for all the remaining apps except for forums and comments.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Fri, 27 Nov 2009 00:21:47 +0000 |
parents | a5b4c5ce0658 |
children | 149c3567fec1 |
line wrap: on
line source
/** * $Id: editor_plugin_src.js 953 2008-11-04 10:16:50Z spocke $ * * @author Moxiecode * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. */ (function() { var each = tinymce.each; tinymce.create('tinymce.plugins.TablePlugin', { init : function(ed, url) { var t = this; t.editor = ed; t.url = url; // Register buttons each([ ['table', 'table.desc', 'mceInsertTable', true], ['delete_table', 'table.del', 'mceTableDelete'], ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'], ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'], ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'], ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'], ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'], ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'], ['row_props', 'table.row_desc', 'mceTableRowProps', true], ['cell_props', 'table.cell_desc', 'mceTableCellProps', true], ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true], ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true] ], function(c) { ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]}); }); if (ed.getParam('inline_styles')) { // Force move of attribs to styles in strict mode ed.onPreProcess.add(function(ed, o) { var dom = ed.dom; each(dom.select('table', o.node), function(n) { var v; if (v = dom.getAttrib(n, 'width')) { dom.setStyle(n, 'width', v); dom.setAttrib(n, 'width'); } if (v = dom.getAttrib(n, 'height')) { dom.setStyle(n, 'height', v); dom.setAttrib(n, 'height'); } }); }); } ed.onInit.add(function() { if (ed && ed.plugins.contextmenu) { ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { var sm, se = ed.selection, el = se.getNode() || ed.getBody(); if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th')) { m.removeAll(); if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) { m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true}); m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'}); m.addSeparator(); } if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) { m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true}); m.addSeparator(); } m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true, value : {action : 'insert'}}); m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable', ui : true}); m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete', ui : true}); m.addSeparator(); // Cell menu sm = m.addMenu({title : 'table.cell'}); sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps', ui : true}); sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells', ui : true}); sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells', ui : true}); // Row menu sm = m.addMenu({title : 'table.row'}); sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps', ui : true}); sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'}); sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'}); sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'}); sm.addSeparator(); sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'}); sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'}); sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}); sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}); // Column menu sm = m.addMenu({title : 'table.col'}); sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'}); sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'}); sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'}); } else m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true}); }); } }); // Add undo level when new rows are created using the tab key ed.onKeyDown.add(function(ed, e) { if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE')) { if (!tinymce.isGecko && !tinymce.isOpera) { tinyMCE.execInstanceCommand(ed.editorId, "mceTableMoveToNextRow", true); return tinymce.dom.Event.cancel(e); } ed.undoManager.add(); } }); // Select whole table is a table border is clicked if (!tinymce.isIE) { if (ed.getParam('table_selection', true)) { ed.onClick.add(function(ed, e) { e = e.target; if (e.nodeName === 'TABLE') ed.selection.select(e); }); } } ed.onNodeChange.add(function(ed, cm, n) { var p = ed.dom.getParent(n, 'td,th,caption'); cm.setActive('table', n.nodeName === 'TABLE' || !!p); if (p && p.nodeName === 'CAPTION') p = null; cm.setDisabled('delete_table', !p); cm.setDisabled('delete_col', !p); cm.setDisabled('delete_table', !p); cm.setDisabled('delete_row', !p); cm.setDisabled('col_after', !p); cm.setDisabled('col_before', !p); cm.setDisabled('row_after', !p); cm.setDisabled('row_before', !p); cm.setDisabled('row_props', !p); cm.setDisabled('cell_props', !p); cm.setDisabled('split_cells', !p || (parseInt(ed.dom.getAttrib(p, 'colspan', '1')) < 2 && parseInt(ed.dom.getAttrib(p, 'rowspan', '1')) < 2)); cm.setDisabled('merge_cells', !p); }); // Padd empty table cells if (!tinymce.isIE) { ed.onBeforeSetContent.add(function(ed, o) { if (o.initial) o.content = o.content.replace(/<(td|th)([^>]+|)>\s*<\/(td|th)>/g, tinymce.isOpera ? '<$1$2> </$1>' : '<$1$2><br mce_bogus="1" /></$1>'); }); } }, execCommand : function(cmd, ui, val) { var ed = this.editor, b; // Is table command switch (cmd) { case "mceTableMoveToNextRow": case "mceInsertTable": case "mceTableRowProps": case "mceTableCellProps": case "mceTableSplitCells": case "mceTableMergeCells": case "mceTableInsertRowBefore": case "mceTableInsertRowAfter": case "mceTableDeleteRow": case "mceTableInsertColBefore": case "mceTableInsertColAfter": case "mceTableDeleteCol": case "mceTableCutRow": case "mceTableCopyRow": case "mceTablePasteRowBefore": case "mceTablePasteRowAfter": case "mceTableDelete": ed.execCommand('mceBeginUndoLevel'); this._doExecCommand(cmd, ui, val); ed.execCommand('mceEndUndoLevel'); return true; } // Pass to next handler in chain return false; }, getInfo : function() { return { longname : 'Tables', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table', version : tinymce.majorVersion + "." + tinymce.minorVersion }; }, // Private plugin internal methods /** * Executes the table commands. */ _doExecCommand : function(command, user_interface, value) { var inst = this.editor, ed = inst, url = this.url; var focusElm = inst.selection.getNode(); var trElm = inst.dom.getParent(focusElm, "tr"); var tdElm = inst.dom.getParent(focusElm, "td,th"); var tableElm = inst.dom.getParent(focusElm, "table"); var doc = inst.contentWindow.document; var tableBorder = tableElm ? tableElm.getAttribute("border") : ""; // Get first TD if no TD found if (trElm && tdElm == null) tdElm = trElm.cells[0]; function inArray(ar, v) { for (var i=0; i<ar.length; i++) { // Is array if (ar[i].length > 0 && inArray(ar[i], v)) return true; // Found value if (ar[i] == v) return true; } return false; } function select(dx, dy) { var td; grid = getTableGrid(tableElm); dx = dx || 0; dy = dy || 0; dx = Math.max(cpos.cellindex + dx, 0); dy = Math.max(cpos.rowindex + dy, 0); // Recalculate grid and select inst.execCommand('mceRepaint'); td = getCell(grid, dy, dx); if (td) { inst.selection.select(td.firstChild || td); inst.selection.collapse(1); } }; function makeTD() { var newTD = doc.createElement("td"); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; } function getColRowSpan(td) { var colspan = inst.dom.getAttrib(td, "colspan"); var rowspan = inst.dom.getAttrib(td, "rowspan"); colspan = colspan == "" ? 1 : parseInt(colspan); rowspan = rowspan == "" ? 1 : parseInt(rowspan); return {colspan : colspan, rowspan : rowspan}; } function getCellPos(grid, td) { var x, y; for (y=0; y<grid.length; y++) { for (x=0; x<grid[y].length; x++) { if (grid[y][x] == td) return {cellindex : x, rowindex : y}; } } return null; } function getCell(grid, row, col) { if (grid[row] && grid[row][col]) return grid[row][col]; return null; } function getNextCell(table, cell) { var cells = [], x = 0, i, j, cell, nextCell; for (i = 0; i < table.rows.length; i++) for (j = 0; j < table.rows[i].cells.length; j++, x++) cells[x] = table.rows[i].cells[j]; for (i = 0; i < cells.length; i++) if (cells[i] == cell) if (nextCell = cells[i+1]) return nextCell; } function getTableGrid(table) { var grid = [], rows = table.rows, x, y, td, sd, xstart, x2, y2; for (y=0; y<rows.length; y++) { for (x=0; x<rows[y].cells.length; x++) { td = rows[y].cells[x]; sd = getColRowSpan(td); // All ready filled for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ; // Fill box for (y2=y; y2<y+sd['rowspan']; y2++) { if (!grid[y2]) grid[y2] = []; for (x2=xstart; x2<xstart+sd['colspan']; x2++) grid[y2][x2] = td; } } } return grid; } function trimRow(table, tr, td, new_tr) { var grid = getTableGrid(table), cpos = getCellPos(grid, td); var cells, lastElm; // Time to crop away some if (new_tr.cells.length != tr.childNodes.length) { cells = tr.childNodes; lastElm = null; for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) { var remove = true; var sd = getColRowSpan(td); // Remove due to rowspan if (inArray(cells, td)) { new_tr.childNodes[x]._delete = true; } else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan for (var i=x; i<x+td.colSpan; i++) new_tr.childNodes[i]._delete = true; } if ((lastElm == null || td != lastElm) && sd.rowspan > 1) td.rowSpan = sd.rowspan + 1; lastElm = td; } deleteMarked(tableElm); } } function prevElm(node, name) { while ((node = node.previousSibling) != null) { if (node.nodeName == name) return node; } return null; } function nextElm(node, names) { var namesAr = names.split(','); while ((node = node.nextSibling) != null) { for (var i=0; i<namesAr.length; i++) { if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() ) return node; } } return null; } function deleteMarked(tbl) { if (tbl.rows == 0) return; var tr = tbl.rows[0]; do { var next = nextElm(tr, "TR"); // Delete row if (tr._delete) { tr.parentNode.removeChild(tr); continue; } // Delete cells var td = tr.cells[0]; if (td.cells > 1) { do { var nexttd = nextElm(td, "TD,TH"); if (td._delete) td.parentNode.removeChild(td); } while ((td = nexttd) != null); } } while ((tr = next) != null); } function addRows(td_elm, tr_elm, rowspan) { // Add rows td_elm.rowSpan = 1; var trNext = nextElm(tr_elm, "TR"); for (var i=1; i<rowspan && trNext; i++) { var newTD = doc.createElement("td"); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; if (tinymce.isIE) trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex)); else trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]); trNext = nextElm(trNext, "TR"); } } function copyRow(doc, table, tr) { var grid = getTableGrid(table); var newTR = tr.cloneNode(false); var cpos = getCellPos(grid, tr.cells[0]); var lastCell = null; var tableBorder = inst.dom.getAttrib(table, "border"); var tdElm = null; for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) { var newTD = null; if (lastCell != tdElm) { for (var i=0; i<tr.cells.length; i++) { if (tdElm == tr.cells[i]) { newTD = tdElm.cloneNode(true); break; } } } if (newTD == null) { newTD = doc.createElement("td"); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; } // Reset col/row span newTD.colSpan = 1; newTD.rowSpan = 1; newTR.appendChild(newTD); lastCell = tdElm; } return newTR; } // ---- Commands ----- // Handle commands switch (command) { case "mceTableMoveToNextRow": var nextCell = getNextCell(tableElm, tdElm); if (!nextCell) { inst.execCommand("mceTableInsertRowAfter", tdElm); nextCell = getNextCell(tableElm, tdElm); } inst.selection.select(nextCell); inst.selection.collapse(true); return true; case "mceTableRowProps": if (trElm == null) return true; if (user_interface) { inst.windowManager.open({ url : url + '/row.htm', width : 400 + parseInt(inst.getLang('table.rowprops_delta_width', 0)), height : 295 + parseInt(inst.getLang('table.rowprops_delta_height', 0)), inline : 1 }, { plugin_url : url }); } return true; case "mceTableCellProps": if (tdElm == null) return true; if (user_interface) { inst.windowManager.open({ url : url + '/cell.htm', width : 400 + parseInt(inst.getLang('table.cellprops_delta_width', 0)), height : 295 + parseInt(inst.getLang('table.cellprops_delta_height', 0)), inline : 1 }, { plugin_url : url }); } return true; case "mceInsertTable": if (user_interface) { inst.windowManager.open({ url : url + '/table.htm', width : 400 + parseInt(inst.getLang('table.table_delta_width', 0)), height : 320 + parseInt(inst.getLang('table.table_delta_height', 0)), inline : 1 }, { plugin_url : url, action : value ? value.action : 0 }); } return true; case "mceTableDelete": var table = inst.dom.getParent(inst.selection.getNode(), "table"); if (table) { table.parentNode.removeChild(table); inst.execCommand('mceRepaint'); } return true; case "mceTableSplitCells": case "mceTableMergeCells": case "mceTableInsertRowBefore": case "mceTableInsertRowAfter": case "mceTableDeleteRow": case "mceTableInsertColBefore": case "mceTableInsertColAfter": case "mceTableDeleteCol": case "mceTableCutRow": case "mceTableCopyRow": case "mceTablePasteRowBefore": case "mceTablePasteRowAfter": // No table just return (invalid command) if (!tableElm) return true; // Table has a tbody use that reference // Changed logic by ApTest 2005.07.12 (www.aptest.com) // Now lookk at the focused element and take its parentNode. That will be a tbody or a table. if (trElm && tableElm != trElm.parentNode) tableElm = trElm.parentNode; if (tableElm && trElm) { switch (command) { case "mceTableCutRow": if (!trElm || !tdElm) return true; inst.tableRowClipboard = copyRow(doc, tableElm, trElm); inst.execCommand("mceTableDeleteRow"); break; case "mceTableCopyRow": if (!trElm || !tdElm) return true; inst.tableRowClipboard = copyRow(doc, tableElm, trElm); break; case "mceTablePasteRowBefore": if (!trElm || !tdElm) return true; var newTR = inst.tableRowClipboard.cloneNode(true); var prevTR = prevElm(trElm, "TR"); if (prevTR != null) trimRow(tableElm, prevTR, prevTR.cells[0], newTR); trElm.parentNode.insertBefore(newTR, trElm); break; case "mceTablePasteRowAfter": if (!trElm || !tdElm) return true; var nextTR = nextElm(trElm, "TR"); var newTR = inst.tableRowClipboard.cloneNode(true); trimRow(tableElm, trElm, tdElm, newTR); if (nextTR == null) trElm.parentNode.appendChild(newTR); else nextTR.parentNode.insertBefore(newTR, nextTR); break; case "mceTableInsertRowBefore": if (!trElm || !tdElm) return true; var grid = getTableGrid(tableElm); var cpos = getCellPos(grid, tdElm); var newTR = doc.createElement("tr"); var lastTDElm = null; cpos.rowindex--; if (cpos.rowindex < 0) cpos.rowindex = 0; // Create cells for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) { if (tdElm != lastTDElm) { var sd = getColRowSpan(tdElm); if (sd['rowspan'] == 1) { var newTD = doc.createElement("td"); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; newTD.colSpan = tdElm.colSpan; newTR.appendChild(newTD); } else tdElm.rowSpan = sd['rowspan'] + 1; lastTDElm = tdElm; } } trElm.parentNode.insertBefore(newTR, trElm); select(0, 1); break; case "mceTableInsertRowAfter": if (!trElm || !tdElm) return true; var grid = getTableGrid(tableElm); var cpos = getCellPos(grid, tdElm); var newTR = doc.createElement("tr"); var lastTDElm = null; // Create cells for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) { if (tdElm != lastTDElm) { var sd = getColRowSpan(tdElm); if (sd['rowspan'] == 1) { var newTD = doc.createElement("td"); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; newTD.colSpan = tdElm.colSpan; newTR.appendChild(newTD); } else tdElm.rowSpan = sd['rowspan'] + 1; lastTDElm = tdElm; } } if (newTR.hasChildNodes()) { var nextTR = nextElm(trElm, "TR"); if (nextTR) nextTR.parentNode.insertBefore(newTR, nextTR); else tableElm.appendChild(newTR); } select(0, 1); break; case "mceTableDeleteRow": if (!trElm || !tdElm) return true; var grid = getTableGrid(tableElm); var cpos = getCellPos(grid, tdElm); // Only one row, remove whole table if (grid.length == 1 && tableElm.nodeName == 'TBODY') { inst.dom.remove(inst.dom.getParent(tableElm, "table")); return true; } // Move down row spanned cells var cells = trElm.cells; var nextTR = nextElm(trElm, "TR"); for (var x=0; x<cells.length; x++) { if (cells[x].rowSpan > 1) { var newTD = cells[x].cloneNode(true); var sd = getColRowSpan(cells[x]); newTD.rowSpan = sd.rowspan - 1; var nextTD = nextTR.cells[x]; if (nextTD == null) nextTR.appendChild(newTD); else nextTR.insertBefore(newTD, nextTD); } } // Delete cells var lastTDElm = null; for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) { if (tdElm != lastTDElm) { var sd = getColRowSpan(tdElm); if (sd.rowspan > 1) { tdElm.rowSpan = sd.rowspan - 1; } else { trElm = tdElm.parentNode; if (trElm.parentNode) trElm._delete = true; } lastTDElm = tdElm; } } deleteMarked(tableElm); select(0, -1); break; case "mceTableInsertColBefore": if (!trElm || !tdElm) return true; var grid = getTableGrid(inst.dom.getParent(tableElm, "table")); var cpos = getCellPos(grid, tdElm); var lastTDElm = null; for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) { if (tdElm != lastTDElm) { var sd = getColRowSpan(tdElm); if (sd['colspan'] == 1) { var newTD = doc.createElement(tdElm.nodeName); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; newTD.rowSpan = tdElm.rowSpan; tdElm.parentNode.insertBefore(newTD, tdElm); } else tdElm.colSpan++; lastTDElm = tdElm; } } select(); break; case "mceTableInsertColAfter": if (!trElm || !tdElm) return true; var grid = getTableGrid(inst.dom.getParent(tableElm, "table")); var cpos = getCellPos(grid, tdElm); var lastTDElm = null; for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) { if (tdElm != lastTDElm) { var sd = getColRowSpan(tdElm); if (sd['colspan'] == 1) { var newTD = doc.createElement(tdElm.nodeName); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; newTD.rowSpan = tdElm.rowSpan; var nextTD = nextElm(tdElm, "TD,TH"); if (nextTD == null) tdElm.parentNode.appendChild(newTD); else nextTD.parentNode.insertBefore(newTD, nextTD); } else tdElm.colSpan++; lastTDElm = tdElm; } } select(1); break; case "mceTableDeleteCol": if (!trElm || !tdElm) return true; var grid = getTableGrid(tableElm); var cpos = getCellPos(grid, tdElm); var lastTDElm = null; // Only one col, remove whole table if ((grid.length > 1 && grid[0].length <= 1) && tableElm.nodeName == 'TBODY') { inst.dom.remove(inst.dom.getParent(tableElm, "table")); return true; } // Delete cells for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) { if (tdElm != lastTDElm) { var sd = getColRowSpan(tdElm); if (sd['colspan'] > 1) tdElm.colSpan = sd['colspan'] - 1; else { if (tdElm.parentNode) tdElm.parentNode.removeChild(tdElm); } lastTDElm = tdElm; } } select(-1); break; case "mceTableSplitCells": if (!trElm || !tdElm) return true; var spandata = getColRowSpan(tdElm); var colspan = spandata["colspan"]; var rowspan = spandata["rowspan"]; // Needs splitting if (colspan > 1 || rowspan > 1) { // Generate cols tdElm.colSpan = 1; for (var i=1; i<colspan; i++) { var newTD = doc.createElement("td"); if (!tinymce.isIE) newTD.innerHTML = '<br mce_bogus="1"/>'; trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH")); if (rowspan > 1) addRows(newTD, trElm, rowspan); } addRows(tdElm, trElm, rowspan); } // Apply visual aids tableElm = inst.dom.getParent(inst.selection.getNode(), "table"); break; case "mceTableMergeCells": var rows = []; var sel = inst.selection.getSel(); var grid = getTableGrid(tableElm); if (tinymce.isIE || sel.rangeCount == 1) { if (user_interface) { // Setup template var sp = getColRowSpan(tdElm); inst.windowManager.open({ url : url + '/merge_cells.htm', width : 240 + parseInt(inst.getLang('table.merge_cells_delta_width', 0)), height : 110 + parseInt(inst.getLang('table.merge_cells_delta_height', 0)), inline : 1 }, { action : "update", numcols : sp.colspan, numrows : sp.rowspan, plugin_url : url }); return true; } else { var numRows = parseInt(value['numrows']); var numCols = parseInt(value['numcols']); var cpos = getCellPos(grid, tdElm); if (("" + numRows) == "NaN") numRows = 1; if (("" + numCols) == "NaN") numCols = 1; // Get rows and cells var tRows = tableElm.rows; for (var y=cpos.rowindex; y<grid.length; y++) { var rowCells = []; for (var x=cpos.cellindex; x<grid[y].length; x++) { var td = getCell(grid, y, x); if (td && !inArray(rows, td) && !inArray(rowCells, td)) { var cp = getCellPos(grid, td); // Within range if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows) rowCells[rowCells.length] = td; } } if (rowCells.length > 0) rows[rows.length] = rowCells; var td = getCell(grid, cpos.rowindex, cpos.cellindex); each(ed.dom.select('br', td), function(e, i) { if (i > 0 && ed.dom.getAttrib('mce_bogus')) ed.dom.remove(e); }); } //return true; } } else { var cells = []; var sel = inst.selection.getSel(); var lastTR = null; var curRow = null; var x1 = -1, y1 = -1, x2, y2; // Only one cell selected, whats the point? if (sel.rangeCount < 2) return true; // Get all selected cells for (var i=0; i<sel.rangeCount; i++) { var rng = sel.getRangeAt(i); var tdElm = rng.startContainer.childNodes[rng.startOffset]; if (!tdElm) break; if (tdElm.nodeName == "TD" || tdElm.nodeName == "TH") cells[cells.length] = tdElm; } // Get rows and cells var tRows = tableElm.rows; for (var y=0; y<tRows.length; y++) { var rowCells = []; for (var x=0; x<tRows[y].cells.length; x++) { var td = tRows[y].cells[x]; for (var i=0; i<cells.length; i++) { if (td == cells[i]) { rowCells[rowCells.length] = td; } } } if (rowCells.length > 0) rows[rows.length] = rowCells; } // Find selected cells in grid and box var curRow = []; var lastTR = null; for (var y=0; y<grid.length; y++) { for (var x=0; x<grid[y].length; x++) { grid[y][x]._selected = false; for (var i=0; i<cells.length; i++) { if (grid[y][x] == cells[i]) { // Get start pos if (x1 == -1) { x1 = x; y1 = y; } // Get end pos x2 = x; y2 = y; grid[y][x]._selected = true; } } } } // Is there gaps, if so deny for (var y=y1; y<=y2; y++) { for (var x=x1; x<=x2; x++) { if (!grid[y][x]._selected) { alert("Invalid selection for merge."); return true; } } } } // Validate selection and get total rowspan and colspan var rowSpan = 1, colSpan = 1; // Validate horizontal and get total colspan var lastRowSpan = -1; for (var y=0; y<rows.length; y++) { var rowColSpan = 0; for (var x=0; x<rows[y].length; x++) { var sd = getColRowSpan(rows[y][x]); rowColSpan += sd['colspan']; if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) { alert("Invalid selection for merge."); return true; } lastRowSpan = sd['rowspan']; } if (rowColSpan > colSpan) colSpan = rowColSpan; lastRowSpan = -1; } // Validate vertical and get total rowspan var lastColSpan = -1; for (var x=0; x<rows[0].length; x++) { var colRowSpan = 0; for (var y=0; y<rows.length; y++) { var sd = getColRowSpan(rows[y][x]); colRowSpan += sd['rowspan']; if (lastColSpan != -1 && sd['colspan'] != lastColSpan) { alert("Invalid selection for merge."); return true; } lastColSpan = sd['colspan']; } if (colRowSpan > rowSpan) rowSpan = colRowSpan; lastColSpan = -1; } // Setup td tdElm = rows[0][0]; tdElm.rowSpan = rowSpan; tdElm.colSpan = colSpan; // Merge cells for (var y=0; y<rows.length; y++) { for (var x=0; x<rows[y].length; x++) { var html = rows[y][x].innerHTML; var chk = html.replace(/[ \t\r\n]/g, ""); if (chk != "<br/>" && chk != "<br>" && chk != '<br mce_bogus="1"/>' && (x+y > 0)) tdElm.innerHTML += html; // Not current cell if (rows[y][x] != tdElm && !rows[y][x]._deleted) { var cpos = getCellPos(grid, rows[y][x]); var tr = rows[y][x].parentNode; tr.removeChild(rows[y][x]); rows[y][x]._deleted = true; // Empty TR, remove it if (!tr.hasChildNodes()) { tr.parentNode.removeChild(tr); var lastCell = null; for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) { if (cellElm != lastCell && cellElm.rowSpan > 1) cellElm.rowSpan--; lastCell = cellElm; } if (tdElm.rowSpan > 1) tdElm.rowSpan--; } } } } // Remove all but one bogus br each(ed.dom.select('br', tdElm), function(e, i) { if (i > 0 && ed.dom.getAttrib(e, 'mce_bogus')) ed.dom.remove(e); }); break; } tableElm = inst.dom.getParent(inst.selection.getNode(), "table"); inst.addVisual(tableElm); inst.nodeChanged(); } return true; } // Pass to next handler in chain return false; } }); // Register plugin tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin); })();