Aleksander Machniak
2012-06-09 db8110c70d40b4e8864292f94c19248bb5a63b67
program/js/tiny_mce/plugins/table/editor_plugin_src.js
@@ -287,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;
@@ -599,6 +614,9 @@
            else
               dom.insertAfter(row, targetRow);
         });
         // Remove current selection
         dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
      };
      function getPos(target) {
@@ -988,7 +1006,7 @@
                  rng.endOffset == 0 && 
                  currentCell && 
                  (n.nodeName=="TR" || n==tableParent);
               tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell;
               tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell;
               return  allOfCellSelected || tableCellSelection;
               // return false;
            }
@@ -1000,7 +1018,7 @@
               var rng = ed.selection.getRng();
               var n = ed.selection.getNode();
               var currentCell = ed.dom.getParent(rng.startContainer, 'TD');
               var currentCell = ed.dom.getParent(rng.startContainer, 'TD,TH');
            
               if (!tableCellSelected(ed, rng, n, currentCell))
                  return;
@@ -1012,7 +1030,7 @@
               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);
@@ -1074,31 +1092,87 @@
            // 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;
                  function handle(upBool, sourceNode, event) {
                     var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
                     var currentRow = ed.dom.getParent(sourceNode, 'tr');
                     var siblingRow = currentRow[siblingDirection];
                     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 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 isVerticalMovement() {
                     return key == VK.UP || key == VK.DOWN;
                  }
                  function isInTable(ed) {
@@ -1129,42 +1203,32 @@
                     return r;
                  }
                  function moveCursorToRow(ed, node, row) {
                  function moveCursorToRow(ed, node, row, upBool) {
                     var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th'));
                     var tgtColumnIndex = findColumn(row, srcColumnIndex)
                     var tgtColumnIndex = findColumn(row, srcColumnIndex);
                     var tgtNode = row.childNodes[tgtColumnIndex];
                     moveCursorToStartOfElement(tgtNode);
                     var rowCellTarget = getChildForDirection(tgtNode, upBool);
                     moveCursorToStartOfElement(rowCellTarget || 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 row
                        moveCursorToStartOfElement(element);
                        return true;
                     }
                  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)
                  }
                  var UP_ARROW = 38;
                  var DOWN_ARROW = 40;
                  function checkSameParentTable(nodeOne, NodeTwo) {
                     return ed.dom.getParent(nodeOne, 'TABLE') === ed.dom.getParent(NodeTwo, 'TABLE');
                  }
                  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 table
                     if (nextRow == null) {
                        return escapeTable(currentRow, e);
                     } else {
                        moveCursorToRow(ed, node, nextRow);
                        tinymce.dom.Event.cancel(e);
                        return true;
                     }
                  if (isVerticalMovement() && isInTable(ed)) {
                     var preBrowserNode = ed.selection.getNode();
                     setTimeout(function() {
                        if (shouldFixCaret(preBrowserNode)) {
                           handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
                        }
                     }, 0);
                  }
               }
@@ -1181,7 +1245,7 @@
                  for (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" />');
                     ed.dom.add(ed.getBody(), 'p', null, '<br data-mce-bogus="1" />');
               };
               // Fixes an bug where it's impossible to place the caret before a table in Gecko
@@ -1219,10 +1283,28 @@
               ed.onPreProcess.add(function(ed, o) {
                  var last = o.node.lastChild;
                  if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR')
                  if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR' && 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'});
            }