home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Plugins / tinymce-advanced / mce / table / editor_plugin.js < prev    next >
Encoding:
JavaScript  |  2008-02-20  |  31.2 KB  |  1,074 lines

  1. /**
  2.  * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
  3.  *
  4.  * @author Moxiecode
  5.  * @copyright Copyright ⌐ 2004-2007, Moxiecode Systems AB, All rights reserved.
  6.  */
  7.  
  8. /* Import plugin specific language pack */
  9. tinyMCE.importPluginLanguagePack('table');
  10.  
  11. var TinyMCE_TablePlugin = {
  12.     getInfo : function() {
  13.         return {
  14.             longname : 'Tables',
  15.             author : 'Moxiecode Systems AB',
  16.             authorurl : 'http://tinymce.moxiecode.com',
  17.             infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',
  18.             version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
  19.         };
  20.     },
  21.  
  22.     initInstance : function(inst) {
  23.         if (tinyMCE.isGecko) {
  24.             var doc = inst.getDoc();
  25.             tinyMCE.addEvent(doc, "mouseup", TinyMCE_TablePlugin._mouseDownHandler);
  26.         }
  27.  
  28.         inst.tableRowClipboard = null;
  29.     },
  30.  
  31.     /**
  32.      * Returns the HTML contents of the table control.
  33.      */
  34.     getControlHTML : function(control_name) {
  35.         var controls = new Array(
  36.             ['table', 'table.gif', 'lang_table_desc', 'mceInsertTable', true],
  37.             ['delete_table', 'table_delete.gif', 'lang_table_del', 'mceTableDelete'],
  38.             ['delete_col', 'table_delete_col.gif', 'lang_table_delete_col_desc', 'mceTableDeleteCol'],
  39.             ['delete_row', 'table_delete_row.gif', 'lang_table_delete_row_desc', 'mceTableDeleteRow'],
  40.             ['col_after', 'table_insert_col_after.gif', 'lang_table_col_after_desc', 'mceTableInsertColAfter'],
  41.             ['col_before', 'table_insert_col_before.gif', 'lang_table_col_before_desc', 'mceTableInsertColBefore'],
  42.             ['row_after', 'table_insert_row_after.gif', 'lang_table_row_after_desc', 'mceTableInsertRowAfter'],
  43.             ['row_before', 'table_insert_row_before.gif', 'lang_table_row_before_desc', 'mceTableInsertRowBefore'],
  44.             ['row_props', 'table_row_props.gif', 'lang_table_row_desc', 'mceTableRowProps', true],
  45.             ['cell_props', 'table_cell_props.gif', 'lang_table_cell_desc', 'mceTableCellProps', true],
  46.             ['split_cells', 'table_split_cells.gif', 'lang_table_split_cells_desc', 'mceTableSplitCells', true],
  47.             ['merge_cells', 'table_merge_cells.gif', 'lang_table_merge_cells_desc', 'mceTableMergeCells', true]);
  48.  
  49.         // Render table control
  50.         for (var i=0; i<controls.length; i++) {
  51.             var but = controls[i];
  52.             var cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + but[3] + '\', ' + (but.length > 4 ? but[4] : false) + (but.length > 5 ? ', \'' + but[5] + '\'' : '') + ');return false;';
  53.  
  54.             if (but[0] == control_name)
  55.                 return tinyMCE.getButtonHTML(control_name, but[2], '{$pluginurl}/images/'+ but[1], but[3], (but.length > 4 ? but[4] : false));
  56.         }
  57.  
  58.         // Special tablecontrols
  59.         if (control_name == "tablecontrols") {
  60.             var html = "";
  61.  
  62.             html += tinyMCE.getControlHTML("table");
  63.             html += tinyMCE.getControlHTML("separator");
  64.             html += tinyMCE.getControlHTML("row_props");
  65.             html += tinyMCE.getControlHTML("cell_props");
  66.             html += tinyMCE.getControlHTML("separator");
  67.             html += tinyMCE.getControlHTML("row_before");
  68.             html += tinyMCE.getControlHTML("row_after");
  69.             html += tinyMCE.getControlHTML("delete_row");
  70.             html += tinyMCE.getControlHTML("separator");
  71.             html += tinyMCE.getControlHTML("col_before");
  72.             html += tinyMCE.getControlHTML("col_after");
  73.             html += tinyMCE.getControlHTML("delete_col");
  74.             html += tinyMCE.getControlHTML("separator");
  75.             html += tinyMCE.getControlHTML("split_cells");
  76.             html += tinyMCE.getControlHTML("merge_cells");
  77.  
  78.             return html;
  79.         }
  80.  
  81.         return "";
  82.     },
  83.  
  84.     /**
  85.      * Executes the table commands.
  86.      */
  87.     execCommand : function(editor_id, element, command, user_interface, value) {
  88.         // Is table command
  89.         switch (command) {
  90.             case "mceInsertTable":
  91.             case "mceTableRowProps":
  92.             case "mceTableCellProps":
  93.             case "mceTableSplitCells":
  94.             case "mceTableMergeCells":
  95.             case "mceTableInsertRowBefore":
  96.             case "mceTableInsertRowAfter":
  97.             case "mceTableDeleteRow":
  98.             case "mceTableInsertColBefore":
  99.             case "mceTableInsertColAfter":
  100.             case "mceTableDeleteCol":
  101.             case "mceTableCutRow":
  102.             case "mceTableCopyRow":
  103.             case "mceTablePasteRowBefore":
  104.             case "mceTablePasteRowAfter":
  105.             case "mceTableDelete":
  106.                 var inst = tinyMCE.getInstanceById(editor_id);
  107.  
  108.                 inst.execCommand('mceBeginUndoLevel');
  109.                 TinyMCE_TablePlugin._doExecCommand(editor_id, element, command, user_interface, value);
  110.                 inst.execCommand('mceEndUndoLevel');
  111.  
  112.                 return true;
  113.         }
  114.  
  115.         // Pass to next handler in chain
  116.         return false;
  117.     },
  118.  
  119.     handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
  120.         var colspan = "1", rowspan = "1", tdElm;
  121.  
  122.         var inst = tinyMCE.getInstanceById(editor_id);
  123.  
  124.         // Reset table controls
  125.         tinyMCE.switchClass(editor_id + '_table', 'mceButtonNormal');
  126.         tinyMCE.switchClass(editor_id + '_delete_table', 'mceButtonDisabled');
  127.         tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonDisabled');
  128.         tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonDisabled');
  129.         tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonDisabled');
  130.         tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonDisabled');
  131.         tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonDisabled');
  132.         tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonDisabled');
  133.         tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonDisabled');
  134.         tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonDisabled');
  135.         tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonDisabled');
  136.         tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonDisabled');
  137.  
  138.         // Within a td element
  139.         if (tdElm = tinyMCE.getParentElement(node, "td,th")) {
  140.             tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonSelected');
  141.             tinyMCE.switchClass(editor_id + '_delete_table', 'mceButtonNormal');
  142.             tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonNormal');
  143.             tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonNormal');
  144.             tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonNormal');
  145.             tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonNormal');
  146.             tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonNormal');
  147.             tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonNormal');
  148.  
  149.             colspan = tinyMCE.getAttrib(tdElm, "colspan");
  150.             rowspan = tinyMCE.getAttrib(tdElm, "rowspan");
  151.  
  152.             colspan = colspan == "" ? "1" : colspan;
  153.             rowspan = rowspan == "" ? "1" : rowspan;
  154.  
  155.             if (colspan != "1" || rowspan != "1")
  156.                 tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonNormal');
  157.         }
  158.  
  159.         // Within a tr element
  160.         if (tinyMCE.getParentElement(node, "tr"))
  161.             tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonSelected');
  162.  
  163.         // Within table
  164.         if (tinyMCE.getParentElement(node, "table")) {
  165.             tinyMCE.switchClass(editor_id + '_table', 'mceButtonSelected');
  166.             tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonNormal');
  167.         }
  168.     },
  169.  
  170.     // Private plugin internal methods
  171.  
  172.     _mouseDownHandler : function(e) {
  173.         var elm = tinyMCE.isMSIE ? event.srcElement : e.target;
  174.         var focusElm = tinyMCE.selectedInstance.getFocusElement();
  175.  
  176.         // If press on special Mozilla create TD/TR thingie
  177.         if (elm.nodeName == "BODY" && (focusElm.nodeName == "TD" || focusElm.nodeName == "TH" || (focusElm.parentNode && focusElm.parentNode.nodeName == "TD") ||(focusElm.parentNode && focusElm.parentNode.nodeName == "TH") )) {
  178.             window.setTimeout(function() {
  179.                 var tableElm = tinyMCE.getParentElement(focusElm, "table");
  180.                 tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
  181.             }, 10);
  182.         }
  183.     },
  184.  
  185.     /**
  186.      * Executes the table commands.
  187.      */
  188.     _doExecCommand : function(editor_id, element, command, user_interface, value) {
  189.         var inst = tinyMCE.getInstanceById(editor_id);
  190.         var focusElm = inst.getFocusElement();
  191.         var trElm = tinyMCE.getParentElement(focusElm, "tr");
  192.         var tdElm = tinyMCE.getParentElement(focusElm, "td,th");
  193.         var tableElm = tinyMCE.getParentElement(focusElm, "table");
  194.         var doc = inst.contentWindow.document;
  195.         var tableBorder = tableElm ? tableElm.getAttribute("border") : "";
  196.  
  197.         // Get first TD if no TD found
  198.         if (trElm && tdElm == null)
  199.             tdElm = trElm.cells[0];
  200.  
  201.         // ------- Inner functions ---------
  202.         function inArray(ar, v) {
  203.             for (var i=0; i<ar.length; i++) {
  204.                 // Is array
  205.                 if (ar[i].length > 0 && inArray(ar[i], v))
  206.                     return true;
  207.  
  208.                 // Found value
  209.                 if (ar[i] == v)
  210.                     return true;
  211.             }
  212.  
  213.             return false;
  214.         }
  215.  
  216.         function makeTD() {
  217.             var newTD = doc.createElement("td");
  218.             newTD.innerHTML = " ";
  219.         }
  220.  
  221.         function getColRowSpan(td) {
  222.             var colspan = tinyMCE.getAttrib(td, "colspan");
  223.             var rowspan = tinyMCE.getAttrib(td, "rowspan");
  224.  
  225.             colspan = colspan == "" ? 1 : parseInt(colspan);
  226.             rowspan = rowspan == "" ? 1 : parseInt(rowspan);
  227.  
  228.             return {colspan : colspan, rowspan : rowspan};
  229.         }
  230.  
  231.         function getCellPos(grid, td) {
  232.             var x, y;
  233.  
  234.             for (y=0; y<grid.length; y++) {
  235.                 for (x=0; x<grid[y].length; x++) {
  236.                     if (grid[y][x] == td)
  237.                         return {cellindex : x, rowindex : y};
  238.                 }
  239.             }
  240.  
  241.             return null;
  242.         }
  243.  
  244.         function getCell(grid, row, col) {
  245.             if (grid[row] && grid[row][col])
  246.                 return grid[row][col];
  247.  
  248.             return null;
  249.         }
  250.  
  251.         function getTableGrid(table) {
  252.             var grid = new Array(), rows = table.rows, x, y, td, sd, xstart, x2, y2;
  253.  
  254.             for (y=0; y<rows.length; y++) {
  255.                 for (x=0; x<rows[y].cells.length; x++) {
  256.                     td = rows[y].cells[x];
  257.                     sd = getColRowSpan(td);
  258.  
  259.                     // All ready filled
  260.                     for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ;
  261.  
  262.                     // Fill box
  263.                     for (y2=y; y2<y+sd['rowspan']; y2++) {
  264.                         if (!grid[y2])
  265.                             grid[y2] = new Array();
  266.  
  267.                         for (x2=xstart; x2<xstart+sd['colspan']; x2++)
  268.                             grid[y2][x2] = td;
  269.                     }
  270.                 }
  271.             }
  272.  
  273.             return grid;
  274.         }
  275.  
  276.         function trimRow(table, tr, td, new_tr) {
  277.             var grid = getTableGrid(table), cpos = getCellPos(grid, td);
  278.             var cells, lastElm;
  279.  
  280.             // Time to crop away some
  281.             if (new_tr.cells.length != tr.childNodes.length) {
  282.                 cells = tr.childNodes;
  283.                 lastElm = null;
  284.  
  285.                 for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) {
  286.                     var remove = true;
  287.                     var sd = getColRowSpan(td);
  288.  
  289.                     // Remove due to rowspan
  290.                     if (inArray(cells, td)) {
  291.                         new_tr.childNodes[x]._delete = true;
  292.                     } else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan
  293.                         for (var i=x; i<x+td.colSpan; i++)
  294.                             new_tr.childNodes[i]._delete = true;
  295.                     }
  296.  
  297.                     if ((lastElm == null || td != lastElm) && sd.rowspan > 1)
  298.                         td.rowSpan = sd.rowspan + 1;
  299.  
  300.                     lastElm = td;
  301.                 }
  302.  
  303.                 deleteMarked(tableElm);
  304.             }
  305.         }
  306.  
  307.         function prevElm(node, name) {
  308.             while ((node = node.previousSibling) != null) {
  309.                 if (node.nodeName == name)
  310.                     return node;
  311.             }
  312.  
  313.             return null;
  314.         }
  315.  
  316.         function nextElm(node, names) {
  317.             var namesAr = names.split(',');
  318.  
  319.             while ((node = node.nextSibling) != null) {
  320.                 for (var i=0; i<namesAr.length; i++) {
  321.                     if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() )
  322.                         return node;
  323.                 }
  324.             }
  325.  
  326.             return null;
  327.         }
  328.  
  329.         function deleteMarked(tbl) {
  330.             if (tbl.rows == 0)
  331.                 return;
  332.  
  333.             var tr = tbl.rows[0];
  334.             do {
  335.                 var next = nextElm(tr, "TR");
  336.  
  337.                 // Delete row
  338.                 if (tr._delete) {
  339.                     tr.parentNode.removeChild(tr);
  340.                     continue;
  341.                 }
  342.  
  343.                 // Delete cells
  344.                 var td = tr.cells[0];
  345.                 if (td.cells > 1) {
  346.                     do {
  347.                         var nexttd = nextElm(td, "TD,TH");
  348.  
  349.                         if (td._delete)
  350.                             td.parentNode.removeChild(td);
  351.                     } while ((td = nexttd) != null);
  352.                 }
  353.             } while ((tr = next) != null);
  354.         }
  355.  
  356.         function addRows(td_elm, tr_elm, rowspan) {
  357.             // Add rows
  358.             td_elm.rowSpan = 1;
  359.             var trNext = nextElm(tr_elm, "TR");
  360.             for (var i=1; i<rowspan && trNext; i++) {
  361.                 var newTD = doc.createElement("td");
  362.                 newTD.innerHTML = " ";
  363.  
  364.                 if (tinyMCE.isMSIE)
  365.                     trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex));
  366.                 else
  367.                     trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]);
  368.  
  369.                 trNext = nextElm(trNext, "TR");
  370.             }
  371.         }
  372.  
  373.         function copyRow(doc, table, tr) {
  374.             var grid = getTableGrid(table);
  375.             var newTR = tr.cloneNode(false);
  376.             var cpos = getCellPos(grid, tr.cells[0]);
  377.             var lastCell = null;
  378.             var tableBorder = tinyMCE.getAttrib(table, "border");
  379.             var tdElm = null;
  380.  
  381.             for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
  382.                 var newTD = null;
  383.  
  384.                 if (lastCell != tdElm) {
  385.                     for (var i=0; i<tr.cells.length; i++) {
  386.                         if (tdElm == tr.cells[i]) {
  387.                             newTD = tdElm.cloneNode(true);
  388.                             break;
  389.                         }
  390.                     }
  391.                 }
  392.  
  393.                 if (newTD == null) {
  394.                     newTD = doc.createElement("td");
  395.                     newTD.innerHTML = " ";
  396.                 }
  397.  
  398.                 // Reset col/row span
  399.                 newTD.colSpan = 1;
  400.                 newTD.rowSpan = 1;
  401.  
  402.                 newTR.appendChild(newTD);
  403.  
  404.                 lastCell = tdElm;
  405.             }
  406.  
  407.             return newTR;
  408.         }
  409.  
  410.         // ---- Commands -----
  411.  
  412.         // Handle commands
  413.         switch (command) {
  414.             case "mceTableRowProps":
  415.                 if (trElm == null)
  416.                     return true;
  417.  
  418.                 if (user_interface) {
  419.                     // Setup template
  420.                     var template = new Array();
  421.  
  422.                     template['file'] = tinyMCE.baseURL + '/../../../wp-content/plugins/tinymce-advanced/mce/table/row.htm';
  423.                     template['width'] = 380;
  424.                     template['height'] = 295;
  425.  
  426.                     // Language specific width and height addons
  427.                     template['width'] += tinyMCE.getLang('lang_table_rowprops_delta_width', 0);
  428.                     template['height'] += tinyMCE.getLang('lang_table_rowprops_delta_height', 0);
  429.  
  430.                     // Open window
  431.                     tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});
  432.                 }
  433.  
  434.                 return true;
  435.  
  436.             case "mceTableCellProps":
  437.                 if (tdElm == null)
  438.                     return true;
  439.  
  440.                 if (user_interface) {
  441.                     // Setup template
  442.                     var template = new Array();
  443.  
  444.                     template['file'] = tinyMCE.baseURL + '/../../../wp-content/plugins/tinymce-advanced/mce/table/cell.htm';
  445.                     template['width'] = 380;
  446.                     template['height'] = 295;
  447.  
  448.                     // Language specific width and height addons
  449.                     template['width'] += tinyMCE.getLang('lang_table_cellprops_delta_width', 0);
  450.                     template['height'] += tinyMCE.getLang('lang_table_cellprops_delta_height', 0);
  451.  
  452.                     // Open window
  453.                     tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});
  454.                 }
  455.  
  456.                 return true;
  457.  
  458.             case "mceInsertTable":
  459.                 if (user_interface) {
  460.                     // Setup template
  461.                     var template = new Array();
  462.  
  463.                     template['file'] = tinyMCE.baseURL + '/../../../wp-content/plugins/tinymce-advanced/mce/table/table.htm';
  464.                     template['width'] = 380;
  465.                     template['height'] = 295;
  466.  
  467.                     // Language specific width and height addons
  468.                     template['width'] += tinyMCE.getLang('lang_table_table_delta_width', 0);
  469.                     template['height'] += tinyMCE.getLang('lang_table_table_delta_height', 0);
  470.  
  471.                     // Open window
  472.                     tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : value});
  473.                 }
  474.  
  475.                 return true;
  476.  
  477.             case "mceTableDelete":
  478.                 var table = tinyMCE.getParentElement(inst.getFocusElement(), "table");
  479.                 if (table) {
  480.                     table.parentNode.removeChild(table);
  481.                     inst.repaint();
  482.                 }
  483.                 return true;
  484.  
  485.             case "mceTableSplitCells":
  486.             case "mceTableMergeCells":
  487.             case "mceTableInsertRowBefore":
  488.             case "mceTableInsertRowAfter":
  489.             case "mceTableDeleteRow":
  490.             case "mceTableInsertColBefore":
  491.             case "mceTableInsertColAfter":
  492.             case "mceTableDeleteCol":
  493.             case "mceTableCutRow":
  494.             case "mceTableCopyRow":
  495.             case "mceTablePasteRowBefore":
  496.             case "mceTablePasteRowAfter":
  497.                 // No table just return (invalid command)
  498.                 if (!tableElm)
  499.                     return true;
  500.  
  501.                 // Table has a tbody use that reference
  502.                 // Changed logic by ApTest 2005.07.12 (www.aptest.com)
  503.                 // Now lookk at the focused element and take its parentNode.  That will be a tbody or a table.
  504.                 if (trElm && tableElm != trElm.parentNode)
  505.                     tableElm = trElm.parentNode;
  506.  
  507.                 if (tableElm && trElm) {
  508.                     switch (command) {
  509.                         case "mceTableCutRow":
  510.                             if (!trElm || !tdElm)
  511.                                 return true;
  512.  
  513.                             inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
  514.                             inst.execCommand("mceTableDeleteRow");
  515.                             break;
  516.  
  517.                         case "mceTableCopyRow":
  518.                             if (!trElm || !tdElm)
  519.                                 return true;
  520.  
  521.                             inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
  522.                             break;
  523.  
  524.                         case "mceTablePasteRowBefore":
  525.                             if (!trElm || !tdElm)
  526.                                 return true;
  527.  
  528.                             var newTR = inst.tableRowClipboard.cloneNode(true);
  529.  
  530.                             var prevTR = prevElm(trElm, "TR");
  531.                             if (prevTR != null)
  532.                                 trimRow(tableElm, prevTR, prevTR.cells[0], newTR);
  533.  
  534.                             trElm.parentNode.insertBefore(newTR, trElm);
  535.                             break;
  536.  
  537.                         case "mceTablePasteRowAfter":
  538.                             if (!trElm || !tdElm)
  539.                                 return true;
  540.                             
  541.                             var nextTR = nextElm(trElm, "TR");
  542.                             var newTR = inst.tableRowClipboard.cloneNode(true);
  543.  
  544.                             trimRow(tableElm, trElm, tdElm, newTR);
  545.  
  546.                             if (nextTR == null)
  547.                                 trElm.parentNode.appendChild(newTR);
  548.                             else
  549.                                 nextTR.parentNode.insertBefore(newTR, nextTR);
  550.  
  551.                             break;
  552.  
  553.                         case "mceTableInsertRowBefore":
  554.                             if (!trElm || !tdElm)
  555.                                 return true;
  556.  
  557.                             var grid = getTableGrid(tableElm);
  558.                             var cpos = getCellPos(grid, tdElm);
  559.                             var newTR = doc.createElement("tr");
  560.                             var lastTDElm = null;
  561.  
  562.                             cpos.rowindex--;
  563.                             if (cpos.rowindex < 0)
  564.                                 cpos.rowindex = 0;
  565.  
  566.                             // Create cells
  567.                             for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
  568.                                 if (tdElm != lastTDElm) {
  569.                                     var sd = getColRowSpan(tdElm);
  570.  
  571.                                     if (sd['rowspan'] == 1) {
  572.                                         var newTD = doc.createElement("td");
  573.  
  574.                                         newTD.innerHTML = " ";
  575.                                         newTD.colSpan = tdElm.colSpan;
  576.  
  577.                                         newTR.appendChild(newTD);
  578.                                     } else
  579.                                         tdElm.rowSpan = sd['rowspan'] + 1;
  580.  
  581.                                     lastTDElm = tdElm;
  582.                                 }
  583.                             }
  584.  
  585.                             trElm.parentNode.insertBefore(newTR, trElm);
  586.  
  587.                             grid = getTableGrid(tableElm);
  588.                             inst.selection.selectNode(getCell(grid, cpos.rowindex + 1, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
  589.                         break;
  590.  
  591.                         case "mceTableInsertRowAfter":
  592.                             if (!trElm || !tdElm)
  593.                                 return true;
  594.  
  595.                             var grid = getTableGrid(tableElm);
  596.                             var cpos = getCellPos(grid, tdElm);
  597.                             var newTR = doc.createElement("tr");
  598.                             var lastTDElm = null;
  599.  
  600.                             // Create cells
  601.                             for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
  602.                                 if (tdElm != lastTDElm) {
  603.                                     var sd = getColRowSpan(tdElm);
  604.  
  605.                                     if (sd['rowspan'] == 1) {
  606.                                         var newTD = doc.createElement("td");
  607.  
  608.                                         newTD.innerHTML = " ";
  609.                                         newTD.colSpan = tdElm.colSpan;
  610.  
  611.                                         newTR.appendChild(newTD);
  612.                                     } else
  613.                                         tdElm.rowSpan = sd['rowspan'] + 1;
  614.  
  615.                                     lastTDElm = tdElm;
  616.                                 }
  617.                             }
  618.  
  619.                             if (newTR.hasChildNodes()) {
  620.                                 var nextTR = nextElm(trElm, "TR");
  621.                                 if (nextTR)
  622.                                     nextTR.parentNode.insertBefore(newTR, nextTR);
  623.                                 else
  624.                                     tableElm.appendChild(newTR);
  625.                             }
  626.  
  627.                             grid = getTableGrid(tableElm);
  628.                             inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
  629.                         break;
  630.  
  631.                         case "mceTableDeleteRow":
  632.                             if (!trElm || !tdElm)
  633.                                 return true;
  634.  
  635.                             var grid = getTableGrid(tableElm);
  636.                             var cpos = getCellPos(grid, tdElm);
  637.  
  638.                             // Only one row, remove whole table
  639.                             if (grid.length == 1) {
  640.                                 tableElm = tinyMCE.getParentElement(tableElm, "table"); // Look for table instead of tbody
  641.                                 tableElm.parentNode.removeChild(tableElm);
  642.                                 return true;
  643.                             }
  644.  
  645.                             // Move down row spanned cells
  646.                             var cells = trElm.cells;
  647.                             var nextTR = nextElm(trElm, "TR");
  648.                             for (var x=0; x<cells.length; x++) {
  649.                                 if (cells[x].rowSpan > 1) {
  650.                                     var newTD = cells[x].cloneNode(true);
  651.                                     var sd = getColRowSpan(cells[x]);
  652.  
  653.                                     newTD.rowSpan = sd.rowspan - 1;
  654.  
  655.                                     var nextTD = nextTR.cells[x];
  656.  
  657.                                     if (nextTD == null)
  658.                                         nextTR.appendChild(newTD);
  659.                                     else
  660.                                         nextTR.insertBefore(newTD, nextTD);
  661.                                 }
  662.                             }
  663.  
  664.                             // Delete cells
  665.                             var lastTDElm = null;
  666.                             for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
  667.                                 if (tdElm != lastTDElm) {
  668.                                     var sd = getColRowSpan(tdElm);
  669.  
  670.                                     if (sd.rowspan > 1) {
  671.                                         tdElm.rowSpan = sd.rowspan - 1;
  672.                                     } else {
  673.                                         trElm = tdElm.parentNode;
  674.  
  675.                                         if (trElm.parentNode)
  676.                                             trElm._delete = true;
  677.                                     }
  678.  
  679.                                     lastTDElm = tdElm;
  680.                                 }
  681.                             }
  682.  
  683.                             deleteMarked(tableElm);
  684.  
  685.                             cpos.rowindex--;
  686.                             if (cpos.rowindex < 0)
  687.                                 cpos.rowindex = 0;
  688.  
  689.                             // Recalculate grid and select
  690.                             grid = getTableGrid(tableElm);
  691.                             inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), tinyMCE.isGecko, true); // Only collape on gecko
  692.                         break;
  693.  
  694.                         case "mceTableInsertColBefore":
  695.                             if (!trElm || !tdElm)
  696.                                 return true;
  697.  
  698.                             var grid = getTableGrid(tableElm);
  699.                             var cpos = getCellPos(grid, tdElm);
  700.                             var lastTDElm = null;
  701.  
  702.                             for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
  703.                                 if (tdElm != lastTDElm) {
  704.                                     var sd = getColRowSpan(tdElm);
  705.  
  706.                                     if (sd['colspan'] == 1) {
  707.                                         var newTD = doc.createElement(tdElm.nodeName);
  708.  
  709.                                         newTD.innerHTML = " ";
  710.                                         newTD.rowSpan = tdElm.rowSpan;
  711.  
  712.                                         tdElm.parentNode.insertBefore(newTD, tdElm);
  713.                                     } else
  714.                                         tdElm.colSpan++;
  715.  
  716.                                     lastTDElm = tdElm;
  717.                                 }
  718.                             }
  719.  
  720.                             grid = getTableGrid(tableElm);
  721.                             inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex + 1), tinyMCE.isGecko, true); // Only collape on gecko
  722.                         break;
  723.  
  724.                         case "mceTableInsertColAfter":
  725.                             if (!trElm || !tdElm)
  726.                                 return true;
  727.  
  728.                             var grid = getTableGrid(tableElm);
  729.                             var cpos = getCellPos(grid, tdElm);
  730.                             var lastTDElm = null;
  731.  
  732.                             for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
  733.                                 if (tdElm != lastTDElm) {
  734.                                     var sd = getColRowSpan(tdElm);
  735.  
  736.                                     if (sd['colspan'] == 1) {
  737.                                         var newTD = doc.createElement(tdElm.nodeName);
  738.  
  739.                                         newTD.innerHTML = " ";
  740.                                         newTD.rowSpan = tdElm.rowSpan;
  741.  
  742.                                         var nextTD = nextElm(tdElm, "TD,TH");
  743.                                         if (nextTD == null)
  744.                                             tdElm.parentNode.appendChild(newTD);
  745.                                         else
  746.                                             nextTD.parentNode.insertBefore(newTD, nextTD);
  747.                                     } else
  748.                                         tdElm.colSpan++;
  749.  
  750.                                     lastTDElm = tdElm;
  751.                                 }
  752.                             }
  753.  
  754.                             grid = getTableGrid(tableElm);
  755.                             inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
  756.                         break;
  757.  
  758.                         case "mceTableDeleteCol":
  759.                             if (!trElm || !tdElm)
  760.                                 return true;
  761.  
  762.                             var grid = getTableGrid(tableElm);
  763.                             var cpos = getCellPos(grid, tdElm);
  764.                             var lastTDElm = null;
  765.  
  766.                             // Only one col, remove whole table
  767.                             if (grid.length > 1 && grid[0].length <= 1) {
  768.                                 tableElm = tinyMCE.getParentElement(tableElm, "table"); // Look for table instead of tbody
  769.                                 tableElm.parentNode.removeChild(tableElm);
  770.                                 return true;
  771.                             }
  772.  
  773.                             // Delete cells
  774.                             for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
  775.                                 if (tdElm != lastTDElm) {
  776.                                     var sd = getColRowSpan(tdElm);
  777.  
  778.                                     if (sd['colspan'] > 1)
  779.                                         tdElm.colSpan = sd['colspan'] - 1;
  780.                                     else {
  781.                                         if (tdElm.parentNode)
  782.                                             tdElm.parentNode.removeChild(tdElm);
  783.                                     }
  784.  
  785.                                     lastTDElm = tdElm;
  786.                                 }
  787.                             }
  788.  
  789.                             cpos.cellindex--;
  790.                             if (cpos.cellindex < 0)
  791.                                 cpos.cellindex = 0;
  792.  
  793.                             // Recalculate grid and select
  794.                             grid = getTableGrid(tableElm);
  795.                             inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), tinyMCE.isGecko, true); // Only collape on gecko
  796.                         break;
  797.  
  798.                     case "mceTableSplitCells":
  799.                         if (!trElm || !tdElm)
  800.                             return true;
  801.  
  802.                         var spandata = getColRowSpan(tdElm);
  803.  
  804.                         var colspan = spandata["colspan"];
  805.                         var rowspan = spandata["rowspan"];
  806.  
  807.                         // Needs splitting
  808.                         if (colspan > 1 || rowspan > 1) {
  809.                             // Generate cols
  810.                             tdElm.colSpan = 1;
  811.                             for (var i=1; i<colspan; i++) {
  812.                                 var newTD = doc.createElement("td");
  813.  
  814.                                 newTD.innerHTML = " ";
  815.  
  816.                                 trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH"));
  817.  
  818.                                 if (rowspan > 1)
  819.                                     addRows(newTD, trElm, rowspan);
  820.                             }
  821.  
  822.                             addRows(tdElm, trElm, rowspan);
  823.                         }
  824.  
  825.                         // Apply visual aids
  826.                         tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
  827.                         break;
  828.  
  829.                     case "mceTableMergeCells":
  830.                         var rows = new Array();
  831.                         var sel = inst.getSel();
  832.                         var grid = getTableGrid(tableElm);
  833.  
  834.                         if (tinyMCE.isMSIE || sel.rangeCount == 1) {
  835.                             if (user_interface) {
  836.                                 // Setup template
  837.                                 var template = new Array();
  838.                                 var sp = getColRowSpan(tdElm);
  839.  
  840.                                 template['file'] = tinyMCE.baseURL + '/../../../wp-content/plugins/tinymce-advanced/mce/table/merge_cells.htm';
  841.                                 template['width'] = 250;
  842.                                 template['height'] = 105 + (tinyMCE.isNS7 ? 25 : 0);
  843.  
  844.                                 // Language specific width and height addons
  845.                                 template['width'] += tinyMCE.getLang('lang_table_merge_cells_delta_width', 0);
  846.                                 template['height'] += tinyMCE.getLang('lang_table_merge_cells_delta_height', 0);
  847.  
  848.                                 // Open window
  849.                                 tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : "update", numcols : sp.colspan, numrows : sp.rowspan});
  850.  
  851.                                 return true;
  852.                             } else {
  853.                                 var numRows = parseInt(value['numrows']);
  854.                                 var numCols = parseInt(value['numcols']);
  855.                                 var cpos = getCellPos(grid, tdElm);
  856.  
  857.                                 if (("" + numRows) == "NaN")
  858.                                     numRows = 1;
  859.  
  860.                                 if (("" + numCols) == "NaN")
  861.                                     numCols = 1;
  862.  
  863.                                 // Get rows and cells
  864.                                 var tRows = tableElm.rows;
  865.                                 for (var y=cpos.rowindex; y<grid.length; y++) {
  866.                                     var rowCells = new Array();
  867.  
  868.                                     for (var x=cpos.cellindex; x<grid[y].length; x++) {
  869.                                         var td = getCell(grid, y, x);
  870.  
  871.                                         if (td && !inArray(rows, td) && !inArray(rowCells, td)) {
  872.                                             var cp = getCellPos(grid, td);
  873.  
  874.                                             // Within range
  875.                                             if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows)
  876.                                                 rowCells[rowCells.length] = td;
  877.                                         }
  878.                                     }
  879.  
  880.                                     if (rowCells.length > 0)
  881.                                         rows[rows.length] = rowCells;
  882.                                 }
  883.  
  884.                                 //return true;
  885.                             }
  886.                         } else {
  887.                             var cells = new Array();
  888.                             var sel = inst.getSel();
  889.                             var lastTR = null;
  890.                             var curRow = null;
  891.                             var x1 = -1, y1 = -1, x2, y2;
  892.  
  893.                             // Only one cell selected, whats the point?
  894.                             if (sel.rangeCount < 2)
  895.                                 return true;
  896.  
  897.                             // Get all selected cells
  898.                             for (var i=0; i<sel.rangeCount; i++) {
  899.                                 var rng = sel.getRangeAt(i);
  900.                                 var tdElm = rng.startContainer.childNodes[rng.startOffset];
  901.  
  902.                                 if (!tdElm)
  903.                                     break;
  904.  
  905.                                 if (tdElm.nodeName == "TD")
  906.                                     cells[cells.length] = tdElm;
  907.                             }
  908.  
  909.                             // Get rows and cells
  910.                             var tRows = tableElm.rows;
  911.                             for (var y=0; y<tRows.length; y++) {
  912.                                 var rowCells = new Array();
  913.  
  914.                                 for (var x=0; x<tRows[y].cells.length; x++) {
  915.                                     var td = tRows[y].cells[x];
  916.  
  917.                                     for (var i=0; i<cells.length; i++) {
  918.                                         if (td == cells[i]) {
  919.                                             rowCells[rowCells.length] = td;
  920.                                         }
  921.                                     }
  922.                                 }
  923.  
  924.                                 if (rowCells.length > 0)
  925.                                     rows[rows.length] = rowCells;
  926.                             }
  927.  
  928.                             // Find selected cells in grid and box
  929.                             var curRow = new Array();
  930.                             var lastTR = null;
  931.                             for (var y=0; y<grid.length; y++) {
  932.                                 for (var x=0; x<grid[y].length; x++) {
  933.                                     grid[y][x]._selected = false;
  934.  
  935.                                     for (var i=0; i<cells.length; i++) {
  936.                                         if (grid[y][x] == cells[i]) {
  937.                                             // Get start pos
  938.                                             if (x1 == -1) {
  939.                                                 x1 = x;
  940.                                                 y1 = y;
  941.                                             }
  942.  
  943.                                             // Get end pos
  944.                                             x2 = x;
  945.                                             y2 = y;
  946.  
  947.                                             grid[y][x]._selected = true;
  948.                                         }
  949.                                     }
  950.                                 }
  951.                             }
  952.  
  953.                             // Is there gaps, if so deny
  954.                             for (var y=y1; y<=y2; y++) {
  955.                                 for (var x=x1; x<=x2; x++) {
  956.                                     if (!grid[y][x]._selected) {
  957.                                         alert("Invalid selection for merge.");
  958.                                         return true;
  959.                                     }
  960.                                 }
  961.                             }
  962.                         }
  963.  
  964.                         // Validate selection and get total rowspan and colspan
  965.                         var rowSpan = 1, colSpan = 1;
  966.  
  967.                         // Validate horizontal and get total colspan
  968.                         var lastRowSpan = -1;
  969.                         for (var y=0; y<rows.length; y++) {
  970.                             var rowColSpan = 0;
  971.  
  972.                             for (var x=0; x<rows[y].length; x++) {
  973.                                 var sd = getColRowSpan(rows[y][x]);
  974.  
  975.                                 rowColSpan += sd['colspan'];
  976.  
  977.                                 if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) {
  978.                                     alert("Invalid selection for merge.");
  979.                                     return true;
  980.                                 }
  981.  
  982.                                 lastRowSpan = sd['rowspan'];
  983.                             }
  984.  
  985.                             if (rowColSpan > colSpan)
  986.                                 colSpan = rowColSpan;
  987.  
  988.                             lastRowSpan = -1;
  989.                         }
  990.  
  991.                         // Validate vertical and get total rowspan
  992.                         var lastColSpan = -1;
  993.                         for (var x=0; x<rows[0].length; x++) {
  994.                             var colRowSpan = 0;
  995.  
  996.                             for (var y=0; y<rows.length; y++) {
  997.                                 var sd = getColRowSpan(rows[y][x]);
  998.  
  999.                                 colRowSpan += sd['rowspan'];
  1000.  
  1001.                                 if (lastColSpan != -1 && sd['colspan'] != lastColSpan) {
  1002.                                     alert("Invalid selection for merge.");
  1003.                                     return true;
  1004.                                 }
  1005.  
  1006.                                 lastColSpan = sd['colspan'];
  1007.                             }
  1008.  
  1009.                             if (colRowSpan > rowSpan)
  1010.                                 rowSpan = colRowSpan;
  1011.  
  1012.                             lastColSpan = -1;
  1013.                         }
  1014.  
  1015.                         // Setup td
  1016.                         tdElm = rows[0][0];
  1017.                         tdElm.rowSpan = rowSpan;
  1018.                         tdElm.colSpan = colSpan;
  1019.  
  1020.                         // Merge cells
  1021.                         for (var y=0; y<rows.length; y++) {
  1022.                             for (var x=0; x<rows[y].length; x++) {
  1023.                                 var html = rows[y][x].innerHTML;
  1024.                                 var chk = tinyMCE.regexpReplace(html, "[ \t\r\n]", "");
  1025.  
  1026.                                 if (chk != "<br/>" && chk != "<br>" && chk != " " && (x+y > 0))
  1027.                                     tdElm.innerHTML += html;
  1028.  
  1029.                                 // Not current cell
  1030.                                 if (rows[y][x] != tdElm && !rows[y][x]._deleted) {
  1031.                                     var cpos = getCellPos(grid, rows[y][x]);
  1032.                                     var tr = rows[y][x].parentNode;
  1033.  
  1034.                                     tr.removeChild(rows[y][x]);
  1035.                                     rows[y][x]._deleted = true;
  1036.  
  1037.                                     // Empty TR, remove it
  1038.                                     if (!tr.hasChildNodes()) {
  1039.                                         tr.parentNode.removeChild(tr);
  1040.  
  1041.                                         var lastCell = null;
  1042.                                         for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) {
  1043.                                             if (cellElm != lastCell && cellElm.rowSpan > 1)
  1044.                                                 cellElm.rowSpan--;
  1045.  
  1046.                                             lastCell = cellElm;
  1047.                                         }
  1048.  
  1049.                                         if (tdElm.rowSpan > 1)
  1050.                                             tdElm.rowSpan--;
  1051.                                     }
  1052.                                 }
  1053.                             }
  1054.                         }
  1055.  
  1056.                         break;
  1057.                     }
  1058.  
  1059.                     tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
  1060.                     tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
  1061.                     tinyMCE.triggerNodeChange();
  1062.                     inst.repaint();
  1063.                 }
  1064.  
  1065.             return true;
  1066.         }
  1067.  
  1068.         // Pass to next handler in chain
  1069.         return false;
  1070.     }
  1071. };
  1072.  
  1073. tinyMCE.addPlugin("table", TinyMCE_TablePlugin);
  1074.