| | |
| | | /**
|
| | | * $Id: editor_plugin_src.js 768 2008-04-04 13:52:49Z spocke $
|
| | | * $Id: editor_plugin_src.js 1209 2009-08-20 12:35:10Z spocke $
|
| | | *
|
| | | * @author Moxiecode
|
| | | * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.
|
| | |
| | |
|
| | | (function() {
|
| | | var each = tinymce.each;
|
| | |
|
| | | // Checks if the selection/caret is at the start of the specified block element
|
| | | function 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 content
|
| | | return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0;
|
| | | };
|
| | |
|
| | | tinymce.create('tinymce.plugins.TablePlugin', {
|
| | | init : function(ed, url) {
|
| | |
| | | ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
|
| | | });
|
| | |
|
| | | if (ed.getParam('inline_styles')) {
|
| | | // Force move of attribs to styles in strict mode
|
| | | ed.onPreProcess.add(function(ed, o) {
|
| | | var dom = ed.dom;
|
| | |
|
| | | each(dom.select('table', o.node), function(n) {
|
| | | var v;
|
| | |
|
| | | if (v = dom.getAttrib(n, 'width')) {
|
| | | dom.setStyle(n, 'width', v);
|
| | | dom.setAttrib(n, 'width');
|
| | | }
|
| | |
|
| | | if (v = dom.getAttrib(n, 'height')) {
|
| | | dom.setStyle(n, 'height', v);
|
| | | dom.setAttrib(n, 'height');
|
| | | }
|
| | | });
|
| | | });
|
| | | }
|
| | |
|
| | | ed.onInit.add(function() {
|
| | | // 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 enabled
|
| | | if (!tinymce.isIE && ed.getParam('forced_root_block')) {
|
| | | function fixTableCaretPos() {
|
| | | var last = ed.getBody().lastChild;
|
| | |
|
| | | 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 table
|
| | | if (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 table
|
| | | if (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();
|
| | | }
|
| | |
|
| | | if (ed && ed.plugins.contextmenu) {
|
| | | ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
|
| | | var sm, se = ed.selection, el = se.getNode() || ed.getBody();
|
| | |
| | |
|
| | | // Add undo level when new rows are created using the tab key
|
| | | ed.onKeyDown.add(function(ed, e) {
|
| | | if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE'))
|
| | | if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE')) {
|
| | | if (!tinymce.isGecko && !tinymce.isOpera) {
|
| | | tinyMCE.execInstanceCommand(ed.editorId, "mceTableMoveToNextRow", true);
|
| | | return tinymce.dom.Event.cancel(e);
|
| | | }
|
| | |
|
| | | ed.undoManager.add();
|
| | | }
|
| | | });
|
| | |
|
| | | // Select whole table is a table border is clicked
|
| | | if (!tinymce.isIE) {
|
| | | if (ed.getParam('table_selection', true)) {
|
| | | ed.onClick.add(function(ed, e) {
|
| | | e = e.target;
|
| | |
|
| | | if (e.nodeName === 'TABLE')
|
| | | ed.selection.select(e);
|
| | | });
|
| | | }
|
| | | }
|
| | |
|
| | | ed.onNodeChange.add(function(ed, cm, n) {
|
| | | var p = ed.dom.getParent(n, 'td,th,caption');
|
| | |
|
| | | cm.setActive('table', !!p);
|
| | | cm.setActive('table', n.nodeName === 'TABLE' || !!p);
|
| | | if (p && p.nodeName === 'CAPTION')
|
| | | p = null;
|
| | |
|
| | |
| | |
|
| | | // Is table command
|
| | | switch (cmd) {
|
| | | case "mceTableMoveToNextRow":
|
| | | case "mceInsertTable":
|
| | | case "mceTableRowProps":
|
| | | case "mceTableCellProps":
|
| | |
| | | return grid[row][col];
|
| | |
|
| | | return null;
|
| | | }
|
| | |
|
| | | function getNextCell(table, cell) {
|
| | | var cells = [], x = 0, i, j, cell, nextCell;
|
| | |
|
| | | for (i = 0; i < table.rows.length; i++)
|
| | | for (j = 0; j < table.rows[i].cells.length; j++, x++)
|
| | | cells[x] = table.rows[i].cells[j];
|
| | |
|
| | | for (i = 0; i < cells.length; i++)
|
| | | if (cells[i] == cell)
|
| | | if (nextCell = cells[i+1])
|
| | | return nextCell;
|
| | | }
|
| | |
|
| | | function getTableGrid(table) {
|
| | |
| | |
|
| | | // Handle commands
|
| | | switch (command) {
|
| | | case "mceTableMoveToNextRow":
|
| | | var nextCell = getNextCell(tableElm, tdElm);
|
| | |
|
| | | if (!nextCell) {
|
| | | inst.execCommand("mceTableInsertRowAfter", tdElm);
|
| | | nextCell = getNextCell(tableElm, tdElm);
|
| | | }
|
| | |
|
| | | inst.selection.select(nextCell);
|
| | | inst.selection.collapse(true);
|
| | |
|
| | | return true;
|
| | |
|
| | | case "mceTableRowProps":
|
| | | if (trElm == null)
|
| | | return true;
|
| | |
| | | var cpos = getCellPos(grid, tdElm);
|
| | |
|
| | | // Only one row, remove whole table
|
| | | if (grid.length == 1) {
|
| | | if (grid.length == 1 && tableElm.nodeName == 'TBODY') {
|
| | | inst.dom.remove(inst.dom.getParent(tableElm, "table"));
|
| | | return true;
|
| | | }
|
| | |
| | | if (!trElm || !tdElm)
|
| | | return true;
|
| | |
|
| | | var grid = getTableGrid(tableElm);
|
| | | var grid = getTableGrid(inst.dom.getParent(tableElm, "table"));
|
| | | var cpos = getCellPos(grid, tdElm);
|
| | | var lastTDElm = null;
|
| | |
|
| | |
| | | if (!trElm || !tdElm)
|
| | | return true;
|
| | |
|
| | | var grid = getTableGrid(tableElm);
|
| | | var grid = getTableGrid(inst.dom.getParent(tableElm, "table"));
|
| | | var cpos = getCellPos(grid, tdElm);
|
| | | var lastTDElm = null;
|
| | |
|
| | |
| | | var lastTDElm = null;
|
| | |
|
| | | // Only one col, remove whole table
|
| | | if (grid.length > 1 && grid[0].length <= 1) {
|
| | | if ((grid.length > 1 && grid[0].length <= 1) && tableElm.nodeName == 'TBODY') {
|
| | | inst.dom.remove(inst.dom.getParent(tableElm, "table"));
|
| | | return true;
|
| | | }
|
| | |
| | | if (!tdElm)
|
| | | break;
|
| | |
|
| | | if (tdElm.nodeName == "TD")
|
| | | if (tdElm.nodeName == "TD" || tdElm.nodeName == "TH")
|
| | | cells[cells.length] = tdElm;
|
| | | }
|
| | |
|