Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** editor_plugin_src.js** Copyright 2009, Moxiecode Systems AB* Released under LGPL License.** License: http://tinymce.moxiecode.com/license* Contributing: http://tinymce.moxiecode.com/contributing*/(function(tinymce) {var each = tinymce.each;// Checks if the selection/caret is at the start of the specified block elementfunction isAtStart(rng, par) {var doc = par.ownerDocument, rng2 = doc.createRange(), elm;rng2.setStartBefore(par);rng2.setEnd(rng.endContainer, rng.endOffset);elm = doc.createElement('body');elm.appendChild(rng2.cloneContents());// Check for text characters of other elements that should be treated as contentreturn elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0;};function getSpanVal(td, name) {return parseInt(td.getAttribute(name) || 1);}/*** Table Grid class.*/function TableGrid(table, dom, selection) {var grid, startPos, endPos, selectedCell;buildGrid();selectedCell = dom.getParent(selection.getStart(), 'th,td');if (selectedCell) {startPos = getPos(selectedCell);endPos = findEndPos();selectedCell = getCell(startPos.x, startPos.y);}function cloneNode(node, children) {node = node.cloneNode(children);node.removeAttribute('id');return node;}function buildGrid() {var startY = 0;grid = [];each(['thead', 'tbody', 'tfoot'], function(part) {var rows = dom.select('> ' + part + ' tr', table);each(rows, function(tr, y) {y += startY;each(dom.select('> td, > th', tr), function(td, x) {var x2, y2, rowspan, colspan;// Skip over existing cells produced by rowspanif (grid[y]) {while (grid[y][x])x++;}// Get col/rowspan from cellrowspan = getSpanVal(td, 'rowspan');colspan = getSpanVal(td, 'colspan');// Fill out rowspan/colspan right and downfor (y2 = y; y2 < y + rowspan; y2++) {if (!grid[y2])grid[y2] = [];for (x2 = x; x2 < x + colspan; x2++) {grid[y2][x2] = {part : part,real : y2 == y && x2 == x,elm : td,rowspan : rowspan,colspan : colspan};}}});});startY += rows.length;});};function getCell(x, y) {var row;row = grid[y];if (row)return row[x];};function setSpanVal(td, name, val) {if (td) {val = parseInt(val);if (val === 1)td.removeAttribute(name, 1);elsetd.setAttribute(name, val, 1);}}function isCellSelected(cell) {return cell && (dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell);};function getSelectedRows() {var rows = [];each(table.rows, function(row) {each(row.cells, function(cell) {if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) {rows.push(row);return false;}});});return rows;};function deleteTable() {var rng = dom.createRng();rng.setStartAfter(table);rng.setEndAfter(table);selection.setRng(rng);dom.remove(table);};function cloneCell(cell) {var formatNode;// Clone formatstinymce.walk(cell, function(node) {var curNode;if (node.nodeType == 3) {each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {node = cloneNode(node, false);if (!formatNode)formatNode = curNode = node;else if (curNode)curNode.appendChild(node);curNode = node;});// Add something to the inner nodeif (curNode)curNode.innerHTML = tinymce.isIE ? ' ' : '<br data-mce-bogus="1" />';return false;}}, 'childNodes');cell = cloneNode(cell, false);setSpanVal(cell, 'rowSpan', 1);setSpanVal(cell, 'colSpan', 1);if (formatNode) {cell.appendChild(formatNode);} else {if (!tinymce.isIE)cell.innerHTML = '<br data-mce-bogus="1" />';}return cell;};function cleanup() {var rng = dom.createRng();// Empty rowseach(dom.select('tr', table), function(tr) {if (tr.cells.length == 0)dom.remove(tr);});// Empty tableif (dom.select('tr', table).length == 0) {rng.setStartAfter(table);rng.setEndAfter(table);selection.setRng(rng);dom.remove(table);return;}// Empty header/body/footereach(dom.select('thead,tbody,tfoot', table), function(part) {if (part.rows.length == 0)dom.remove(part);});// Restore selection to start position if it still existsbuildGrid();// Restore the selection to the closest table positionrow = grid[Math.min(grid.length - 1, startPos.y)];if (row) {selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);selection.collapse(true);}};function fillLeftDown(x, y, rows, cols) {var tr, x2, r, c, cell;tr = grid[y][x].elm.parentNode;for (r = 1; r <= rows; r++) {tr = dom.getNext(tr, 'tr');if (tr) {// Loop left to find real cellfor (x2 = x; x2 >= 0; x2--) {cell = grid[y + r][x2].elm;if (cell.parentNode == tr) {// Append clones afterfor (c = 1; c <= cols; c++)dom.insertAfter(cloneCell(cell), cell);break;}}if (x2 == -1) {// Insert nodes before first cellfor (c = 1; c <= cols; c++)tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);}}}};function split() {each(grid, function(row, y) {each(row, function(cell, x) {var colSpan, rowSpan, newCell, i;if (isCellSelected(cell)) {cell = cell.elm;colSpan = getSpanVal(cell, 'colspan');rowSpan = getSpanVal(cell, 'rowspan');if (colSpan > 1 || rowSpan > 1) {setSpanVal(cell, 'rowSpan', 1);setSpanVal(cell, 'colSpan', 1);// Insert cells rightfor (i = 0; i < colSpan - 1; i++)dom.insertAfter(cloneCell(cell), cell);fillLeftDown(x, y, rowSpan - 1, colSpan);}}});});};function merge(cell, cols, rows) {var startX, startY, endX, endY, x, y, startCell, endCell, cell, children, count;// Use specified cell and cols/rowsif (cell) {pos = getPos(cell);startX = pos.x;startY = pos.y;endX = startX + (cols - 1);endY = startY + (rows - 1);} else {// Use selectionstartX = startPos.x;startY = startPos.y;endX = endPos.x;endY = endPos.y;}// Find start/end cellsstartCell = getCell(startX, startY);endCell = getCell(endX, endY);// Check if the cells exists and if they are of the same part for example tbody = tbodyif (startCell && endCell && startCell.part == endCell.part) {// Split and rebuild gridsplit();buildGrid();// Set row/col span to start cellstartCell = getCell(startX, startY).elm;setSpanVal(startCell, 'colSpan', (endX - startX) + 1);setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);// Remove other cells and add it's contents to the start cellfor (y = startY; y <= endY; y++) {for (x = startX; x <= endX; x++) {if (!grid[y] || !grid[y][x])continue;cell = grid[y][x].elm;if (cell != startCell) {// Move children to startCellchildren = tinymce.grep(cell.childNodes);each(children, function(node) {startCell.appendChild(node);});// Remove bogus nodes if there is children in the target cellif (children.length) {children = tinymce.grep(startCell.childNodes);count = 0;each(children, function(node) {if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1)startCell.removeChild(node);});}// Remove celldom.remove(cell);}}}// Remove empty rows etc and restore caret locationcleanup();}};function insertRow(before) {var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;// Find first/last roweach(grid, function(row, y) {each(row, function(cell, x) {if (isCellSelected(cell)) {cell = cell.elm;rowElm = cell.parentNode;newRow = cloneNode(rowElm, false);posY = y;if (before)return false;}});if (before)return !posY;});for (x = 0; x < grid[0].length; x++) {// Cell not found could be because of an invalid table structureif (!grid[posY][x])continue;cell = grid[posY][x].elm;if (cell != lastCell) {if (!before) {rowSpan = getSpanVal(cell, 'rowspan');if (rowSpan > 1) {setSpanVal(cell, 'rowSpan', rowSpan + 1);continue;}} else {// Check if cell above can be expandedif (posY > 0 && grid[posY - 1][x]) {otherCell = grid[posY - 1][x].elm;rowSpan = getSpanVal(otherCell, 'rowSpan');if (rowSpan > 1) {setSpanVal(otherCell, 'rowSpan', rowSpan + 1);continue;}}}// Insert new cell into new rownewCell = cloneCell(cell);setSpanVal(newCell, 'colSpan', cell.colSpan);newRow.appendChild(newCell);lastCell = cell;}}if (newRow.hasChildNodes()) {if (!before)dom.insertAfter(newRow, rowElm);elserowElm.parentNode.insertBefore(newRow, rowElm);}};function insertCol(before) {var posX, lastCell;// Find first/last columneach(grid, function(row, y) {each(row, function(cell, x) {if (isCellSelected(cell)) {posX = x;if (before)return false;}});if (before)return !posX;});each(grid, function(row, y) {var cell, rowSpan, colSpan;if (!row[posX])return;cell = row[posX].elm;if (cell != lastCell) {colSpan = getSpanVal(cell, 'colspan');rowSpan = getSpanVal(cell, 'rowspan');if (colSpan == 1) {if (!before) {dom.insertAfter(cloneCell(cell), cell);fillLeftDown(posX, y, rowSpan - 1, colSpan);} else {cell.parentNode.insertBefore(cloneCell(cell), cell);fillLeftDown(posX, y, rowSpan - 1, colSpan);}} elsesetSpanVal(cell, 'colSpan', cell.colSpan + 1);lastCell = cell;}});};function deleteCols() {var cols = [];// Get selected column indexeseach(grid, function(row, y) {each(row, function(cell, x) {if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) {each(grid, function(row) {var cell = row[x].elm, colSpan;colSpan = getSpanVal(cell, 'colSpan');if (colSpan > 1)setSpanVal(cell, 'colSpan', colSpan - 1);elsedom.remove(cell);});cols.push(x);}});});cleanup();};function deleteRows() {var rows;function deleteRow(tr) {var nextTr, pos, lastCell;nextTr = dom.getNext(tr, 'tr');// Move down row spanned cellseach(tr.cells, function(cell) {var rowSpan = getSpanVal(cell, 'rowSpan');if (rowSpan > 1) {setSpanVal(cell, 'rowSpan', rowSpan - 1);pos = getPos(cell);fillLeftDown(pos.x, pos.y, 1, 1);}});// Delete cellspos = getPos(tr.cells[0]);each(grid[pos.y], function(cell) {var rowSpan;cell = cell.elm;if (cell != lastCell) {rowSpan = getSpanVal(cell, 'rowSpan');if (rowSpan <= 1)dom.remove(cell);elsesetSpanVal(cell, 'rowSpan', rowSpan - 1);lastCell = cell;}});};// Get selected rows and move selection out of scoperows = getSelectedRows();// Delete all selected rowseach(rows.reverse(), function(tr) {deleteRow(tr);});cleanup();};function cutRows() {var rows = getSelectedRows();dom.remove(rows);cleanup();return rows;};function copyRows() {var rows = getSelectedRows();each(rows, function(row, i) {rows[i] = cloneNode(row, true);});return rows;};function pasteRows(rows, before) {var selectedRows = getSelectedRows(),targetRow = selectedRows[before ? 0 : selectedRows.length - 1],targetCellCount = targetRow.cells.length;// Calc target cell counteach(grid, function(row) {var match;targetCellCount = 0;each(row, function(cell, x) {if (cell.real)targetCellCount += cell.colspan;if (cell.elm.parentNode == targetRow)match = 1;});if (match)return false;});if (!before)rows.reverse();each(rows, function(row) {var cellCount = row.cells.length, cell;// Remove col/rowspansfor (i = 0; i < cellCount; i++) {cell = row.cells[i];setSpanVal(cell, 'colSpan', 1);setSpanVal(cell, 'rowSpan', 1);}// Needs more cellsfor (i = cellCount; i < targetCellCount; i++)row.appendChild(cloneCell(row.cells[cellCount - 1]));// Needs less cellsfor (i = targetCellCount; i < cellCount; i++)dom.remove(row.cells[i]);// Add before/afterif (before)targetRow.parentNode.insertBefore(row, targetRow);elsedom.insertAfter(row, targetRow);});};function getPos(target) {var pos;each(grid, function(row, y) {each(row, function(cell, x) {if (cell.elm == target) {pos = {x : x, y : y};return false;}});return !pos;});return pos;};function setStartCell(cell) {startPos = getPos(cell);};function findEndPos() {var pos, maxX, maxY;maxX = maxY = 0;each(grid, function(row, y) {each(row, function(cell, x) {var colSpan, rowSpan;if (isCellSelected(cell)) {cell = grid[y][x];if (x > maxX)maxX = x;if (y > maxY)maxY = y;if (cell.real) {colSpan = cell.colspan - 1;rowSpan = cell.rowspan - 1;if (colSpan) {if (x + colSpan > maxX)maxX = x + colSpan;}if (rowSpan) {if (y + rowSpan > maxY)maxY = y + rowSpan;}}}});});return {x : maxX, y : maxY};};function setEndCell(cell) {var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan;endPos = getPos(cell);if (startPos && endPos) {// Get start/end positionsstartX = Math.min(startPos.x, endPos.x);startY = Math.min(startPos.y, endPos.y);endX = Math.max(startPos.x, endPos.x);endY = Math.max(startPos.y, endPos.y);// Expand end positon to include spansmaxX = endX;maxY = endY;// Expand startXfor (y = startY; y <= maxY; y++) {cell = grid[y][startX];if (!cell.real) {if (startX - (cell.colspan - 1) < startX)startX -= cell.colspan - 1;}}// Expand startYfor (x = startX; x <= maxX; x++) {cell = grid[startY][x];if (!cell.real) {if (startY - (cell.rowspan - 1) < startY)startY -= cell.rowspan - 1;}}// Find max X, Yfor (y = startY; y <= endY; y++) {for (x = startX; x <= endX; x++) {cell = grid[y][x];if (cell.real) {colSpan = cell.colspan - 1;rowSpan = cell.rowspan - 1;if (colSpan) {if (x + colSpan > maxX)maxX = x + colSpan;}if (rowSpan) {if (y + rowSpan > maxY)maxY = y + rowSpan;}}}}// Remove current selectiondom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');// Add new selectionfor (y = startY; y <= maxY; y++) {for (x = startX; x <= maxX; x++) {if (grid[y][x])dom.addClass(grid[y][x].elm, 'mceSelected');}}}};// Expose to publictinymce.extend(this, {deleteTable : deleteTable,split : split,merge : merge,insertRow : insertRow,insertCol : insertCol,deleteCols : deleteCols,deleteRows : deleteRows,cutRows : cutRows,copyRows : copyRows,pasteRows : pasteRows,getPos : getPos,setStartCell : setStartCell,setEndCell : setEndCell});};tinymce.create('tinymce.plugins.TablePlugin', {init : function(ed, url) {var winMan, clipboardRows, hasCellSelection = true; // Might be selected cells on reloadfunction createTableGrid(node) {var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table');if (tblElm)return new TableGrid(tblElm, ed.dom, selection);};function cleanup() {// Restore selection possibilitiesed.getBody().style.webkitUserSelect = '';if (hasCellSelection) {ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');hasCellSelection = false;}};// Register buttonseach([['table', 'table.desc', 'mceInsertTable', true],['delete_table', 'table.del', 'mceTableDelete'],['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],['row_props', 'table.row_desc', 'mceTableRowProps', true],['cell_props', 'table.cell_desc', 'mceTableCellProps', true],['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]], function(c) {ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});});// Select whole table is a table border is clickedif (!tinymce.isIE) {ed.onClick.add(function(ed, e) {e = e.target;if (e.nodeName === 'TABLE') {ed.selection.select(e);ed.nodeChanged();}});}ed.onPreProcess.add(function(ed, args) {var nodes, i, node, dom = ed.dom, value;nodes = dom.select('table', args.node);i = nodes.length;while (i--) {node = nodes[i];dom.setAttrib(node, 'data-mce-style', '');if ((value = dom.getAttrib(node, 'width'))) {dom.setStyle(node, 'width', value);dom.setAttrib(node, 'width', '');}if ((value = dom.getAttrib(node, 'height'))) {dom.setStyle(node, 'height', value);dom.setAttrib(node, 'height', '');}}});// Handle node change updatesed.onNodeChange.add(function(ed, cm, n) {var p;n = ed.selection.getStart();p = ed.dom.getParent(n, 'td,th,caption');cm.setActive('table', n.nodeName === 'TABLE' || !!p);// Disable table tools if we are in captionif (p && p.nodeName === 'CAPTION')p = 0;cm.setDisabled('delete_table', !p);cm.setDisabled('delete_col', !p);cm.setDisabled('delete_table', !p);cm.setDisabled('delete_row', !p);cm.setDisabled('col_after', !p);cm.setDisabled('col_before', !p);cm.setDisabled('row_after', !p);cm.setDisabled('row_before', !p);cm.setDisabled('row_props', !p);cm.setDisabled('cell_props', !p);cm.setDisabled('split_cells', !p);cm.setDisabled('merge_cells', !p);});ed.onInit.add(function(ed) {var startTable, startCell, dom = ed.dom, tableGrid;winMan = ed.windowManager;// Add cell selection logiced.onMouseDown.add(function(ed, e) {if (e.button != 2) {cleanup();startCell = dom.getParent(e.target, 'td,th');startTable = dom.getParent(startCell, 'table');}});dom.bind(ed.getDoc(), 'mouseover', function(e) {var sel, table, target = e.target;if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {table = dom.getParent(target, 'table');if (table == startTable) {if (!tableGrid) {tableGrid = createTableGrid(table);tableGrid.setStartCell(startCell);ed.getBody().style.webkitUserSelect = 'none';}tableGrid.setEndCell(target);hasCellSelection = true;}// Remove current selectionsel = ed.selection.getSel();try {if (sel.removeAllRanges)sel.removeAllRanges();elsesel.empty();} catch (ex) {// IE9 might throw errors here}e.preventDefault();}});ed.onMouseUp.add(function(ed, e) {var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode;// Move selection to startCellif (startCell) {if (tableGrid)ed.getBody().style.webkitUserSelect = '';function setPoint(node, start) {var walker = new tinymce.dom.TreeWalker(node, node);do {// Text nodeif (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {if (start)rng.setStart(node, 0);elserng.setEnd(node, node.nodeValue.length);return;}// BR elementif (node.nodeName == 'BR') {if (start)rng.setStartBefore(node);elserng.setEndBefore(node);return;}} while (node = (start ? walker.next() : walker.prev()));}// Try to expand text selection as much as we can only Gecko supports cell selectionselectedCells = dom.select('td.mceSelected,th.mceSelected');if (selectedCells.length > 0) {rng = dom.createRng();node = selectedCells[0];endNode = selectedCells[selectedCells.length - 1];rng.setStartBefore(node);rng.setEndAfter(node);setPoint(node, 1);walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table'));do {if (node.nodeName == 'TD' || node.nodeName == 'TH') {if (!dom.hasClass(node, 'mceSelected'))break;lastNode = node;}} while (node = walker.next());setPoint(lastNode);sel.setRng(rng);}ed.nodeChanged();startCell = tableGrid = startTable = null;}});ed.onKeyUp.add(function(ed, e) {cleanup();});ed.onKeyDown.add(function (ed, e) {fixTableCellSelection(ed);});ed.onMouseDown.add(function (ed, e) {if (e.button != 2) {fixTableCellSelection(ed);}});function tableCellSelected(ed, rng, n, currentCell) {// The decision of when a table cell is selected is somewhat involved. The fact that this code is// required is actually a pointer to the root cause of this bug. A cell is selected when the start// and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)// or the parent of the table (in the case of the selection containing the last cell of a table).var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE'),tableParent, allOfCellSelected, tableCellSelection;if (table)tableParent = table.parentNode;allOfCellSelected =rng.startContainer.nodeType == TEXT_NODE &&rng.startOffset == 0 &&rng.endOffset == 0 &¤tCell &&(n.nodeName=="TR" || n==tableParent);tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell;return allOfCellSelected || tableCellSelection;// return false;}// this nasty hack is here to work around some WebKit selection bugs.function fixTableCellSelection(ed) {if (!tinymce.isWebKit)return;var rng = ed.selection.getRng();var n = ed.selection.getNode();var currentCell = ed.dom.getParent(rng.startContainer, 'TD');if (!tableCellSelected(ed, rng, n, currentCell))return;if (!currentCell) {currentCell=n;}// Get the very last node inside the table cellvar end = currentCell.lastChild;while (end.lastChild)end = end.lastChild;// Select the entire table cell. Nothing outside of the table cell should be selected.rng.setEnd(end, end.nodeValue.length);ed.selection.setRng(rng);}ed.plugins.table.fixTableCellSelection=fixTableCellSelection;// Add context menuif (ed && ed.plugins.contextmenu) {ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {var sm, se = ed.selection, el = se.getNode() || ed.getBody();if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) {m.removeAll();if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});m.addSeparator();}if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});m.addSeparator();}m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}});m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'});m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'});m.addSeparator();// Cell menusm = m.addMenu({title : 'table.cell'});sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'});sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'});sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'});// Row menusm = m.addMenu({title : 'table.row'});sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'});sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});sm.addSeparator();sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows);sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows);// Column menusm = m.addMenu({title : 'table.col'});sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});} elsem.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'});});}// Fix to allow navigating up and down in a table in WebKit browsers.if (tinymce.isWebKit) {function moveSelection(ed, e) {function moveCursorToStartOfElement(n) {ed.selection.setCursorLocation(n, 0);}function getSibling(event, element) {return event.keyCode == UP_ARROW ? element.previousSibling : element.nextSibling;}function getNextRow(e, row) {var sibling = getSibling(e, row);return sibling !== null && sibling.tagName === 'TR' ? sibling : null;}function getTable(ed, currentRow) {return ed.dom.getParent(currentRow, 'table');}function getTableSibling(currentRow) {var table = getTable(ed, currentRow);return getSibling(e, table);}function isVerticalMovement(event) {return event.keyCode == UP_ARROW || event.keyCode == DOWN_ARROW;}function isInTable(ed) {var node = ed.selection.getNode();var currentRow = ed.dom.getParent(node, 'tr');return currentRow !== null;}function columnIndex(column) {var colIndex = 0;var c = column;while (c.previousSibling) {c = c.previousSibling;colIndex = colIndex + getSpanVal(c, "colspan");}return colIndex;}function findColumn(rowElement, columnIndex) {var c = 0;var r = 0;each(rowElement.children, function(cell, i) {c = c + getSpanVal(cell, "colspan");r = i;if (c > columnIndex)return false;});return r;}function moveCursorToRow(ed, node, row) {var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th'));var tgtColumnIndex = findColumn(row, srcColumnIndex)var tgtNode = row.childNodes[tgtColumnIndex];moveCursorToStartOfElement(tgtNode);}function escapeTable(currentRow, e) {var tableSiblingElement = getTableSibling(currentRow);if (tableSiblingElement !== null) {moveCursorToStartOfElement(tableSiblingElement);return tinymce.dom.Event.cancel(e);} else {var element = e.keyCode == UP_ARROW ? currentRow.firstChild : currentRow.lastChild;// rely on default behaviour to escape table after we are in the last cell of the last rowmoveCursorToStartOfElement(element);return true;}}var UP_ARROW = 38;var DOWN_ARROW = 40;if (isVerticalMovement(e) && isInTable(ed)) {var node = ed.selection.getNode();var currentRow = ed.dom.getParent(node, 'tr');var nextRow = getNextRow(e, currentRow);// If we're at the first or last row in the table, we should move the caret outside of the tableif (nextRow == null) {return escapeTable(currentRow, e);} else {moveCursorToRow(ed, node, nextRow);tinymce.dom.Event.cancel(e);return true;}}}ed.onKeyDown.add(moveSelection);}// Fixes an issue on Gecko where it's impossible to place the caret behind a table// This fix will force a paragraph element after the table but only when the forced_root_block setting is enabledif (!tinymce.isIE) {function fixTableCaretPos() {var last;// Skip empty text nodes form the endfor (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;if (last && last.nodeName == 'TABLE')ed.dom.add(ed.getBody(), 'p', null, '<br mce_bogus="1" />');};// Fixes an bug where it's impossible to place the caret before a table in Gecko// this fix solves it by detecting when the caret is at the beginning of such a table// and then manually moves the caret infront of the tableif (tinymce.isGecko) {ed.onKeyDown.add(function(ed, e) {var rng, table, dom = ed.dom;// On gecko it's not possible to place the caret before a tableif (e.keyCode == 37 || e.keyCode == 38) {rng = ed.selection.getRng();table = dom.getParent(rng.startContainer, 'table');if (table && ed.getBody().firstChild == table) {if (isAtStart(rng, table)) {rng = dom.createRng();rng.setStartBefore(table);rng.setEndBefore(table);ed.selection.setRng(rng);e.preventDefault();}}}});}ed.onKeyUp.add(fixTableCaretPos);ed.onSetContent.add(fixTableCaretPos);ed.onVisualAid.add(fixTableCaretPos);ed.onPreProcess.add(function(ed, o) {var last = o.node.lastChild;if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR')ed.dom.remove(last);});fixTableCaretPos();ed.startContent = ed.getContent({format : 'raw'});}});// Register action commandseach({mceTableSplitCells : function(grid) {grid.split();},mceTableMergeCells : function(grid) {var rowSpan, colSpan, cell;cell = ed.dom.getParent(ed.selection.getNode(), 'th,td');if (cell) {rowSpan = cell.rowSpan;colSpan = cell.colSpan;}if (!ed.dom.select('td.mceSelected,th.mceSelected').length) {winMan.open({url : url + '/merge_cells.htm',width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)),height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)),inline : 1}, {rows : rowSpan,cols : colSpan,onaction : function(data) {grid.merge(cell, data.cols, data.rows);},plugin_url : url});} elsegrid.merge();},mceTableInsertRowBefore : function(grid) {grid.insertRow(true);},mceTableInsertRowAfter : function(grid) {grid.insertRow();},mceTableInsertColBefore : function(grid) {grid.insertCol(true);},mceTableInsertColAfter : function(grid) {grid.insertCol();},mceTableDeleteCol : function(grid) {grid.deleteCols();},mceTableDeleteRow : function(grid) {grid.deleteRows();},mceTableCutRow : function(grid) {clipboardRows = grid.cutRows();},mceTableCopyRow : function(grid) {clipboardRows = grid.copyRows();},mceTablePasteRowBefore : function(grid) {grid.pasteRows(clipboardRows, true);},mceTablePasteRowAfter : function(grid) {grid.pasteRows(clipboardRows);},mceTableDelete : function(grid) {grid.deleteTable();}}, function(func, name) {ed.addCommand(name, function() {var grid = createTableGrid();if (grid) {func(grid);ed.execCommand('mceRepaint');cleanup();}});});// Register dialog commandseach({mceInsertTable : function(val) {winMan.open({url : url + '/table.htm',width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)),height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)),inline : 1}, {plugin_url : url,action : val ? val.action : 0});},mceTableRowProps : function() {winMan.open({url : url + '/row.htm',width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)),height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)),inline : 1}, {plugin_url : url});},mceTableCellProps : function() {winMan.open({url : url + '/cell.htm',width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)),height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)),inline : 1}, {plugin_url : url});}}, function(func, name) {ed.addCommand(name, function(ui, val) {func(val);});});}});// Register plugintinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);})(tinymce);