JAVASCRIPT 15
Editor_plugin_src.js Guest on 10th October 2020 09:07:03 PM
  1. /**
  2.  * editor_plugin_src.js
  3.  *
  4.  * Copyright 2009, Moxiecode Systems AB
  5.  * Released under LGPL License.
  6.  *
  7.  * License: http://tinymce.moxiecode.com/license
  8.  * Contributing: http://tinymce.moxiecode.com/contributing
  9.  */
  10.  
  11. (function(tinymce) {
  12.         var each = tinymce.each;
  13.  
  14.         // Checks if the selection/caret is at the start of the specified block element
  15.         function isAtStart(rng, par) {
  16.                 var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
  17.  
  18.                 rng2.setStartBefore(par);
  19.                 rng2.setEnd(rng.endContainer, rng.endOffset);
  20.  
  21.                 elm = doc.createElement('body');
  22.                 elm.appendChild(rng2.cloneContents());
  23.  
  24.                 // Check for text characters of other elements that should be treated as content
  25.                 return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0;
  26.         };
  27.  
  28.         /**
  29.          * Table Grid class.
  30.          */
  31.         function TableGrid(table, dom, selection) {
  32.                 var grid, startPos, endPos, selectedCell;
  33.  
  34.                 buildGrid();
  35.                 selectedCell = dom.getParent(selection.getStart(), 'th,td');
  36.                 if (selectedCell) {
  37.                         startPos = getPos(selectedCell);
  38.                         endPos = findEndPos();
  39.                         selectedCell = getCell(startPos.x, startPos.y);
  40.                 }
  41.  
  42.                 function cloneNode(node, children) {
  43.                         node = node.cloneNode(children);
  44.                         node.removeAttribute('id');
  45.  
  46.                         return node;
  47.                 }
  48.  
  49.                 function buildGrid() {
  50.                         var startY = 0;
  51.  
  52.                         grid = [];
  53.  
  54.                         each(['thead', 'tbody', 'tfoot'], function(part) {
  55.                                 var rows = dom.select('> ' + part + ' tr', table);
  56.  
  57.                                 each(rows, function(tr, y) {
  58.                                         y += startY;
  59.  
  60.                                         each(dom.select('> td, > th', tr), function(td, x) {
  61.                                                 var x2, y2, rowspan, colspan;
  62.  
  63.                                                 // Skip over existing cells produced by rowspan
  64.                                                 if (grid[y]) {
  65.                                                         while (grid[y][x])
  66.                                                                 x++;
  67.                                                 }
  68.  
  69.                                                 // Get col/rowspan from cell
  70.                                                 rowspan = getSpanVal(td, 'rowspan');
  71.                                                 colspan = getSpanVal(td, 'colspan');
  72.  
  73.                                                 // Fill out rowspan/colspan right and down
  74.                                                 for (y2 = y; y2 < y + rowspan; y2++) {
  75.                                                         if (!grid[y2])
  76.                                                                 grid[y2] = [];
  77.  
  78.                                                         for (x2 = x; x2 < x + colspan; x2++) {
  79.                                                                 grid[y2][x2] = {
  80.                                                                         part : part,
  81.                                                                         real : y2 == y && x2 == x,
  82.                                                                         elm : td,
  83.                                                                         rowspan : rowspan,
  84.                                                                         colspan : colspan
  85.                                                                 };
  86.                                                         }
  87.                                                 }
  88.                                         });
  89.                                 });
  90.  
  91.                                 startY += rows.length;
  92.                         });
  93.                 };
  94.  
  95.                 function getCell(x, y) {
  96.                         var row;
  97.  
  98.                         row = grid[y];
  99.                         if (row)
  100.                                 return row[x];
  101.                 };
  102.  
  103.                 function getSpanVal(td, name) {
  104.                         return parseInt(td.getAttribute(name) || 1);
  105.                 };
  106.  
  107.                 function isCellSelected(cell) {
  108.                         return dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell;
  109.                 };
  110.  
  111.                 function getSelectedRows() {
  112.                         var rows = [];
  113.  
  114.                         each(table.rows, function(row) {
  115.                                 each(row.cells, function(cell) {
  116.                                         if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) {
  117.                                                 rows.push(row);
  118.                                                 return false;
  119.                                         }
  120.                                 });
  121.                         });
  122.  
  123.                         return rows;
  124.                 };
  125.  
  126.                 function deleteTable() {
  127.                         var rng = dom.createRng();
  128.  
  129.                         rng.setStartAfter(table);
  130.                         rng.setEndAfter(table);
  131.  
  132.                         selection.setRng(rng);
  133.  
  134.                         dom.remove(table);
  135.                 };
  136.  
  137.                 function cloneCell(cell) {
  138.                         var formatNode;
  139.  
  140.                         // Clone formats
  141.                         tinymce.walk(cell, function(node) {
  142.                                 var curNode;
  143.  
  144.                                 if (node.nodeType == 3) {
  145.                                         each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
  146.                                                 node = cloneNode(node, false);
  147.  
  148.                                                 if (!formatNode)
  149.                                                         formatNode = curNode = node;
  150.                                                 else if (curNode)
  151.                                                         curNode.appendChild(node);
  152.  
  153.                                                 curNode = node;
  154.                                         });
  155.  
  156.                                         // Add something to the inner node
  157.                                         if (curNode)
  158.                                                 curNode.innerHTML = tinymce.isIE ? ' ' : '<br _mce_bogus="1" />';
  159.  
  160.                                         return false;
  161.                                 }
  162.                         }, 'childNodes');
  163.  
  164.                         cell = cloneNode(cell, false);
  165.                         cell.rowSpan = cell.colSpan = 1;
  166.  
  167.                         if (formatNode) {
  168.                                 cell.appendChild(formatNode);
  169.                         } else {
  170.                                 if (!tinymce.isIE)
  171.                                         cell.innerHTML = '<br _mce_bogus="1" />';
  172.                         }
  173.  
  174.                         return cell;
  175.                 };
  176.  
  177.                 function cleanup() {
  178.                         var rng = dom.createRng();
  179.  
  180.                         // Empty rows
  181.                         each(dom.select('tr', table), function(tr) {
  182.                                 if (tr.cells.length == 0)
  183.                                         dom.remove(tr);
  184.                         });
  185.  
  186.                         // Empty table
  187.                         if (dom.select('tr', table).length == 0) {
  188.                                 rng.setStartAfter(table);
  189.                                 rng.setEndAfter(table);
  190.                                 selection.setRng(rng);
  191.                                 dom.remove(table);
  192.                                 return;
  193.                         }
  194.  
  195.                         // Empty header/body/footer
  196.                         each(dom.select('thead,tbody,tfoot', table), function(part) {
  197.                                 if (part.rows.length == 0)
  198.                                         dom.remove(part);
  199.                         });
  200.  
  201.                         // Restore selection to start position if it still exists
  202.                         buildGrid();
  203.  
  204.                         // Restore the selection to the closest table position
  205.                         row = grid[Math.min(grid.length - 1, startPos.y)];
  206.                         if (row) {
  207.                                 selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
  208.                                 selection.collapse(true);
  209.                         }
  210.                 };
  211.  
  212.                 function fillLeftDown(x, y, rows, cols) {
  213.                         var tr, x2, r, c, cell;
  214.  
  215.                         tr = grid[y][x].elm.parentNode;
  216.                         for (r = 1; r <= rows; r++) {
  217.                                 tr = dom.getNext(tr, 'tr');
  218.  
  219.                                 if (tr) {
  220.                                         // Loop left to find real cell
  221.                                         for (x2 = x; x2 >= 0; x2--) {
  222.                                                 cell = grid[y + r][x2].elm;
  223.  
  224.                                                 if (cell.parentNode == tr) {
  225.                                                         // Append clones after
  226.                                                         for (c = 1; c <= cols; c++)
  227.                                                                 dom.insertAfter(cloneCell(cell), cell);
  228.  
  229.                                                         break;
  230.                                                 }
  231.                                         }
  232.  
  233.                                         if (x2 == -1) {
  234.                                                 // Insert nodes before first cell
  235.                                                 for (c = 1; c <= cols; c++)
  236.                                                         tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
  237.                                         }
  238.                                 }
  239.                         }
  240.                 };
  241.  
  242.                 function split() {
  243.                         each(grid, function(row, y) {
  244.                                 each(row, function(cell, x) {
  245.                                         var colSpan, rowSpan, newCell, i;
  246.  
  247.                                         if (isCellSelected(cell)) {
  248.                                                 cell = cell.elm;
  249.                                                 colSpan = getSpanVal(cell, 'colspan');
  250.                                                 rowSpan = getSpanVal(cell, 'rowspan');
  251.  
  252.                                                 if (colSpan > 1 || rowSpan > 1) {
  253.                                                         cell.colSpan = cell.rowSpan = 1;
  254.  
  255.                                                         // Insert cells right
  256.                                                         for (i = 0; i < colSpan - 1; i++)
  257.                                                                 dom.insertAfter(cloneCell(cell), cell);
  258.  
  259.                                                         fillLeftDown(x, y, rowSpan - 1, colSpan);
  260.                                                 }
  261.                                         }
  262.                                 });
  263.                         });
  264.                 };
  265.  
  266.                 function merge(cell, cols, rows) {
  267.                         var startX, startY, endX, endY, x, y, startCell, endCell, cell, children;
  268.  
  269.                         // Use specified cell and cols/rows
  270.                         if (cell) {
  271.                                 pos = getPos(cell);
  272.                                 startX = pos.x;
  273.                                 startY = pos.y;
  274.                                 endX = startX + (cols - 1);
  275.                                 endY = startY + (rows - 1);
  276.                         } else {
  277.                                 // Use selection
  278.                                 startX = startPos.x;
  279.                                 startY = startPos.y;
  280.                                 endX = endPos.x;
  281.                                 endY = endPos.y;
  282.                         }
  283.  
  284.                         // Find start/end cells
  285.                         startCell = getCell(startX, startY);
  286.                         endCell = getCell(endX, endY);
  287.  
  288.                         // Check if the cells exists and if they are of the same part for example tbody = tbody
  289.                         if (startCell && endCell && startCell.part == endCell.part) {
  290.                                 // Split and rebuild grid
  291.                                 split();
  292.                                 buildGrid();
  293.  
  294.                                 // Set row/col span to start cell
  295.                                 startCell = getCell(startX, startY).elm;
  296.                                 startCell.colSpan = (endX - startX) + 1;
  297.                                 startCell.rowSpan = (endY - startY) + 1;
  298.  
  299.                                 // Remove other cells and add it's contents to the start cell
  300.                                 for (y = startY; y <= endY; y++) {
  301.                                         for (x = startX; x <= endX; x++) {
  302.                                                 cell = grid[y][x].elm;
  303.  
  304.                                                 if (cell != startCell) {
  305.                                                         // Move children to startCell
  306.                                                         children = tinymce.grep(cell.childNodes);
  307.                                                         each(children, function(node, i) {
  308.                                                                 // Jump over last BR element
  309.                                                                 if (node.nodeName != 'BR' || i != children.length - 1)
  310.                                                                         startCell.appendChild(node);
  311.                                                         });
  312.  
  313.                                                         // Remove cell
  314.                                                         dom.remove(cell);
  315.                                                 }
  316.                                         }
  317.                                 }
  318.  
  319.                                 // Remove empty rows etc and restore caret location
  320.                                 cleanup();
  321.                         }
  322.                 };
  323.  
  324.                 function insertRow(before) {
  325.                         var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell;
  326.  
  327.                         // Find first/last row
  328.                         each(grid, function(row, y) {
  329.                                 each(row, function(cell, x) {
  330.                                         if (isCellSelected(cell)) {
  331.                                                 cell = cell.elm;
  332.                                                 rowElm = cell.parentNode;
  333.                                                 newRow = cloneNode(rowElm, false);
  334.                                                 posY = y;
  335.  
  336.                                                 if (before)
  337.                                                         return false;
  338.                                         }
  339.                                 });
  340.  
  341.                                 if (before)
  342.                                         return !posY;
  343.                         });
  344.  
  345.                         for (x = 0; x < grid[0].length; x++) {
  346.                                 cell = grid[posY][x].elm;
  347.  
  348.                                 if (cell != lastCell) {
  349.                                         if (!before) {
  350.                                                 rowSpan = getSpanVal(cell, 'rowspan');
  351.                                                 if (rowSpan > 1) {
  352.                                                         cell.rowSpan = rowSpan + 1;
  353.                                                         continue;
  354.                                                 }
  355.                                         } else {
  356.                                                 // Check if cell above can be expanded
  357.                                                 if (posY > 0 && grid[posY - 1][x]) {
  358.                                                         otherCell = grid[posY - 1][x].elm;
  359.                                                         rowSpan = getSpanVal(otherCell, 'rowspan');
  360.                                                         if (rowSpan > 1) {
  361.                                                                 otherCell.rowSpan = rowSpan + 1;
  362.                                                                 continue;
  363.                                                         }
  364.                                                 }
  365.                                         }
  366.  
  367.                                         // Insert new cell into new row
  368.                                         newCell = cloneCell(cell)
  369.                                         newCell.colSpan = cell.colSpan;
  370.                                         newRow.appendChild(newCell);
  371.  
  372.                                         lastCell = cell;
  373.                                 }
  374.                         }
  375.  
  376.                         if (newRow.hasChildNodes()) {
  377.                                 if (!before)
  378.                                         dom.insertAfter(newRow, rowElm);
  379.                                 else
  380.                                         rowElm.parentNode.insertBefore(newRow, rowElm);
  381.                         }
  382.                 };
  383.  
  384.                 function insertCol(before) {
  385.                         var posX, lastCell;
  386.  
  387.                         // Find first/last column
  388.                         each(grid, function(row, y) {
  389.                                 each(row, function(cell, x) {
  390.                                         if (isCellSelected(cell)) {
  391.                                                 posX = x;
  392.  
  393.                                                 if (before)
  394.                                                         return false;
  395.                                         }
  396.                                 });
  397.  
  398.                                 if (before)
  399.                                         return !posX;
  400.                         });
  401.  
  402.                         each(grid, function(row, y) {
  403.                                 var cell = row[posX].elm, rowSpan, colSpan;
  404.  
  405.                                 if (cell != lastCell) {
  406.                                         colSpan = getSpanVal(cell, 'colspan');
  407.                                         rowSpan = getSpanVal(cell, 'rowspan');
  408.  
  409.                                         if (colSpan == 1) {
  410.                                                 if (!before) {
  411.                                                         dom.insertAfter(cloneCell(cell), cell);
  412.                                                         fillLeftDown(posX, y, rowSpan - 1, colSpan);
  413.                                                 } else {
  414.                                                         cell.parentNode.insertBefore(cloneCell(cell), cell);
  415.                                                         fillLeftDown(posX, y, rowSpan - 1, colSpan);
  416.                                                 }
  417.                                         } else
  418.                                                 cell.colSpan++;
  419.  
  420.                                         lastCell = cell;
  421.                                 }
  422.                         });
  423.                 };
  424.  
  425.                 function deleteCols() {
  426.                         var cols = [];
  427.  
  428.                         // Get selected column indexes
  429.                         each(grid, function(row, y) {
  430.                                 each(row, function(cell, x) {
  431.                                         if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) {
  432.                                                 each(grid, function(row) {
  433.                                                         var cell = row[x].elm, colSpan;
  434.  
  435.                                                         colSpan = getSpanVal(cell, 'colspan');
  436.  
  437.                                                         if (colSpan > 1)
  438.                                                                 cell.colSpan = colSpan - 1;
  439.                                                         else
  440.                                                                 dom.remove(cell);
  441.                                                 });
  442.  
  443.                                                 cols.push(x);
  444.                                         }
  445.                                 });
  446.                         });
  447.  
  448.                         cleanup();
  449.                 };
  450.  
  451.                 function deleteRows() {
  452.                         var rows;
  453.  
  454.                         function deleteRow(tr) {
  455.                                 var nextTr, pos, lastCell;
  456.  
  457.                                 nextTr = dom.getNext(tr, 'tr');
  458.  
  459.                                 // Move down row spanned cells
  460.                                 each(tr.cells, function(cell) {
  461.                                         var rowSpan = getSpanVal(cell, 'rowspan');
  462.  
  463.                                         if (rowSpan > 1) {
  464.                                                 cell.rowSpan = rowSpan - 1;
  465.                                                 pos = getPos(cell);
  466.                                                 fillLeftDown(pos.x, pos.y, 1, 1);
  467.                                         }
  468.                                 });
  469.  
  470.                                 // Delete cells
  471.                                 pos = getPos(tr.cells[0]);
  472.                                 each(grid[pos.y], function(cell) {
  473.                                         var rowSpan;
  474.  
  475.                                         cell = cell.elm;
  476.  
  477.                                         if (cell != lastCell) {
  478.                                                 rowSpan = getSpanVal(cell, 'rowspan');
  479.  
  480.                                                 if (rowSpan <= 1)
  481.                                                         dom.remove(cell);
  482.                                                 else
  483.                                                         cell.rowSpan = rowSpan - 1;
  484.  
  485.                                                 lastCell = cell;
  486.                                         }
  487.                                 });
  488.                         };
  489.  
  490.                         // Get selected rows and move selection out of scope
  491.                         rows = getSelectedRows();
  492.  
  493.                         // Delete all selected rows
  494.                         each(rows.reverse(), function(tr) {
  495.                                 deleteRow(tr);
  496.                         });
  497.  
  498.                         cleanup();
  499.                 };
  500.  
  501.                 function cutRows() {
  502.                         var rows = getSelectedRows();
  503.  
  504.                         dom.remove(rows);
  505.                         cleanup();
  506.  
  507.                         return rows;
  508.                 };
  509.  
  510.                 function copyRows() {
  511.                         var rows = getSelectedRows();
  512.  
  513.                         each(rows, function(row, i) {
  514.                                 rows[i] = cloneNode(row, true);
  515.                         });
  516.  
  517.                         return rows;
  518.                 };
  519.  
  520.                 function pasteRows(rows, before) {
  521.                         var selectedRows = getSelectedRows(),
  522.                                 targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
  523.                                 targetCellCount = targetRow.cells.length;
  524.  
  525.                         // Calc target cell count
  526.                         each(grid, function(row) {
  527.                                 var match;
  528.  
  529.                                 targetCellCount = 0;
  530.                                 each(row, function(cell, x) {
  531.                                         if (cell.real)
  532.                                                 targetCellCount += cell.colspan;
  533.  
  534.                                         if (cell.elm.parentNode == targetRow)
  535.                                                 match = 1;
  536.                                 });
  537.  
  538.                                 if (match)
  539.                                         return false;
  540.                         });
  541.  
  542.                         if (!before)
  543.                                 rows.reverse();
  544.  
  545.                         each(rows, function(row) {
  546.                                 var cellCount = row.cells.length, cell;
  547.  
  548.                                 // Remove col/rowspans
  549.                                 for (i = 0; i < cellCount; i++) {
  550.                                         cell = row.cells[i];
  551.                                         cell.colSpan = cell.rowSpan = 1;
  552.                                 }
  553.  
  554.                                 // Needs more cells
  555.                                 for (i = cellCount; i < targetCellCount; i++)
  556.                                         row.appendChild(cloneCell(row.cells[cellCount - 1]));
  557.  
  558.                                 // Needs less cells
  559.                                 for (i = targetCellCount; i < cellCount; i++)
  560.                                         dom.remove(row.cells[i]);
  561.  
  562.                                 // Add before/after
  563.                                 if (before)
  564.                                         targetRow.parentNode.insertBefore(row, targetRow);
  565.                                 else
  566.                                         dom.insertAfter(row, targetRow);
  567.                         });
  568.                 };
  569.  
  570.                 function getPos(target) {
  571.                         var pos;
  572.  
  573.                         each(grid, function(row, y) {
  574.                                 each(row, function(cell, x) {
  575.                                         if (cell.elm == target) {
  576.                                                 pos = {x : x, y : y};
  577.                                                 return false;
  578.                                         }
  579.                                 });
  580.  
  581.                                 return !pos;
  582.                         });
  583.  
  584.                         return pos;
  585.                 };
  586.  
  587.                 function setStartCell(cell) {
  588.                         startPos = getPos(cell);
  589.                 };
  590.  
  591.                 function findEndPos() {
  592.                         var pos, maxX, maxY;
  593.  
  594.                         maxX = maxY = 0;
  595.  
  596.                         each(grid, function(row, y) {
  597.                                 each(row, function(cell, x) {
  598.                                         var colSpan, rowSpan;
  599.  
  600.                                         if (isCellSelected(cell)) {
  601.                                                 cell = grid[y][x];
  602.  
  603.                                                 if (x > maxX)
  604.                                                         maxX = x;
  605.  
  606.                                                 if (y > maxY)
  607.                                                         maxY = y;
  608.  
  609.                                                 if (cell.real) {
  610.                                                         colSpan = cell.colspan - 1;
  611.                                                         rowSpan = cell.rowspan - 1;
  612.  
  613.                                                         if (colSpan) {
  614.                                                                 if (x + colSpan > maxX)
  615.                                                                         maxX = x + colSpan;
  616.                                                         }
  617.  
  618.                                                         if (rowSpan) {
  619.                                                                 if (y + rowSpan > maxY)
  620.                                                                         maxY = y + rowSpan;
  621.                                                         }
  622.                                                 }
  623.                                         }
  624.                                 });
  625.                         });
  626.  
  627.                         return {x : maxX, y : maxY};
  628.                 };
  629.  
  630.                 function setEndCell(cell) {
  631.                         var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan;
  632.  
  633.                         endPos = getPos(cell);
  634.  
  635.                         if (startPos && endPos) {
  636.                                 // Get start/end positions
  637.                                 startX = Math.min(startPos.x, endPos.x);
  638.                                 startY = Math.min(startPos.y, endPos.y);
  639.                                 endX = Math.max(startPos.x, endPos.x);
  640.                                 endY = Math.max(startPos.y, endPos.y);
  641.  
  642.                                 // Expand end positon to include spans
  643.                                 maxX = endX;
  644.                                 maxY = endY;
  645.  
  646.                                 // Expand startX
  647.                                 for (y = startY; y <= maxY; y++) {
  648.                                         cell = grid[y][startX];
  649.  
  650.                                         if (!cell.real) {
  651.                                                 if (startX - (cell.colspan - 1) < startX)
  652.                                                         startX -= cell.colspan - 1;
  653.                                         }
  654.                                 }
  655.  
  656.                                 // Expand startY
  657.                                 for (x = startX; x <= maxX; x++) {
  658.                                         cell = grid[startY][x];
  659.  
  660.                                         if (!cell.real) {
  661.                                                 if (startY - (cell.rowspan - 1) < startY)
  662.                                                         startY -= cell.rowspan - 1;
  663.                                         }
  664.                                 }
  665.  
  666.                                 // Find max X, Y
  667.                                 for (y = startY; y <= endY; y++) {
  668.                                         for (x = startX; x <= endX; x++) {
  669.                                                 cell = grid[y][x];
  670.  
  671.                                                 if (cell.real) {
  672.                                                         colSpan = cell.colspan - 1;
  673.                                                         rowSpan = cell.rowspan - 1;
  674.  
  675.                                                         if (colSpan) {
  676.                                                                 if (x + colSpan > maxX)
  677.                                                                         maxX = x + colSpan;
  678.                                                         }
  679.  
  680.                                                         if (rowSpan) {
  681.                                                                 if (y + rowSpan > maxY)
  682.                                                                         maxY = y + rowSpan;
  683.                                                         }
  684.                                                 }
  685.                                         }
  686.                                 }
  687.  
  688.                                 // Remove current selection
  689.                                 dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
  690.  
  691.                                 // Add new selection
  692.                                 for (y = startY; y <= maxY; y++) {
  693.                                         for (x = startX; x <= maxX; x++)
  694.                                                 dom.addClass(grid[y][x].elm, 'mceSelected');
  695.                                 }
  696.                         }
  697.                 };
  698.  
  699.                 // Expose to public
  700.                 tinymce.extend(this, {
  701.                         deleteTable : deleteTable,
  702.                         split : split,
  703.                         merge : merge,
  704.                         insertRow : insertRow,
  705.                         insertCol : insertCol,
  706.                         deleteCols : deleteCols,
  707.                         deleteRows : deleteRows,
  708.                         cutRows : cutRows,
  709.                         copyRows : copyRows,
  710.                         pasteRows : pasteRows,
  711.                         getPos : getPos,
  712.                         setStartCell : setStartCell,
  713.                         setEndCell : setEndCell
  714.                 });
  715.         };
  716.  
  717.         tinymce.create('tinymce.plugins.TablePlugin', {
  718.                 init : function(ed, url) {
  719.                         var winMan, clipboardRows;
  720.  
  721.                         function createTableGrid(node) {
  722.                                 var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table');
  723.  
  724.                                 if (tblElm)
  725.                                         return new TableGrid(tblElm, ed.dom, selection);
  726.                         };
  727.  
  728.                         function cleanup() {
  729.                                 // Restore selection possibilities
  730.                                 ed.getBody().style.webkitUserSelect = '';
  731.                                 ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
  732.                         };
  733.  
  734.                         // Register buttons
  735.                         each([
  736.                                 ['table', 'table.desc', 'mceInsertTable', true],
  737.                                 ['delete_table', 'table.del', 'mceTableDelete'],
  738.                                 ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],
  739.                                 ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],
  740.                                 ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],
  741.                                 ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],
  742.                                 ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],
  743.                                 ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],
  744.                                 ['row_props', 'table.row_desc', 'mceTableRowProps', true],
  745.                                 ['cell_props', 'table.cell_desc', 'mceTableCellProps', true],
  746.                                 ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],
  747.                                 ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]
  748.                         ], function(c) {
  749.                                 ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
  750.                         });
  751.  
  752.                         // Select whole table is a table border is clicked
  753.                         if (!tinymce.isIE) {
  754.                                 ed.onClick.add(function(ed, e) {
  755.                                         e = e.target;
  756.  
  757.                                         if (e.nodeName === 'TABLE')
  758.                                                 ed.selection.select(e);
  759.                                 });
  760.                         }
  761.  
  762.                         // Handle node change updates
  763.                         ed.onNodeChange.add(function(ed, cm, n) {
  764.                                 var p;
  765.  
  766.                                 n = ed.selection.getStart();
  767.                                 p = ed.dom.getParent(n, 'td,th,caption');
  768.                                 cm.setActive('table', n.nodeName === 'TABLE' || !!p);
  769.  
  770.                                 // Disable table tools if we are in caption
  771.                                 if (p && p.nodeName === 'CAPTION')
  772.                                         p = 0;
  773.  
  774.                                 cm.setDisabled('delete_table', !p);
  775.                                 cm.setDisabled('delete_col', !p);
  776.                                 cm.setDisabled('delete_table', !p);
  777.                                 cm.setDisabled('delete_row', !p);
  778.                                 cm.setDisabled('col_after', !p);
  779.                                 cm.setDisabled('col_before', !p);
  780.                                 cm.setDisabled('row_after', !p);
  781.                                 cm.setDisabled('row_before', !p);
  782.                                 cm.setDisabled('row_props', !p);
  783.                                 cm.setDisabled('cell_props', !p);
  784.                                 cm.setDisabled('split_cells', !p);
  785.                                 cm.setDisabled('merge_cells', !p);
  786.                         });
  787.  
  788.                         ed.onInit.add(function(ed) {
  789.                                 var startTable, startCell, dom = ed.dom, tableGrid;
  790.  
  791.                                 winMan = ed.windowManager;
  792.  
  793.                                 // Add cell selection logic
  794.                                 ed.onMouseDown.add(function(ed, e) {
  795.                                         if (e.button != 2) {
  796.                                                 cleanup();
  797.  
  798.                                                 startCell = dom.getParent(e.target, 'td,th');
  799.                                                 startTable = dom.getParent(startCell, 'table');
  800.                                         }
  801.                                 });
  802.  
  803.                                 dom.bind(ed.getDoc(), 'mouseover', function(e) {
  804.                                         var sel, table, target = e.target;
  805.  
  806.                                         if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
  807.                                                 table = dom.getParent(target, 'table');
  808.                                                 if (table == startTable) {
  809.                                                         if (!tableGrid) {
  810.                                                                 tableGrid = createTableGrid(table);
  811.                                                                 tableGrid.setStartCell(startCell);
  812.  
  813.                                                                 ed.getBody().style.webkitUserSelect = 'none';
  814.                                                         }
  815.  
  816.                                                         tableGrid.setEndCell(target);
  817.                                                 }
  818.  
  819.                                                 // Remove current selection
  820.                                                 sel = ed.selection.getSel();
  821.  
  822.                                                 if (sel.removeAllRanges)
  823.                                                         sel.removeAllRanges();
  824.                                                 else
  825.                                                         sel.empty();
  826.  
  827.                                                 e.preventDefault();
  828.                                         }
  829.                                 });
  830.  
  831.                                 ed.onMouseUp.add(function(ed, e) {
  832.                                         var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode;
  833.  
  834.                                         // Move selection to startCell
  835.                                         if (startCell) {
  836.                                                 if (tableGrid)
  837.                                                         ed.getBody().style.webkitUserSelect = '';
  838.  
  839.                                                 function setPoint(node, start) {
  840.                                                         var walker = new tinymce.dom.TreeWalker(node, node);
  841.  
  842.                                                         do {
  843.                                                                 // Text node
  844.                                                                 if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {
  845.                                                                         if (start)
  846.                                                                                 rng.setStart(node, 0);
  847.                                                                         else
  848.                                                                                 rng.setEnd(node, node.nodeValue.length);
  849.  
  850.                                                                         return;
  851.                                                                 }
  852.  
  853.                                                                 // BR element
  854.                                                                 if (node.nodeName == 'BR') {
  855.                                                                         if (start)
  856.                                                                                 rng.setStartBefore(node);
  857.                                                                         else
  858.                                                                                 rng.setEndBefore(node);
  859.  
  860.                                                                         return;
  861.                                                                 }
  862.                                                         } while (node = (start ? walker.next() : walker.prev()));
  863.                                                 };
  864.  
  865.                                                 // Try to expand text selection as much as we can only Gecko supports cell selection
  866.                                                 selectedCells = dom.select('td.mceSelected,th.mceSelected');
  867.                                                 if (selectedCells.length > 0) {
  868.                                                         rng = dom.createRng();
  869.                                                         node = selectedCells[0];
  870.                                                         endNode = selectedCells[selectedCells.length - 1];
  871.  
  872.                                                         setPoint(node, 1);
  873.                                                         walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
  874.  
  875.                                                         do {
  876.                                                                 if (node.nodeName == 'TD' || node.nodeName == 'TH') {
  877.                                                                         if (!dom.hasClass(node, 'mceSelected'))
  878.                                                                                 break;
  879.  
  880.                                                                         lastNode = node;
  881.                                                                 }
  882.                                                         } while (node = walker.next());
  883.  
  884.                                                         setPoint(lastNode);
  885.  
  886.                                                         sel.setRng(rng);
  887.                                                 }
  888.  
  889.                                                 ed.nodeChanged();
  890.                                                 startCell = tableGrid = startTable = null;
  891.                                         }
  892.                                 });
  893.  
  894.                                 ed.onKeyUp.add(function(ed, e) {
  895.                                         cleanup();
  896.                                 });
  897.  
  898.                                 // Add context menu
  899.                                 if (ed && ed.plugins.contextmenu) {
  900.                                         ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
  901.                                                 var sm, se = ed.selection, el = se.getNode() || ed.getBody();
  902.  
  903.                                                 if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) {
  904.                                                         m.removeAll();
  905.  
  906.                                                         if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {
  907.                                                                 m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
  908.                                                                 m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
  909.                                                                 m.addSeparator();
  910.                                                         }
  911.  
  912.                                                         if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {
  913.                                                                 m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
  914.                                                                 m.addSeparator();
  915.                                                         }
  916.  
  917.                                                         m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}});
  918.                                                         m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'});
  919.                                                         m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'});
  920.                                                         m.addSeparator();
  921.  
  922.                                                         // Cell menu
  923.                                                         sm = m.addMenu({title : 'table.cell'});
  924.                                                         sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'});
  925.                                                         sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'});
  926.                                                         sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'});
  927.  
  928.                                                         // Row menu
  929.                                                         sm = m.addMenu({title : 'table.row'});
  930.                                                         sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'});
  931.                                                         sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});
  932.                                                         sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});
  933.                                                         sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});
  934.                                                         sm.addSeparator();
  935.                                                         sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});
  936.                                                         sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});
  937.                                                         sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows);
  938.                                                         sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows);
  939.  
  940.                                                         // Column menu
  941.                                                         sm = m.addMenu({title : 'table.col'});
  942.                                                         sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});
  943.                                                         sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});
  944.                                                         sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});
  945.                                                 } else
  946.                                                         m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'});
  947.                                         });
  948.                                 }
  949.  
  950.                                 // Fixes an issue on Gecko where it's impossible to place the caret behind a table
  951.                                 // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
  952.                                 if (!tinymce.isIE) {
  953.                                         function fixTableCaretPos() {
  954.                                                 var last;
  955.  
  956.                                                 // Skip empty text nodes form the end
  957.                                                 for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
  958.  
  959.                                                 if (last && last.nodeName == 'TABLE')
  960.                                                         ed.dom.add(ed.getBody(), 'p', null, '<br mce_bogus="1" />');
  961.                                         };
  962.  
  963.                                         // Fixes an bug where it's impossible to place the caret before a table in Gecko
  964.                                         // this fix solves it by detecting when the caret is at the beginning of such a table
  965.                                         // and then manually moves the caret infront of the table
  966.                                         if (tinymce.isGecko) {
  967.                                                 ed.onKeyDown.add(function(ed, e) {
  968.                                                         var rng, table, dom = ed.dom;
  969.  
  970.                                                         // On gecko it's not possible to place the caret before a table
  971.                                                         if (e.keyCode == 37 || e.keyCode == 38) {
  972.                                                                 rng = ed.selection.getRng();
  973.                                                                 table = dom.getParent(rng.startContainer, 'table');
  974.  
  975.                                                                 if (table && ed.getBody().firstChild == table) {
  976.                                                                         if (isAtStart(rng, table)) {
  977.                                                                                 rng = dom.createRng();
  978.  
  979.                                                                                 rng.setStartBefore(table);
  980.                                                                                 rng.setEndBefore(table);
  981.  
  982.                                                                                 ed.selection.setRng(rng);
  983.  
  984.                                                                                 e.preventDefault();
  985.                                                                         }
  986.                                                                 }
  987.                                                         }
  988.                                                 });
  989.                                         }
  990.  
  991.                                         ed.onKeyUp.add(fixTableCaretPos);
  992.                                         ed.onSetContent.add(fixTableCaretPos);
  993.                                         ed.onVisualAid.add(fixTableCaretPos);
  994.  
  995.                                         ed.onPreProcess.add(function(ed, o) {
  996.                                                 var last = o.node.lastChild;
  997.  
  998.                                                 if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR')
  999.                                                         ed.dom.remove(last);
  1000.                                         });
  1001.  
  1002.                                         fixTableCaretPos();
  1003.                                 }
  1004.                         });
  1005.  
  1006.                         // Register action commands
  1007.                         each({
  1008.                                 mceTableSplitCells : function(grid) {
  1009.                                         grid.split();
  1010.                                 },
  1011.  
  1012.                                 mceTableMergeCells : function(grid) {
  1013.                                         var rowSpan, colSpan, cell;
  1014.  
  1015.                                         cell = ed.dom.getParent(ed.selection.getNode(), 'th,td');
  1016.                                         if (cell) {
  1017.                                                 rowSpan = cell.rowSpan;
  1018.                                                 colSpan = cell.colSpan;
  1019.                                         }
  1020.  
  1021.                                         if (!ed.dom.select('td.mceSelected,th.mceSelected').length) {
  1022.                                                 winMan.open({
  1023.                                                         url : url + '/merge_cells.htm',
  1024.                                                         width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)),
  1025.                                                         height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)),
  1026.                                                         inline : 1
  1027.                                                 }, {
  1028.                                                         rows : rowSpan,
  1029.                                                         cols : colSpan,
  1030.                                                         onaction : function(data) {
  1031.                                                                 grid.merge(cell, data.cols, data.rows);
  1032.                                                         },
  1033.                                                         plugin_url : url
  1034.                                                 });
  1035.                                         } else
  1036.                                                 grid.merge();
  1037.                                 },
  1038.  
  1039.                                 mceTableInsertRowBefore : function(grid) {
  1040.                                         grid.insertRow(true);
  1041.                                 },
  1042.  
  1043.                                 mceTableInsertRowAfter : function(grid) {
  1044.                                         grid.insertRow();
  1045.                                 },
  1046.  
  1047.                                 mceTableInsertColBefore : function(grid) {
  1048.                                         grid.insertCol(true);
  1049.                                 },
  1050.  
  1051.                                 mceTableInsertColAfter : function(grid) {
  1052.                                         grid.insertCol();
  1053.                                 },
  1054.  
  1055.                                 mceTableDeleteCol : function(grid) {
  1056.                                         grid.deleteCols();
  1057.                                 },
  1058.  
  1059.                                 mceTableDeleteRow : function(grid) {
  1060.                                         grid.deleteRows();
  1061.                                 },
  1062.  
  1063.                                 mceTableCutRow : function(grid) {
  1064.                                         clipboardRows = grid.cutRows();
  1065.                                 },
  1066.  
  1067.                                 mceTableCopyRow : function(grid) {
  1068.                                         clipboardRows = grid.copyRows();
  1069.                                 },
  1070.  
  1071.                                 mceTablePasteRowBefore : function(grid) {
  1072.                                         grid.pasteRows(clipboardRows, true);
  1073.                                 },
  1074.  
  1075.                                 mceTablePasteRowAfter : function(grid) {
  1076.                                         grid.pasteRows(clipboardRows);
  1077.                                 },
  1078.  
  1079.                                 mceTableDelete : function(grid) {
  1080.                                         grid.deleteTable();
  1081.                                 }
  1082.                         }, function(func, name) {
  1083.                                 ed.addCommand(name, function() {
  1084.                                         var grid = createTableGrid();
  1085.  
  1086.                                         if (grid) {
  1087.                                                 func(grid);
  1088.                                                 ed.execCommand('mceRepaint');
  1089.                                                 cleanup();
  1090.                                         }
  1091.                                 });
  1092.                         });
  1093.  
  1094.                         // Register dialog commands
  1095.                         each({
  1096.                                 mceInsertTable : function(val) {
  1097.                                         winMan.open({
  1098.                                                 url : url + '/table.htm',
  1099.                                                 width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)),
  1100.                                                 height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)),
  1101.                                                 inline : 1
  1102.                                         }, {
  1103.                                                 plugin_url : url,
  1104.                                                 action : val ? val.action : 0
  1105.                                         });
  1106.                                 },
  1107.  
  1108.                                 mceTableRowProps : function() {
  1109.                                         winMan.open({
  1110.                                                 url : url + '/row.htm',
  1111.                                                 width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)),
  1112.                                                 height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)),
  1113.                                                 inline : 1
  1114.                                         }, {
  1115.                                                 plugin_url : url
  1116.                                         });
  1117.                                 },
  1118.  
  1119.                                 mceTableCellProps : function() {
  1120.                                         winMan.open({
  1121.                                                 url : url + '/cell.htm',
  1122.                                                 width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)),
  1123.                                                 height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)),
  1124.                                                 inline : 1
  1125.                                         }, {
  1126.                                                 plugin_url : url
  1127.                                         });
  1128.                                 }
  1129.                         }, function(func, name) {
  1130.                                 ed.addCommand(name, function(ui, val) {
  1131.                                         func(val);
  1132.                                 });
  1133.                         });
  1134.                 }
  1135.         });
  1136.  
  1137.         // Register plugin
  1138.         tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
  1139. })(tinymce);

Paste is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.