From fc84ca1f0cd4684697adecb406fcb5c347d91807 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sat, 30 Jun 2012 03:50:39 -0400
Subject: [PATCH] Decorated select width fix is also needed for IE and Safari
---
program/js/tiny_mce/plugins/table/editor_plugin_src.js | 502 +++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 413 insertions(+), 89 deletions(-)
diff --git a/program/js/tiny_mce/plugins/table/editor_plugin_src.js b/program/js/tiny_mce/plugins/table/editor_plugin_src.js
index c2f307f..6a36309 100644
--- a/program/js/tiny_mce/plugins/table/editor_plugin_src.js
+++ b/program/js/tiny_mce/plugins/table/editor_plugin_src.js
@@ -11,6 +11,24 @@
(function(tinymce) {
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;
+ };
+
+ function getSpanVal(td, name) {
+ return parseInt(td.getAttribute(name) || 1);
+ }
+
/**
* Table Grid class.
*/
@@ -38,12 +56,12 @@
grid = [];
each(['thead', 'tbody', 'tfoot'], function(part) {
- var rows = dom.select(part + ' tr', table);
+ var rows = dom.select('> ' + part + ' tr', table);
each(rows, function(tr, y) {
y += startY;
- each(dom.select('td,th', tr), function(td, x) {
+ each(dom.select('> td, > th', tr), function(td, x) {
var x2, y2, rowspan, colspan;
// Skip over existing cells produced by rowspan
@@ -86,12 +104,19 @@
return row[x];
};
- function getSpanVal(td, name) {
- return parseInt(td.getAttribute(name) || 1);
- };
+ function setSpanVal(td, name, val) {
+ if (td) {
+ val = parseInt(val);
+
+ if (val === 1)
+ td.removeAttribute(name, 1);
+ else
+ td.setAttribute(name, val, 1);
+ }
+ }
function isCellSelected(cell) {
- return dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell;
+ return cell && (dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell);
};
function getSelectedRows() {
@@ -141,20 +166,21 @@
// Add something to the inner node
if (curNode)
- curNode.innerHTML = tinymce.isIE ? ' ' : '<br _mce_bogus="1" />';
+ curNode.innerHTML = tinymce.isIE ? ' ' : '<br data-mce-bogus="1" />';
return false;
}
}, 'childNodes');
cell = cloneNode(cell, false);
- cell.rowSpan = cell.colSpan = 1;
+ setSpanVal(cell, 'rowSpan', 1);
+ setSpanVal(cell, 'colSpan', 1);
if (formatNode) {
cell.appendChild(formatNode);
} else {
if (!tinymce.isIE)
- cell.innerHTML = '<br _mce_bogus="1" />';
+ cell.innerHTML = '<br data-mce-bogus="1" />';
}
return cell;
@@ -236,7 +262,8 @@
rowSpan = getSpanVal(cell, 'rowspan');
if (colSpan > 1 || rowSpan > 1) {
- cell.colSpan = cell.rowSpan = 1;
+ setSpanVal(cell, 'rowSpan', 1);
+ setSpanVal(cell, 'colSpan', 1);
// Insert cells right
for (i = 0; i < colSpan - 1; i++)
@@ -250,7 +277,7 @@
};
function merge(cell, cols, rows) {
- var startX, startY, endX, endY, x, y, startCell, endCell, cell, children;
+ var startX, startY, endX, endY, x, y, startCell, endCell, cell, children, count;
// Use specified cell and cols/rows
if (cell) {
@@ -260,6 +287,21 @@
endX = startX + (cols - 1);
endY = startY + (rows - 1);
} else {
+ startPos = endPos = null;
+
+ // Calculate start/end pos by checking for selected cells in grid works better with context menu
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ if (isCellSelected(cell)) {
+ if (!startPos) {
+ startPos = {x: x, y: y};
+ }
+
+ endPos = {x: x, y: y};
+ }
+ });
+ });
+
// Use selection
startX = startPos.x;
startY = startPos.y;
@@ -279,23 +321,34 @@
// Set row/col span to start cell
startCell = getCell(startX, startY).elm;
- startCell.colSpan = (endX - startX) + 1;
- startCell.rowSpan = (endY - startY) + 1;
+ setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
+ setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
// Remove other cells and add it's contents to the start cell
for (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 startCell
children = tinymce.grep(cell.childNodes);
- each(children, function(node, i) {
- // Jump over last BR element
- if (node.nodeName != 'BR' || i != children.length - 1)
- startCell.appendChild(node);
+ each(children, function(node) {
+ startCell.appendChild(node);
});
+ // Remove bogus nodes if there is children in the target cell
+ if (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 cell
dom.remove(cell);
}
@@ -308,7 +361,7 @@
};
function insertRow(before) {
- var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell;
+ var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
// Find first/last row
each(grid, function(row, y) {
@@ -329,30 +382,35 @@
});
for (x = 0; x < grid[0].length; x++) {
+ // Cell not found could be because of an invalid table structure
+ if (!grid[posY][x])
+ continue;
+
cell = grid[posY][x].elm;
if (cell != lastCell) {
if (!before) {
rowSpan = getSpanVal(cell, 'rowspan');
if (rowSpan > 1) {
- cell.rowSpan = rowSpan + 1;
+ setSpanVal(cell, 'rowSpan', rowSpan + 1);
continue;
}
} else {
// Check if cell above can be expanded
if (posY > 0 && grid[posY - 1][x]) {
otherCell = grid[posY - 1][x].elm;
- rowSpan = getSpanVal(otherCell, 'rowspan');
+ rowSpan = getSpanVal(otherCell, 'rowSpan');
if (rowSpan > 1) {
- otherCell.rowSpan = rowSpan + 1;
+ setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
continue;
}
}
}
// Insert new cell into new row
- newCell = cloneCell(cell)
- newCell.colSpan = cell.colSpan;
+ newCell = cloneCell(cell);
+ setSpanVal(newCell, 'colSpan', cell.colSpan);
+
newRow.appendChild(newCell);
lastCell = cell;
@@ -386,8 +444,12 @@
});
each(grid, function(row, y) {
- var cell = row[posX].elm, rowSpan, colSpan;
+ var cell, rowSpan, colSpan;
+ if (!row[posX])
+ return;
+
+ cell = row[posX].elm;
if (cell != lastCell) {
colSpan = getSpanVal(cell, 'colspan');
rowSpan = getSpanVal(cell, 'rowspan');
@@ -401,7 +463,7 @@
fillLeftDown(posX, y, rowSpan - 1, colSpan);
}
} else
- cell.colSpan++;
+ setSpanVal(cell, 'colSpan', cell.colSpan + 1);
lastCell = cell;
}
@@ -418,10 +480,10 @@
each(grid, function(row) {
var cell = row[x].elm, colSpan;
- colSpan = getSpanVal(cell, 'colspan');
+ colSpan = getSpanVal(cell, 'colSpan');
if (colSpan > 1)
- cell.colSpan = colSpan - 1;
+ setSpanVal(cell, 'colSpan', colSpan - 1);
else
dom.remove(cell);
});
@@ -444,10 +506,10 @@
// Move down row spanned cells
each(tr.cells, function(cell) {
- var rowSpan = getSpanVal(cell, 'rowspan');
+ var rowSpan = getSpanVal(cell, 'rowSpan');
if (rowSpan > 1) {
- cell.rowSpan = rowSpan - 1;
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
pos = getPos(cell);
fillLeftDown(pos.x, pos.y, 1, 1);
}
@@ -461,12 +523,12 @@
cell = cell.elm;
if (cell != lastCell) {
- rowSpan = getSpanVal(cell, 'rowspan');
+ rowSpan = getSpanVal(cell, 'rowSpan');
if (rowSpan <= 1)
dom.remove(cell);
else
- cell.rowSpan = rowSpan - 1;
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
lastCell = cell;
}
@@ -534,7 +596,8 @@
// Remove col/rowspans
for (i = 0; i < cellCount; i++) {
cell = row.cells[i];
- cell.colSpan = cell.rowSpan = 1;
+ setSpanVal(cell, 'colSpan', 1);
+ setSpanVal(cell, 'rowSpan', 1);
}
// Needs more cells
@@ -551,6 +614,9 @@
else
dom.insertAfter(row, targetRow);
});
+
+ // Remove current selection
+ dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
};
function getPos(target) {
@@ -676,8 +742,10 @@
// Add new selection
for (y = startY; y <= maxY; y++) {
- for (x = startX; x <= maxX; x++)
- dom.addClass(grid[y][x].elm, 'mceSelected');
+ for (x = startX; x <= maxX; x++) {
+ if (grid[y][x])
+ dom.addClass(grid[y][x].elm, 'mceSelected');
+ }
}
}
};
@@ -702,7 +770,7 @@
tinymce.create('tinymce.plugins.TablePlugin', {
init : function(ed, url) {
- var winMan, clipboardRows;
+ var winMan, clipboardRows, hasCellSelection = true; // Might be selected cells on reload
function createTableGrid(node) {
var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table');
@@ -714,7 +782,11 @@
function cleanup() {
// Restore selection possibilities
ed.getBody().style.webkitUserSelect = '';
- ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
+
+ if (hasCellSelection) {
+ ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
+ hasCellSelection = false;
+ }
};
// Register buttons
@@ -740,10 +812,33 @@
ed.onClick.add(function(ed, e) {
e = e.target;
- if (e.nodeName === 'TABLE')
+ 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 updates
ed.onNodeChange.add(function(ed, cm, n) {
@@ -800,15 +895,20 @@
}
tableGrid.setEndCell(target);
+ hasCellSelection = true;
}
// Remove current selection
sel = ed.selection.getSel();
- if (sel.removeAllRanges)
- sel.removeAllRanges();
- else
- sel.empty();
+ try {
+ if (sel.removeAllRanges)
+ sel.removeAllRanges();
+ else
+ sel.empty();
+ } catch (ex) {
+ // IE9 might throw errors here
+ }
e.preventDefault();
}
@@ -846,7 +946,7 @@
return;
}
} while (node = (start ? walker.next() : walker.prev()));
- };
+ }
// Try to expand text selection as much as we can only Gecko supports cell selection
selectedCells = dom.select('td.mceSelected,th.mceSelected');
@@ -854,6 +954,8 @@
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'));
@@ -880,6 +982,60 @@
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 &&
+ currentCell &&
+ (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,TH');
+
+ if (!tableCellSelected(ed, rng, n, currentCell))
+ return;
+ if (!currentCell) {
+ currentCell=n;
+ }
+
+ // Get the very last node inside the table cell
+ var 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 menu
if (ed && ed.plugins.contextmenu) {
@@ -933,60 +1089,228 @@
});
}
- // 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) {
- function fixTableCaretPos() {
- var last;
+ // Fix to allow navigating up and down in a table in WebKit browsers.
+ if (tinymce.isWebKit) {
+ function moveSelection(ed, e) {
+ var VK = tinymce.VK;
+ var key = e.keyCode;
- // Skip empty text nodes form the end
- for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
+ function handle(upBool, sourceNode, event) {
+ var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
+ var currentRow = ed.dom.getParent(sourceNode, 'tr');
+ var siblingRow = currentRow[siblingDirection];
- 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();
+ if (siblingRow) {
+ moveCursorToRow(ed, sourceNode, siblingRow, upBool);
+ tinymce.dom.Event.cancel(event);
+ return true;
+ } else {
+ var tableNode = ed.dom.getParent(currentRow, 'table');
+ var middleNode = currentRow.parentNode;
+ var parentNodeName = middleNode.nodeName.toLowerCase();
+ if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
+ var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
+ if (targetParent !== null) {
+ return moveToRowInTarget(upBool, targetParent, sourceNode, event);
}
}
+ return escapeTable(upBool, currentRow, siblingDirection, tableNode, event);
}
- });
+ }
+
+ function getTargetParent(upBool, topNode, secondNode, nodeName) {
+ var tbodies = ed.dom.select('>' + nodeName, topNode);
+ var position = tbodies.indexOf(secondNode);
+ if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
+ return getFirstHeadOrFoot(upBool, topNode);
+ } else if (position === -1) {
+ var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
+ return tbodies[topOrBottom];
+ } else {
+ return tbodies[position + (upBool ? -1 : 1)];
+ }
+ }
+
+ function getFirstHeadOrFoot(upBool, parent) {
+ var tagName = upBool ? 'thead' : 'tfoot';
+ var headOrFoot = ed.dom.select('>' + tagName, parent);
+ return headOrFoot.length !== 0 ? headOrFoot[0] : null;
+ }
+
+ function moveToRowInTarget(upBool, targetParent, sourceNode, event) {
+ var targetRow = getChildForDirection(targetParent, upBool);
+ targetRow && moveCursorToRow(ed, sourceNode, targetRow, upBool);
+ tinymce.dom.Event.cancel(event);
+ return true;
+ }
+
+ function escapeTable(upBool, currentRow, siblingDirection, table, event) {
+ var tableSibling = table[siblingDirection];
+ if (tableSibling) {
+ moveCursorToStartOfElement(tableSibling);
+ return true;
+ } else {
+ var parentCell = ed.dom.getParent(table, 'td,th');
+ if (parentCell) {
+ return handle(upBool, parentCell, event);
+ } else {
+ var backUpSibling = getChildForDirection(currentRow, !upBool);
+ moveCursorToStartOfElement(backUpSibling);
+ return tinymce.dom.Event.cancel(event);
+ }
+ }
+ }
+
+ function getChildForDirection(parent, up) {
+ var child = parent && parent[up ? 'lastChild' : 'firstChild'];
+ // BR is not a valid table child to return in this case we return the table cell
+ return child && child.nodeName === 'BR' ? ed.dom.getParent(child, 'td,th') : child;
+ }
+
+ function moveCursorToStartOfElement(n) {
+ ed.selection.setCursorLocation(n, 0);
+ }
+
+ function isVerticalMovement() {
+ return key == VK.UP || key == VK.DOWN;
+ }
+
+ 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, upBool) {
+ var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th'));
+ var tgtColumnIndex = findColumn(row, srcColumnIndex);
+ var tgtNode = row.childNodes[tgtColumnIndex];
+ var rowCellTarget = getChildForDirection(tgtNode, upBool);
+ moveCursorToStartOfElement(rowCellTarget || tgtNode);
+ }
+
+ function shouldFixCaret(preBrowserNode) {
+ var newNode = ed.selection.getNode();
+ var newParent = ed.dom.getParent(newNode, 'td,th');
+ var oldParent = ed.dom.getParent(preBrowserNode, 'td,th');
+ return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent)
+ }
+
+ function checkSameParentTable(nodeOne, NodeTwo) {
+ return ed.dom.getParent(nodeOne, 'TABLE') === ed.dom.getParent(NodeTwo, 'TABLE');
+ }
+
+ if (isVerticalMovement() && isInTable(ed)) {
+ var preBrowserNode = ed.selection.getNode();
+ setTimeout(function() {
+ if (shouldFixCaret(preBrowserNode)) {
+ handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
+ }
+ }, 0);
+ }
}
- 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.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 enabled
+ function fixTableCaretPos() {
+ var last;
+
+ // Skip empty text nodes form the end
+ for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
+
+ if (last && last.nodeName == 'TABLE') {
+ if (ed.settings.forced_root_block)
+ ed.dom.add(ed.getBody(), ed.settings.forced_root_block, null, tinymce.isIE ? ' ' : '<br data-mce-bogus="1" />');
+ else
+ ed.dom.add(ed.getBody(), 'br', {'data-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.nodeName == "BR" || (last.childNodes.length == 1 && (last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0'))) && last.previousSibling && last.previousSibling.nodeName == "TABLE") {
+ ed.dom.remove(last);
+ }
+ });
+
+
+ /**
+ * Fixes bug in Gecko where shift-enter in table cell does not place caret on new line
+ */
+ if (tinymce.isGecko) {
+ ed.onKeyDown.add(function(ed, e) {
+ if (e.keyCode === tinymce.VK.ENTER && e.shiftKey) {
+ var node = ed.selection.getRng().startContainer;
+ var tableCell = dom.getParent(node, 'td,th');
+ if (tableCell) {
+ var zeroSizedNbsp = ed.getDoc().createTextNode("\uFEFF");
+ dom.insertAfter(zeroSizedNbsp, node);
+ }
+ }
+ });
+ }
+
+
+ fixTableCaretPos();
+ ed.startContent = ed.getContent({format : 'raw'});
});
// Register action commands
@@ -1122,4 +1446,4 @@
// Register plugin
tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
-})(tinymce);
\ No newline at end of file
+})(tinymce);
--
Gitblit v1.9.1