diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/editor/plugins/tagonenterhandler.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/editor/plugins/tagonenterhandler.js | 742 |
1 files changed, 0 insertions, 742 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/editor/plugins/tagonenterhandler.js b/contexts/data/lib/closure-library/closure/goog/editor/plugins/tagonenterhandler.js deleted file mode 100644 index c586894..0000000 --- a/contexts/data/lib/closure-library/closure/goog/editor/plugins/tagonenterhandler.js +++ /dev/null @@ -1,742 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview TrogEdit plugin to handle enter keys by inserting the - * specified block level tag. - * - */ - -goog.provide('goog.editor.plugins.TagOnEnterHandler'); - -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.Range'); -goog.require('goog.dom.TagName'); -goog.require('goog.editor.Command'); -goog.require('goog.editor.node'); -goog.require('goog.editor.plugins.EnterHandler'); -goog.require('goog.editor.range'); -goog.require('goog.editor.style'); -goog.require('goog.events.KeyCodes'); -goog.require('goog.string'); -goog.require('goog.style'); -goog.require('goog.userAgent'); - - - -/** - * Plugin to handle enter keys. This subclass normalizes all browsers to use - * the given block tag on enter. - * @param {goog.dom.TagName} tag The type of tag to add on enter. - * @constructor - * @extends {goog.editor.plugins.EnterHandler} - */ -goog.editor.plugins.TagOnEnterHandler = function(tag) { - this.tag = tag; - - goog.editor.plugins.EnterHandler.call(this); -}; -goog.inherits(goog.editor.plugins.TagOnEnterHandler, - goog.editor.plugins.EnterHandler); - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.getTrogClassId = function() { - return 'TagOnEnterHandler'; -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.getNonCollapsingBlankHtml = - function() { - if (this.tag == goog.dom.TagName.P) { - return '<p> </p>'; - } else if (this.tag == goog.dom.TagName.DIV) { - return '<div><br></div>'; - } - return '<br>'; -}; - - -/** - * This plugin is active on uneditable fields so it can provide a value for - * queryCommandValue calls asking for goog.editor.Command.BLOCKQUOTE. - * @return {boolean} True. - * @override - */ -goog.editor.plugins.TagOnEnterHandler.prototype.activeOnUneditableFields = - goog.functions.TRUE; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.isSupportedCommand = function( - command) { - return command == goog.editor.Command.DEFAULT_TAG; -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.queryCommandValue = function( - command) { - return command == goog.editor.Command.DEFAULT_TAG ? this.tag : null; -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.handleBackspaceInternal = - function(e, range) { - goog.editor.plugins.TagOnEnterHandler.superClass_.handleBackspaceInternal. - call(this, e, range); - - if (goog.userAgent.GECKO) { - this.markBrToNotBeRemoved_(range, true); - } -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.processParagraphTagsInternal = - function(e, split) { - if ((goog.userAgent.OPERA || goog.userAgent.IE) && - this.tag != goog.dom.TagName.P) { - this.ensureBlockIeOpera(this.tag); - } -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.handleDeleteGecko = function( - e) { - var range = this.getFieldObject().getRange(); - var container = goog.editor.style.getContainer( - range && range.getContainerElement()); - if (this.getFieldObject().getElement().lastChild == container && - goog.editor.plugins.EnterHandler.isBrElem(container)) { - // Don't delete if it's the last node in the field and just has a BR. - e.preventDefault(); - // TODO(user): I think we probably don't need to stopPropagation here - e.stopPropagation(); - } else { - // Go ahead with deletion. - // Prevent an existing BR immediately following the selection being deleted - // from being removed in the keyup stage (as opposed to a BR added by FF - // after deletion, which we do remove). - this.markBrToNotBeRemoved_(range, false); - // Manually delete the selection if it's at a BR. - this.deleteBrGecko(e); - } -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.handleKeyUpInternal = function( - e) { - if (goog.userAgent.GECKO) { - if (e.keyCode == goog.events.KeyCodes.DELETE) { - this.removeBrIfNecessary_(false); - } else if (e.keyCode == goog.events.KeyCodes.BACKSPACE) { - this.removeBrIfNecessary_(true); - } - } else if ((goog.userAgent.IE || goog.userAgent.OPERA) && - e.keyCode == goog.events.KeyCodes.ENTER) { - this.ensureBlockIeOpera(this.tag, true); - } - // Safari uses DIVs by default. -}; - - -/** - * String that matches a single BR tag or NBSP surrounded by non-breaking - * whitespace - * @type {string} - * @private - */ -goog.editor.plugins.TagOnEnterHandler.BrOrNbspSurroundedWithWhiteSpace_ = - '[\t\n\r ]*(<br[^>]*\/?>| )[\t\n\r ]*'; - - -/** - * String that matches a single BR tag or NBSP surrounded by non-breaking - * whitespace - * @type {RegExp} - * @private - */ -goog.editor.plugins.TagOnEnterHandler.emptyLiRegExp_ = new RegExp('^' + - goog.editor.plugins.TagOnEnterHandler.BrOrNbspSurroundedWithWhiteSpace_ + - '$'); - - -/** - * Ensures the current node is wrapped in the tag. - * @param {Node} node The node to ensure gets wrapped. - * @param {Element} container Element containing the selection. - * @return {Element} Element containing the selection, after the wrapping. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.prototype.ensureNodeIsWrappedW3c_ = - function(node, container) { - if (container == this.getFieldObject().getElement()) { - // If the first block-level ancestor of cursor is the field, - // don't split the tree. Find all the text from the cursor - // to both block-level elements surrounding it (if they exist) - // and split the text into two elements. - // This is the IE contentEditable behavior. - - // The easy way to do this is to wrap all the text in an element - // and then split the element as if the user had hit enter - // in the paragraph - - // However, simply wrapping the text into an element creates problems - // if the text was already wrapped using some other element such as an - // anchor. For example, wrapping the text of - // <a href="">Text</a> - // would produce - // <a href=""><p>Text</p></a> - // which is not what we want. What we really want is - // <p><a href="">Text</a></p> - // So we need to search for an ancestor of position.node to be wrapped. - // We do this by iterating up the hierarchy of postiion.node until we've - // reached the node that's just under the container. - var isChildOfFn = function(child) { - return container == child.parentNode; }; - var nodeToWrap = goog.dom.getAncestor(node, isChildOfFn, true); - container = goog.editor.plugins.TagOnEnterHandler.wrapInContainerW3c_( - this.tag, {node: nodeToWrap, offset: 0}, container); - } - return container; -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype.handleEnterWebkitInternal = - function(e) { - if (this.tag == goog.dom.TagName.DIV) { - var range = this.getFieldObject().getRange(); - var container = - goog.editor.style.getContainer(range.getContainerElement()); - - var position = goog.editor.range.getDeepEndPoint(range, true); - container = this.ensureNodeIsWrappedW3c_(position.node, container); - goog.dom.Range.createCaret(position.node, position.offset).select(); - } -}; - - -/** @override */ -goog.editor.plugins.TagOnEnterHandler.prototype. - handleEnterAtCursorGeckoInternal = function(e, wasCollapsed, range) { - // We use this because there are a few cases where FF default - // implementation doesn't follow IE's: - // -Inserts BRs into empty elements instead of NBSP which has nasty - // side effects w/ making/deleting selections - // -Hitting enter when your cursor is in the field itself. IE will - // create two elements. FF just inserts a BR. - // -Hitting enter inside an empty list-item doesn't create a block - // tag. It just splits the list and puts your cursor in the middle. - var li = null; - if (wasCollapsed) { - // Only break out of lists for collapsed selections. - li = goog.dom.getAncestorByTagNameAndClass( - range && range.getContainerElement(), goog.dom.TagName.LI); - } - var isEmptyLi = (li && - li.innerHTML.match( - goog.editor.plugins.TagOnEnterHandler.emptyLiRegExp_)); - var elementAfterCursor = isEmptyLi ? - this.breakOutOfEmptyListItemGecko_(li) : - this.handleRegularEnterGecko_(); - - // Move the cursor in front of "nodeAfterCursor", and make sure it - // is visible - this.scrollCursorIntoViewGecko_(elementAfterCursor); - - // Fix for http://b/1991234 : - if (goog.editor.plugins.EnterHandler.isBrElem(elementAfterCursor)) { - // The first element in the new line is a line with just a BR and maybe some - // whitespace. - // Calling normalize() is needed because there might be empty text nodes - // before BR and empty text nodes cause the cursor position bug in Firefox. - // See http://b/5220858 - elementAfterCursor.normalize(); - var br = elementAfterCursor.getElementsByTagName(goog.dom.TagName.BR)[0]; - if (br.previousSibling && - br.previousSibling.nodeType == goog.dom.NodeType.TEXT) { - // If there is some whitespace before the BR, don't put the selection on - // the BR, put it in the text node that's there, otherwise when you type - // it will create adjacent text nodes. - elementAfterCursor = br.previousSibling; - } - } - - goog.editor.range.selectNodeStart(elementAfterCursor); - - e.preventDefault(); - // TODO(user): I think we probably don't need to stopPropagation here - e.stopPropagation(); -}; - - -/** - * If The cursor is in an empty LI then break out of the list like in IE - * @param {Node} li LI to break out of. - * @return {Element} Element to put the cursor after. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.prototype.breakOutOfEmptyListItemGecko_ = - function(li) { - // Do this as follows: - // 1. <ul>...<li> </li>...</ul> - // 2. <ul id='foo1'>...<li id='foo2'> </li>...</ul> - // 3. <ul id='foo1'>...</ul><p id='foo3'> </p><ul id='foo2'>...</ul> - // 4. <ul>...</ul><p> </p><ul>...</ul> - // - // There are a couple caveats to the above. If the UL is contained in - // a list, then the new node inserted is an LI, not a P. - // For an OL, it's all the same, except the tagname of course. - // Finally, it's possible that with the LI at the beginning or the end - // of the list that we'll end up with an empty list. So we special case - // those cases. - - var listNode = li.parentNode; - var grandparent = listNode.parentNode; - var inSubList = grandparent.tagName == goog.dom.TagName.OL || - grandparent.tagName == goog.dom.TagName.UL; - - // TODO(robbyw): Should we apply the list or list item styles to the new node? - var newNode = goog.dom.getDomHelper(li).createElement( - inSubList ? goog.dom.TagName.LI : this.tag); - - if (!li.previousSibling) { - goog.dom.insertSiblingBefore(newNode, listNode); - } else { - if (li.nextSibling) { - var listClone = listNode.cloneNode(false); - while (li.nextSibling) { - listClone.appendChild(li.nextSibling); - } - goog.dom.insertSiblingAfter(listClone, listNode); - } - goog.dom.insertSiblingAfter(newNode, listNode); - } - if (goog.editor.node.isEmpty(listNode)) { - goog.dom.removeNode(listNode); - } - goog.dom.removeNode(li); - newNode.innerHTML = ' '; - - return newNode; -}; - - -/** - * Wrap the text indicated by "position" in an HTML container of type - * "nodeName". - * @param {string} nodeName Type of container, e.g. "p" (paragraph). - * @param {Object} position The W3C cursor position object - * (from getCursorPositionW3c). - * @param {Node} container The field containing position. - * @return {Element} The container element that holds the contents from - * position. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.wrapInContainerW3c_ = function(nodeName, - position, container) { - var start = position.node; - while (start.previousSibling && - !goog.editor.style.isContainer(start.previousSibling)) { - start = start.previousSibling; - } - - var end = position.node; - while (end.nextSibling && - !goog.editor.style.isContainer(end.nextSibling)) { - end = end.nextSibling; - } - - var para = container.ownerDocument.createElement(nodeName); - while (start != end) { - var newStart = start.nextSibling; - goog.dom.appendChild(para, start); - start = newStart; - } - var nextSibling = end.nextSibling; - goog.dom.appendChild(para, end); - container.insertBefore(para, nextSibling); - - return para; -}; - - -/** - * When we delete an element, FF inserts a BR. We want to strip that - * BR after the fact, but in the case where your cursor is at a character - * right before a BR and you delete that character, we don't want to - * strip it. So we detect this case on keydown and mark the BR as not needing - * removal. - * @param {goog.dom.AbstractRange} range The closure range object. - * @param {boolean} isBackspace Whether this is handling the backspace key. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.prototype.markBrToNotBeRemoved_ = - function(range, isBackspace) { - var focusNode = range.getFocusNode(); - var focusOffset = range.getFocusOffset(); - var newEndOffset = isBackspace ? focusOffset : focusOffset + 1; - - if (goog.editor.node.getLength(focusNode) == newEndOffset) { - var sibling = focusNode.nextSibling; - if (sibling && sibling.tagName == goog.dom.TagName.BR) { - this.brToKeep_ = sibling; - } - } -}; - - -/** - * If we hit delete/backspace to merge elements, FF inserts a BR. - * We want to strip that BR. In markBrToNotBeRemoved, we detect if - * there was already a BR there before the delete/backspace so that - * we don't accidentally remove a user-inserted BR. - * @param {boolean} isBackSpace Whether this is handling the backspace key. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.prototype.removeBrIfNecessary_ = function( - isBackSpace) { - var range = this.getFieldObject().getRange(); - var focusNode = range.getFocusNode(); - var focusOffset = range.getFocusOffset(); - - var sibling; - if (isBackSpace && focusNode.data == '') { - // nasty hack. sometimes firefox will backspace a paragraph and put - // the cursor before the BR. when it does this, the focusNode is - // an empty textnode. - sibling = focusNode.nextSibling; - } else if (isBackSpace && focusOffset == 0) { - var node = focusNode; - while (node && !node.previousSibling && - node.parentNode != this.getFieldObject().getElement()) { - node = node.parentNode; - } - sibling = node.previousSibling; - } else if (focusNode.length == focusOffset) { - sibling = focusNode.nextSibling; - } - - if (!sibling || sibling.tagName != goog.dom.TagName.BR || - this.brToKeep_ == sibling) { - return; - } - - goog.dom.removeNode(sibling); - if (focusNode.nodeType == goog.dom.NodeType.TEXT) { - // Sometimes firefox inserts extra whitespace. Do our best to deal. - // This is buggy though. - focusNode.data = - goog.editor.plugins.TagOnEnterHandler.trimTabsAndLineBreaks_( - focusNode.data); - // When we strip whitespace, make sure that our cursor is still at - // the end of the textnode. - goog.dom.Range.createCaret(focusNode, - Math.min(focusOffset, focusNode.length)).select(); - } -}; - - -/** - * Trim the tabs and line breaks from a string. - * @param {string} string String to trim. - * @return {string} Trimmed string. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.trimTabsAndLineBreaks_ = function( - string) { - return string.replace(/^[\t\n\r]|[\t\n\r]$/g, ''); -}; - - -/** - * Called in response to a normal enter keystroke. It has the action of - * splitting elements. - * @return {Element} The node that the cursor should be before. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.prototype.handleRegularEnterGecko_ = - function() { - var range = this.getFieldObject().getRange(); - var container = - goog.editor.style.getContainer(range.getContainerElement()); - var newNode; - if (goog.editor.plugins.EnterHandler.isBrElem(container)) { - if (container.tagName == goog.dom.TagName.BODY) { - // If the field contains only a single BR, this code ensures we don't - // try to clone the body tag. - container = this.ensureNodeIsWrappedW3c_( - container.getElementsByTagName(goog.dom.TagName.BR)[0], - container); - } - - newNode = container.cloneNode(true); - goog.dom.insertSiblingAfter(newNode, container); - } else { - if (!container.firstChild) { - container.innerHTML = ' '; - } - - var position = goog.editor.range.getDeepEndPoint(range, true); - container = this.ensureNodeIsWrappedW3c_(position.node, container); - - newNode = goog.editor.plugins.TagOnEnterHandler.splitDomAndAppend_( - position.node, position.offset, container); - - // If the left half and right half of the splitted node are anchors then - // that means the user pressed enter while the caret was inside - // an anchor tag and split it. The left half is the first anchor - // found while traversing the right branch of container. The right half - // is the first anchor found while traversing the left branch of newNode. - var leftAnchor = - goog.editor.plugins.TagOnEnterHandler.findAnchorInTraversal_( - container); - var rightAnchor = - goog.editor.plugins.TagOnEnterHandler.findAnchorInTraversal_( - newNode, true); - if (leftAnchor && rightAnchor && - leftAnchor.tagName == goog.dom.TagName.A && - rightAnchor.tagName == goog.dom.TagName.A) { - // If the original anchor (left anchor) is now empty, that means - // the user pressed [Enter] at the beginning of the anchor, - // in which case we we - // want to replace that anchor with its child nodes - // Otherwise, we take the second half of the splitted text and break - // it out of the anchor. - var anchorToRemove = goog.editor.node.isEmpty(leftAnchor, false) ? - leftAnchor : rightAnchor; - goog.dom.flattenElement(/** @type {Element} */ (anchorToRemove)); - } - } - return /** @type {Element} */ (newNode); -}; - - -/** - * Scroll the cursor into view, resulting from splitting the paragraph/adding - * a br. It behaves differently than scrollIntoView - * @param {Element} element The element immediately following the cursor. Will - * be used to determine how to scroll in order to make the cursor visible. - * CANNOT be a BR, as they do not have offsetHeight/offsetTop. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.prototype.scrollCursorIntoViewGecko_ = - function(element) { - if (!this.getFieldObject().isFixedHeight()) { - return; // Only need to scroll fixed height fields. - } - - var field = this.getFieldObject().getElement(); - - // Get the y position of the element we want to scroll to - var elementY = goog.style.getPageOffsetTop(element); - - // Determine the height of that element, since we want the bottom of the - // element to be in view. - var bottomOfNode = elementY + element.offsetHeight; - - var dom = this.getFieldDomHelper(); - var win = this.getFieldDomHelper().getWindow(); - var scrollY = dom.getDocumentScroll().y; - var viewportHeight = goog.dom.getViewportSize(win).height; - - // If the botom of the element is outside the viewport, move it into view - if (bottomOfNode > viewportHeight + scrollY) { - // In standards mode, use the html element and not the body - if (field.tagName == goog.dom.TagName.BODY && - goog.editor.node.isStandardsMode(field)) { - field = field.parentNode; - } - field.scrollTop = bottomOfNode - viewportHeight; - } -}; - - -/** - * Splits the DOM tree around the given node and returns the node - * containing the second half of the tree. The first half of the tree - * is modified, but not removed from the DOM. - * @param {Node} positionNode Node to split at. - * @param {number} positionOffset Offset into positionNode to split at. If - * positionNode is a text node, this offset is an offset in to the text - * content of that node. Otherwise, positionOffset is an offset in to - * the childNodes array. All elements with child index of positionOffset - * or greater will be moved to the second half. If positionNode is an - * empty element, the dom will be split at that element, with positionNode - * ending up in the second half. positionOffset must be 0 in this case. - * @param {Node=} opt_root Node at which to stop splitting the dom (the root - * is also split). - * @return {Node} The node containing the second half of the tree. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.splitDom_ = function( - positionNode, positionOffset, opt_root) { - if (!opt_root) opt_root = positionNode.ownerDocument.body; - - // Split the node. - var textSplit = positionNode.nodeType == goog.dom.NodeType.TEXT; - var secondHalfOfSplitNode; - if (textSplit) { - if (goog.userAgent.IE && - positionOffset == positionNode.nodeValue.length) { - // Since splitText fails in IE at the end of a node, we split it manually. - secondHalfOfSplitNode = goog.dom.getDomHelper(positionNode). - createTextNode(''); - goog.dom.insertSiblingAfter(secondHalfOfSplitNode, positionNode); - } else { - secondHalfOfSplitNode = positionNode.splitText(positionOffset); - } - } else { - // Here we ensure positionNode is the last node in the first half of the - // resulting tree. - if (positionOffset) { - // Use offset as an index in to childNodes. - positionNode = positionNode.childNodes[positionOffset - 1]; - } else { - // In this case, positionNode would be the last node in the first half - // of the tree, but we actually want to move it to the second half. - // Therefore we set secondHalfOfSplitNode to the same node. - positionNode = secondHalfOfSplitNode = positionNode.firstChild || - positionNode; - } - } - - // Create second half of the tree. - var secondHalf = goog.editor.node.splitDomTreeAt( - positionNode, secondHalfOfSplitNode, opt_root); - - if (textSplit) { - // Join secondHalfOfSplitNode and its right text siblings together and - // then replace leading NonNbspWhiteSpace with a Nbsp. If - // secondHalfOfSplitNode has a right sibling that isn't a text node, - // then we can leave secondHalfOfSplitNode empty. - secondHalfOfSplitNode = - goog.editor.plugins.TagOnEnterHandler.joinTextNodes_( - secondHalfOfSplitNode, true); - goog.editor.plugins.TagOnEnterHandler.replaceWhiteSpaceWithNbsp_( - secondHalfOfSplitNode, true, !!secondHalfOfSplitNode.nextSibling); - - // Join positionNode and its left text siblings together and then replace - // trailing NonNbspWhiteSpace with a Nbsp. - var firstHalf = goog.editor.plugins.TagOnEnterHandler.joinTextNodes_( - positionNode, false); - goog.editor.plugins.TagOnEnterHandler.replaceWhiteSpaceWithNbsp_( - firstHalf, false, false); - } - - return secondHalf; -}; - - -/** - * Splits the DOM tree around the given node and returns the node containing - * second half of the tree, which is appended after the old node. The first - * half of the tree is modified, but not removed from the DOM. - * @param {Node} positionNode Node to split at. - * @param {number} positionOffset Offset into positionNode to split at. If - * positionNode is a text node, this offset is an offset in to the text - * content of that node. Otherwise, positionOffset is an offset in to - * the childNodes array. All elements with child index of positionOffset - * or greater will be moved to the second half. If positionNode is an - * empty element, the dom will be split at that element, with positionNode - * ending up in the second half. positionOffset must be 0 in this case. - * @param {Node} node Node to split. - * @return {Node} The node containing the second half of the tree. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.splitDomAndAppend_ = function( - positionNode, positionOffset, node) { - var newNode = goog.editor.plugins.TagOnEnterHandler.splitDom_( - positionNode, positionOffset, node); - goog.dom.insertSiblingAfter(newNode, node); - return newNode; -}; - - -/** - * Joins node and its adjacent text nodes together. - * @param {Node} node The node to start joining. - * @param {boolean} moveForward Determines whether to join left siblings (false) - * or right siblings (true). - * @return {Node} The joined text node. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.joinTextNodes_ = function(node, - moveForward) { - if (node && node.nodeName == '#text') { - var nextNodeFn = moveForward ? 'nextSibling' : 'previousSibling'; - var prevNodeFn = moveForward ? 'previousSibling' : 'nextSibling'; - var nodeValues = [node.nodeValue]; - while (node[nextNodeFn] && - node[nextNodeFn].nodeType == goog.dom.NodeType.TEXT) { - node = node[nextNodeFn]; - nodeValues.push(node.nodeValue); - goog.dom.removeNode(node[prevNodeFn]); - } - if (!moveForward) { - nodeValues.reverse(); - } - node.nodeValue = nodeValues.join(''); - } - return node; -}; - - -/** - * Replaces leading or trailing spaces of a text node to a single Nbsp. - * @param {Node} textNode The text node to search and replace white spaces. - * @param {boolean} fromStart Set to true to replace leading spaces, false to - * replace trailing spaces. - * @param {boolean} isLeaveEmpty Set to true to leave the node empty if the - * text node was empty in the first place, otherwise put a Nbsp into the - * text node. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.replaceWhiteSpaceWithNbsp_ = function( - textNode, fromStart, isLeaveEmpty) { - var regExp = fromStart ? /^[ \t\r\n]+/ : /[ \t\r\n]+$/; - textNode.nodeValue = textNode.nodeValue.replace(regExp, - goog.string.Unicode.NBSP); - - if (!isLeaveEmpty && textNode.nodeValue == '') { - textNode.nodeValue = goog.string.Unicode.NBSP; - } -}; - - -/** - * Finds the first A element in a traversal from the input node. The input - * node itself is not included in the search. - * @param {Node} node The node to start searching from. - * @param {boolean=} opt_useFirstChild Whether to traverse along the first child - * (true) or last child (false). - * @return {Node} The first anchor node found in the search, or null if none - * was found. - * @private - */ -goog.editor.plugins.TagOnEnterHandler.findAnchorInTraversal_ = function(node, - opt_useFirstChild) { - while ((node = opt_useFirstChild ? node.firstChild : node.lastChild) && - node.tagName != goog.dom.TagName.A) { - // Do nothing - advancement is handled in the condition. - } - return node; -}; |