Update wmts-hidpi, add nicer-api-docs
This commit is contained in:
632
nicer-api-docs/closure-library/closure/goog/editor/range.js
Normal file
632
nicer-api-docs/closure-library/closure/goog/editor/range.js
Normal file
@@ -0,0 +1,632 @@
|
||||
// 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 Utilties for working with ranges.
|
||||
*
|
||||
* @author nicksantos@google.com (Nick Santos)
|
||||
*/
|
||||
|
||||
goog.provide('goog.editor.range');
|
||||
goog.provide('goog.editor.range.Point');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.NodeType');
|
||||
goog.require('goog.dom.Range');
|
||||
goog.require('goog.dom.RangeEndpoint');
|
||||
goog.require('goog.dom.SavedCaretRange');
|
||||
goog.require('goog.editor.node');
|
||||
goog.require('goog.editor.style');
|
||||
goog.require('goog.iter');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* Given a range and an element, create a narrower range that is limited to the
|
||||
* boundaries of the element. If the range starts (or ends) outside the
|
||||
* element, the narrowed range's start point (or end point) will be the
|
||||
* leftmost (or rightmost) leaf of the element.
|
||||
* @param {goog.dom.AbstractRange} range The range.
|
||||
* @param {Element} el The element to limit the range to.
|
||||
* @return {goog.dom.AbstractRange} A new narrowed range, or null if the
|
||||
* element does not contain any part of the given range.
|
||||
*/
|
||||
goog.editor.range.narrow = function(range, el) {
|
||||
var startContainer = range.getStartNode();
|
||||
var endContainer = range.getEndNode();
|
||||
|
||||
if (startContainer && endContainer) {
|
||||
var isElement = function(node) {
|
||||
return node == el;
|
||||
};
|
||||
var hasStart = goog.dom.getAncestor(startContainer, isElement, true);
|
||||
var hasEnd = goog.dom.getAncestor(endContainer, isElement, true);
|
||||
|
||||
if (hasStart && hasEnd) {
|
||||
// The range is contained entirely within this element.
|
||||
return range.clone();
|
||||
} else if (hasStart) {
|
||||
// The range starts inside the element, but ends outside it.
|
||||
var leaf = goog.editor.node.getRightMostLeaf(el);
|
||||
return goog.dom.Range.createFromNodes(
|
||||
range.getStartNode(), range.getStartOffset(),
|
||||
leaf, goog.editor.node.getLength(leaf));
|
||||
} else if (hasEnd) {
|
||||
// The range starts outside the element, but ends inside it.
|
||||
return goog.dom.Range.createFromNodes(
|
||||
goog.editor.node.getLeftMostLeaf(el), 0,
|
||||
range.getEndNode(), range.getEndOffset());
|
||||
}
|
||||
}
|
||||
|
||||
// The selection starts and ends outside the element.
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given a range, expand the range to include outer tags if the full contents of
|
||||
* those tags are entirely selected. This essentially changes the dom position,
|
||||
* but not the visible position of the range.
|
||||
* Ex. <li>foo</li> if "foo" is selected, instead of returning start and end
|
||||
* nodes as the foo text node, return the li.
|
||||
* @param {goog.dom.AbstractRange} range The range.
|
||||
* @param {Node=} opt_stopNode Optional node to stop expanding past.
|
||||
* @return {goog.dom.AbstractRange} The expanded range.
|
||||
*/
|
||||
goog.editor.range.expand = function(range, opt_stopNode) {
|
||||
// Expand the start out to the common container.
|
||||
var expandedRange = goog.editor.range.expandEndPointToContainer_(
|
||||
range, goog.dom.RangeEndpoint.START, opt_stopNode);
|
||||
// Expand the end out to the common container.
|
||||
expandedRange = goog.editor.range.expandEndPointToContainer_(
|
||||
expandedRange, goog.dom.RangeEndpoint.END, opt_stopNode);
|
||||
|
||||
var startNode = expandedRange.getStartNode();
|
||||
var endNode = expandedRange.getEndNode();
|
||||
var startOffset = expandedRange.getStartOffset();
|
||||
var endOffset = expandedRange.getEndOffset();
|
||||
|
||||
// If we have reached a common container, now expand out.
|
||||
if (startNode == endNode) {
|
||||
while (endNode != opt_stopNode &&
|
||||
startOffset == 0 &&
|
||||
endOffset == goog.editor.node.getLength(endNode)) {
|
||||
// Select the parent instead.
|
||||
var parentNode = endNode.parentNode;
|
||||
startOffset = goog.array.indexOf(parentNode.childNodes, endNode);
|
||||
endOffset = startOffset + 1;
|
||||
endNode = parentNode;
|
||||
}
|
||||
startNode = endNode;
|
||||
}
|
||||
|
||||
return goog.dom.Range.createFromNodes(startNode, startOffset,
|
||||
endNode, endOffset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given a range, expands the start or end points as far out towards the
|
||||
* range's common container (or stopNode, if provided) as possible, while
|
||||
* perserving the same visible position.
|
||||
*
|
||||
* @param {goog.dom.AbstractRange} range The range to expand.
|
||||
* @param {goog.dom.RangeEndpoint} endpoint The endpoint to expand.
|
||||
* @param {Node=} opt_stopNode Optional node to stop expanding past.
|
||||
* @return {goog.dom.AbstractRange} The expanded range.
|
||||
* @private
|
||||
*/
|
||||
goog.editor.range.expandEndPointToContainer_ = function(range, endpoint,
|
||||
opt_stopNode) {
|
||||
var expandStart = endpoint == goog.dom.RangeEndpoint.START;
|
||||
var node = expandStart ? range.getStartNode() : range.getEndNode();
|
||||
var offset = expandStart ? range.getStartOffset() : range.getEndOffset();
|
||||
var container = range.getContainerElement();
|
||||
|
||||
// Expand the node out until we reach the container or the stop node.
|
||||
while (node != container && node != opt_stopNode) {
|
||||
// It is only valid to expand the start if we are at the start of a node
|
||||
// (offset 0) or expand the end if we are at the end of a node
|
||||
// (offset length).
|
||||
if (expandStart && offset != 0 ||
|
||||
!expandStart && offset != goog.editor.node.getLength(node)) {
|
||||
break;
|
||||
}
|
||||
|
||||
var parentNode = node.parentNode;
|
||||
var index = goog.array.indexOf(parentNode.childNodes, node);
|
||||
offset = expandStart ? index : index + 1;
|
||||
node = parentNode;
|
||||
}
|
||||
|
||||
return goog.dom.Range.createFromNodes(
|
||||
expandStart ? node : range.getStartNode(),
|
||||
expandStart ? offset : range.getStartOffset(),
|
||||
expandStart ? range.getEndNode() : node,
|
||||
expandStart ? range.getEndOffset() : offset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cause the window's selection to be the start of this node.
|
||||
* @param {Node} node The node to select the start of.
|
||||
*/
|
||||
goog.editor.range.selectNodeStart = function(node) {
|
||||
goog.dom.Range.createCaret(goog.editor.node.getLeftMostLeaf(node), 0).
|
||||
select();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Position the cursor immediately to the left or right of "node".
|
||||
* In Firefox, the selection parent is outside of "node", so the cursor can
|
||||
* effectively be moved to the end of a link node, without being considered
|
||||
* inside of it.
|
||||
* Note: This does not always work in WebKit. In particular, if you try to
|
||||
* place a cursor to the right of a link, typing still puts you in the link.
|
||||
* Bug: http://bugs.webkit.org/show_bug.cgi?id=17697
|
||||
* @param {Node} node The node to position the cursor relative to.
|
||||
* @param {boolean} toLeft True to place it to the left, false to the right.
|
||||
* @return {goog.dom.AbstractRange} The newly selected range.
|
||||
*/
|
||||
goog.editor.range.placeCursorNextTo = function(node, toLeft) {
|
||||
var parent = node.parentNode;
|
||||
var offset = goog.array.indexOf(parent.childNodes, node) +
|
||||
(toLeft ? 0 : 1);
|
||||
var point = goog.editor.range.Point.createDeepestPoint(
|
||||
parent, offset, toLeft, true);
|
||||
var range = goog.dom.Range.createCaret(point.node, point.offset);
|
||||
range.select();
|
||||
return range;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes the node, preserving the selection of the document.
|
||||
*
|
||||
* May also normalize things outside the node, if it is more efficient to do so.
|
||||
*
|
||||
* @param {Node} node The node to normalize.
|
||||
*/
|
||||
goog.editor.range.selectionPreservingNormalize = function(node) {
|
||||
var doc = goog.dom.getOwnerDocument(node);
|
||||
var selection = goog.dom.Range.createFromWindow(goog.dom.getWindow(doc));
|
||||
var normalizedRange =
|
||||
goog.editor.range.rangePreservingNormalize(node, selection);
|
||||
if (normalizedRange) {
|
||||
normalizedRange.select();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Manually normalizes the node in IE, since native normalize in IE causes
|
||||
* transient problems.
|
||||
* @param {Node} node The node to normalize.
|
||||
* @private
|
||||
*/
|
||||
goog.editor.range.normalizeNodeIe_ = function(node) {
|
||||
var lastText = null;
|
||||
var child = node.firstChild;
|
||||
while (child) {
|
||||
var next = child.nextSibling;
|
||||
if (child.nodeType == goog.dom.NodeType.TEXT) {
|
||||
if (child.nodeValue == '') {
|
||||
node.removeChild(child);
|
||||
} else if (lastText) {
|
||||
lastText.nodeValue += child.nodeValue;
|
||||
node.removeChild(child);
|
||||
} else {
|
||||
lastText = child;
|
||||
}
|
||||
} else {
|
||||
goog.editor.range.normalizeNodeIe_(child);
|
||||
lastText = null;
|
||||
}
|
||||
child = next;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes the given node.
|
||||
* @param {Node} node The node to normalize.
|
||||
*/
|
||||
goog.editor.range.normalizeNode = function(node) {
|
||||
if (goog.userAgent.IE) {
|
||||
goog.editor.range.normalizeNodeIe_(node);
|
||||
} else {
|
||||
node.normalize();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes the node, preserving a range of the document.
|
||||
*
|
||||
* May also normalize things outside the node, if it is more efficient to do so.
|
||||
*
|
||||
* @param {Node} node The node to normalize.
|
||||
* @param {goog.dom.AbstractRange?} range The range to normalize.
|
||||
* @return {goog.dom.AbstractRange?} The range, adjusted for normalization.
|
||||
*/
|
||||
goog.editor.range.rangePreservingNormalize = function(node, range) {
|
||||
if (range) {
|
||||
var rangeFactory = goog.editor.range.normalize(range);
|
||||
// WebKit has broken selection affinity, so carets tend to jump out of the
|
||||
// beginning of inline elements. This means that if we're doing the
|
||||
// normalize as the result of a range that will later become the selection,
|
||||
// we might not normalize something in the range after it is read back from
|
||||
// the selection. We can't just normalize the parentNode here because WebKit
|
||||
// can move the selection range out of multiple inline parents.
|
||||
var container = goog.editor.style.getContainer(range.getContainerElement());
|
||||
}
|
||||
|
||||
if (container) {
|
||||
goog.editor.range.normalizeNode(
|
||||
goog.dom.findCommonAncestor(container, node));
|
||||
} else if (node) {
|
||||
goog.editor.range.normalizeNode(node);
|
||||
}
|
||||
|
||||
if (rangeFactory) {
|
||||
return rangeFactory();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the deepest point in the DOM that's equivalent to the endpoint of the
|
||||
* given range.
|
||||
*
|
||||
* @param {goog.dom.AbstractRange} range A range.
|
||||
* @param {boolean} atStart True for the start point, false for the end point.
|
||||
* @return {goog.editor.range.Point} The end point, expressed as a node
|
||||
* and an offset.
|
||||
*/
|
||||
goog.editor.range.getDeepEndPoint = function(range, atStart) {
|
||||
return atStart ?
|
||||
goog.editor.range.Point.createDeepestPoint(
|
||||
range.getStartNode(), range.getStartOffset()) :
|
||||
goog.editor.range.Point.createDeepestPoint(
|
||||
range.getEndNode(), range.getEndOffset());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given a range in the current DOM, create a factory for a range that
|
||||
* represents the same selection in a normalized DOM. The factory function
|
||||
* should be invoked after the DOM is normalized.
|
||||
*
|
||||
* All browsers do a bad job preserving ranges across DOM normalization.
|
||||
* The issue is best described in this 5-year-old bug report:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=191864
|
||||
* For most applications, this isn't a problem. The browsers do a good job
|
||||
* handling un-normalized text, so there's usually no reason to normalize.
|
||||
*
|
||||
* The exception to this rule is the rich text editing commands
|
||||
* execCommand and queryCommandValue, which will fail often if there are
|
||||
* un-normalized text nodes.
|
||||
*
|
||||
* The factory function creates new ranges so that we can normalize the DOM
|
||||
* without problems. It must be created before any normalization happens,
|
||||
* and invoked after normalization happens.
|
||||
*
|
||||
* @param {goog.dom.AbstractRange} range The range to normalize. It may
|
||||
* become invalid after body.normalize() is called.
|
||||
* @return {function(): goog.dom.AbstractRange} A factory for a normalized
|
||||
* range. Should be called after body.normalize() is called.
|
||||
*/
|
||||
goog.editor.range.normalize = function(range) {
|
||||
var isReversed = range.isReversed();
|
||||
var anchorPoint = goog.editor.range.normalizePoint_(
|
||||
goog.editor.range.getDeepEndPoint(range, !isReversed));
|
||||
var anchorParent = anchorPoint.getParentPoint();
|
||||
var anchorPreviousSibling = anchorPoint.node.previousSibling;
|
||||
if (anchorPoint.node.nodeType == goog.dom.NodeType.TEXT) {
|
||||
anchorPoint.node = null;
|
||||
}
|
||||
|
||||
var focusPoint = goog.editor.range.normalizePoint_(
|
||||
goog.editor.range.getDeepEndPoint(range, isReversed));
|
||||
var focusParent = focusPoint.getParentPoint();
|
||||
var focusPreviousSibling = focusPoint.node.previousSibling;
|
||||
if (focusPoint.node.nodeType == goog.dom.NodeType.TEXT) {
|
||||
focusPoint.node = null;
|
||||
}
|
||||
|
||||
/** @return {goog.dom.AbstractRange} The normalized range. */
|
||||
return function() {
|
||||
if (!anchorPoint.node && anchorPreviousSibling) {
|
||||
// If anchorPoint.node was previously an empty text node with no siblings,
|
||||
// anchorPreviousSibling may not have a nextSibling since that node will
|
||||
// no longer exist. Do our best and point to the end of the previous
|
||||
// element.
|
||||
anchorPoint.node = anchorPreviousSibling.nextSibling;
|
||||
if (!anchorPoint.node) {
|
||||
anchorPoint = goog.editor.range.Point.getPointAtEndOfNode(
|
||||
anchorPreviousSibling);
|
||||
}
|
||||
}
|
||||
|
||||
if (!focusPoint.node && focusPreviousSibling) {
|
||||
// If focusPoint.node was previously an empty text node with no siblings,
|
||||
// focusPreviousSibling may not have a nextSibling since that node will no
|
||||
// longer exist. Do our best and point to the end of the previous
|
||||
// element.
|
||||
focusPoint.node = focusPreviousSibling.nextSibling;
|
||||
if (!focusPoint.node) {
|
||||
focusPoint = goog.editor.range.Point.getPointAtEndOfNode(
|
||||
focusPreviousSibling);
|
||||
}
|
||||
}
|
||||
|
||||
return goog.dom.Range.createFromNodes(
|
||||
anchorPoint.node || anchorParent.node.firstChild || anchorParent.node,
|
||||
anchorPoint.offset,
|
||||
focusPoint.node || focusParent.node.firstChild || focusParent.node,
|
||||
focusPoint.offset);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given a point in the current DOM, adjust it to represent the same point in
|
||||
* a normalized DOM.
|
||||
*
|
||||
* See the comments on goog.editor.range.normalize for more context.
|
||||
*
|
||||
* @param {goog.editor.range.Point} point A point in the document.
|
||||
* @return {goog.editor.range.Point} The same point, for easy chaining.
|
||||
* @private
|
||||
*/
|
||||
goog.editor.range.normalizePoint_ = function(point) {
|
||||
var previous;
|
||||
if (point.node.nodeType == goog.dom.NodeType.TEXT) {
|
||||
// If the cursor position is in a text node,
|
||||
// look at all the previous text siblings of the text node,
|
||||
// and set the offset relative to the earliest text sibling.
|
||||
for (var current = point.node.previousSibling;
|
||||
current && current.nodeType == goog.dom.NodeType.TEXT;
|
||||
current = current.previousSibling) {
|
||||
point.offset += goog.editor.node.getLength(current);
|
||||
}
|
||||
|
||||
previous = current;
|
||||
} else {
|
||||
previous = point.node.previousSibling;
|
||||
}
|
||||
|
||||
var parent = point.node.parentNode;
|
||||
point.node = previous ? previous.nextSibling : parent.firstChild;
|
||||
return point;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a range is completely inside an editable region.
|
||||
* @param {goog.dom.AbstractRange} range The range to test.
|
||||
* @return {boolean} Whether the range is completely inside an editable region.
|
||||
*/
|
||||
goog.editor.range.isEditable = function(range) {
|
||||
var rangeContainer = range.getContainerElement();
|
||||
|
||||
// Closure's implementation of getContainerElement() is a little too
|
||||
// smart in IE when exactly one element is contained in the range.
|
||||
// It assumes that there's a user whose intent was actually to select
|
||||
// all that element's children, so it returns the element itself as its
|
||||
// own containing element.
|
||||
// This little sanity check detects this condition so we can account for it.
|
||||
var rangeContainerIsOutsideRange =
|
||||
range.getStartNode() != rangeContainer.parentElement;
|
||||
|
||||
return (rangeContainerIsOutsideRange &&
|
||||
goog.editor.node.isEditableContainer(rangeContainer)) ||
|
||||
goog.editor.node.isEditable(rangeContainer);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the given range intersects with any instance of the given
|
||||
* tag.
|
||||
* @param {goog.dom.AbstractRange} range The range to check.
|
||||
* @param {goog.dom.TagName} tagName The name of the tag.
|
||||
* @return {boolean} Whether the given range intersects with any instance of
|
||||
* the given tag.
|
||||
*/
|
||||
goog.editor.range.intersectsTag = function(range, tagName) {
|
||||
if (goog.dom.getAncestorByTagNameAndClass(range.getContainerElement(),
|
||||
tagName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return goog.iter.some(range, function(node) {
|
||||
return node.tagName == tagName;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* One endpoint of a range, represented as a Node and and offset.
|
||||
* @param {Node} node The node containing the point.
|
||||
* @param {number} offset The offset of the point into the node.
|
||||
* @constructor
|
||||
*/
|
||||
goog.editor.range.Point = function(node, offset) {
|
||||
/**
|
||||
* The node containing the point.
|
||||
* @type {Node}
|
||||
*/
|
||||
this.node = node;
|
||||
|
||||
/**
|
||||
* The offset of the point into the node.
|
||||
* @type {number}
|
||||
*/
|
||||
this.offset = offset;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the point of this point's node in the DOM.
|
||||
* @return {goog.editor.range.Point} The node's point.
|
||||
*/
|
||||
goog.editor.range.Point.prototype.getParentPoint = function() {
|
||||
var parent = this.node.parentNode;
|
||||
return new goog.editor.range.Point(
|
||||
parent, goog.array.indexOf(parent.childNodes, this.node));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct the deepest possible point in the DOM that's equivalent
|
||||
* to the given point, expressed as a node and an offset.
|
||||
* @param {Node} node The node containing the point.
|
||||
* @param {number} offset The offset of the point from the node.
|
||||
* @param {boolean=} opt_trendLeft Notice that a (node, offset) pair may be
|
||||
* equivalent to more than one descendent (node, offset) pair in the DOM.
|
||||
* By default, we trend rightward. If this parameter is true, then we
|
||||
* trend leftward. The tendency to fall rightward by default is for
|
||||
* consistency with other range APIs (like placeCursorNextTo).
|
||||
* @param {boolean=} opt_stopOnChildlessElement If true, and we encounter
|
||||
* a Node which is an Element that cannot have children, we return a Point
|
||||
* based on its parent rather than that Node itself.
|
||||
* @return {goog.editor.range.Point} A new point.
|
||||
*/
|
||||
goog.editor.range.Point.createDeepestPoint =
|
||||
function(node, offset, opt_trendLeft, opt_stopOnChildlessElement) {
|
||||
while (node.nodeType == goog.dom.NodeType.ELEMENT) {
|
||||
var child = node.childNodes[offset];
|
||||
if (!child && !node.lastChild) {
|
||||
break;
|
||||
} else if (child) {
|
||||
var prevSibling = child.previousSibling;
|
||||
if (opt_trendLeft && prevSibling) {
|
||||
if (opt_stopOnChildlessElement &&
|
||||
goog.editor.range.Point.isTerminalElement_(prevSibling)) {
|
||||
break;
|
||||
}
|
||||
node = prevSibling;
|
||||
offset = goog.editor.node.getLength(node);
|
||||
} else {
|
||||
if (opt_stopOnChildlessElement &&
|
||||
goog.editor.range.Point.isTerminalElement_(child)) {
|
||||
break;
|
||||
}
|
||||
node = child;
|
||||
offset = 0;
|
||||
}
|
||||
} else {
|
||||
if (opt_stopOnChildlessElement &&
|
||||
goog.editor.range.Point.isTerminalElement_(node.lastChild)) {
|
||||
break;
|
||||
}
|
||||
node = node.lastChild;
|
||||
offset = goog.editor.node.getLength(node);
|
||||
}
|
||||
}
|
||||
|
||||
return new goog.editor.range.Point(node, offset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the specified node is an Element that is not expected to have
|
||||
* children. The createDeepestPoint() method should not traverse into
|
||||
* such elements.
|
||||
* @param {Node} node .
|
||||
* @return {boolean} True if the node is an Element that does not contain
|
||||
* child nodes (e.g. BR, IMG).
|
||||
* @private
|
||||
*/
|
||||
goog.editor.range.Point.isTerminalElement_ = function(node) {
|
||||
return (node.nodeType == goog.dom.NodeType.ELEMENT &&
|
||||
!goog.dom.canHaveChildren(node));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct a point at the very end of the given node.
|
||||
* @param {Node} node The node to create a point for.
|
||||
* @return {goog.editor.range.Point} A new point.
|
||||
*/
|
||||
goog.editor.range.Point.getPointAtEndOfNode = function(node) {
|
||||
return new goog.editor.range.Point(node, goog.editor.node.getLength(node));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Saves the range by inserting carets into the HTML.
|
||||
*
|
||||
* Unlike the regular saveUsingCarets, this SavedRange normalizes text nodes.
|
||||
* Browsers have other bugs where they don't handle split text nodes in
|
||||
* contentEditable regions right.
|
||||
*
|
||||
* @param {goog.dom.AbstractRange} range The abstract range object.
|
||||
* @return {goog.dom.SavedCaretRange} A saved caret range that normalizes
|
||||
* text nodes.
|
||||
*/
|
||||
goog.editor.range.saveUsingNormalizedCarets = function(range) {
|
||||
return new goog.editor.range.NormalizedCaretRange_(range);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Saves the range using carets, but normalizes text nodes when carets
|
||||
* are removed.
|
||||
* @see goog.editor.range.saveUsingNormalizedCarets
|
||||
* @param {goog.dom.AbstractRange} range The range being saved.
|
||||
* @constructor
|
||||
* @extends {goog.dom.SavedCaretRange}
|
||||
* @private
|
||||
*/
|
||||
goog.editor.range.NormalizedCaretRange_ = function(range) {
|
||||
goog.dom.SavedCaretRange.call(this, range);
|
||||
};
|
||||
goog.inherits(goog.editor.range.NormalizedCaretRange_,
|
||||
goog.dom.SavedCaretRange);
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes text nodes whenever carets are removed from the document.
|
||||
* @param {goog.dom.AbstractRange=} opt_range A range whose offsets have already
|
||||
* been adjusted for caret removal; it will be adjusted and returned if it
|
||||
* is also affected by post-removal operations, such as text node
|
||||
* normalization.
|
||||
* @return {goog.dom.AbstractRange|undefined} The adjusted range, if opt_range
|
||||
* was provided.
|
||||
* @override
|
||||
*/
|
||||
goog.editor.range.NormalizedCaretRange_.prototype.removeCarets =
|
||||
function(opt_range) {
|
||||
var startCaret = this.getCaret(true);
|
||||
var endCaret = this.getCaret(false);
|
||||
var node = startCaret && endCaret ?
|
||||
goog.dom.findCommonAncestor(startCaret, endCaret) :
|
||||
startCaret || endCaret;
|
||||
|
||||
goog.editor.range.NormalizedCaretRange_.superClass_.removeCarets.call(this);
|
||||
|
||||
if (opt_range) {
|
||||
return goog.editor.range.rangePreservingNormalize(node, opt_range);
|
||||
} else if (node) {
|
||||
goog.editor.range.selectionPreservingNormalize(node);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user