aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/editor/range.js
diff options
context:
space:
mode:
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/editor/range.js')
-rw-r--r--contexts/data/lib/closure-library/closure/goog/editor/range.js612
1 files changed, 0 insertions, 612 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/editor/range.js b/contexts/data/lib/closure-library/closure/goog/editor/range.js
deleted file mode 100644
index 26d8636..0000000
--- a/contexts/data/lib/closure-library/closure/goog/editor/range.js
+++ /dev/null
@@ -1,612 +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 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.BrowserFeature');
-goog.require('goog.editor.node');
-goog.require('goog.editor.style');
-goog.require('goog.iter');
-
-
-/**
- * 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);
- // NOTE: It's for fixing bug that selecting HR tag breaks
- // the cursor position In IE9. See http://b/6040468.
- if (goog.userAgent.IE && goog.userAgent.isVersion('9') &&
- point.node.nodeType == goog.dom.NodeType.ELEMENT &&
- point.node.tagName == goog.dom.TagName.HR) {
- var hr = point.node;
- point.node = hr.parentNode;
- point.offset = goog.array.indexOf(point.node.childNodes, hr) +
- (toLeft ? 0 : 1);
- }
- 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 startPoint = goog.editor.range.normalizePoint_(
- goog.editor.range.getDeepEndPoint(range, true));
- var startParent = startPoint.getParentPoint();
- var startPreviousSibling = startPoint.node.previousSibling;
- if (startPoint.node.nodeType == goog.dom.NodeType.TEXT) {
- startPoint.node = null;
- }
-
- var endPoint = goog.editor.range.normalizePoint_(
- goog.editor.range.getDeepEndPoint(range, false));
- var endParent = endPoint.getParentPoint();
- var endPreviousSibling = endPoint.node.previousSibling;
- if (endPoint.node.nodeType == goog.dom.NodeType.TEXT) {
- endPoint.node = null;
- }
-
- /** @return {goog.dom.AbstractRange} The normalized range. */
- return function() {
- if (!startPoint.node && startPreviousSibling) {
- // If startPoint.node was previously an empty text node with no siblings,
- // startPreviousSibling may not have a nextSibling since that node will no
- // longer exist. Do our best and point to the end of the previous
- // element.
- startPoint.node = startPreviousSibling.nextSibling;
- if (!startPoint.node) {
- startPoint = goog.editor.range.Point.getPointAtEndOfNode(
- startPreviousSibling);
- }
- }
-
- if (!endPoint.node && endPreviousSibling) {
- // If endPoint.node was previously an empty text node with no siblings,
- // endPreviousSibling may not have a nextSibling since that node will no
- // longer exist. Do our best and point to the end of the previous
- // element.
- endPoint.node = endPreviousSibling.nextSibling;
- if (!endPoint.node) {
- endPoint = goog.editor.range.Point.getPointAtEndOfNode(
- endPreviousSibling);
- }
- }
-
- return goog.dom.Range.createFromNodes(
- startPoint.node || startParent.node.firstChild || startParent.node,
- startPoint.offset,
- endPoint.node || endParent.node.firstChild || endParent.node,
- endPoint.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).
- * @return {goog.editor.range.Point} A new point.
- */
-goog.editor.range.Point.createDeepestPoint =
- function(node, offset, opt_trendLeft) {
- while (node.nodeType == goog.dom.NodeType.ELEMENT) {
- var child = node.childNodes[offset];
- if (!child && !node.lastChild) {
- break;
- }
- if (child) {
- var prevSibling = child.previousSibling;
- if (opt_trendLeft && prevSibling) {
- node = prevSibling;
- offset = goog.editor.node.getLength(node);
- } else {
- node = child;
- offset = 0;
- }
- } else {
- node = node.lastChild;
- offset = goog.editor.node.getLength(node);
- }
- }
-
- return new goog.editor.range.Point(node, offset);
-};
-
-
-/**
- * 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);
- }
-};