123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- // Copyright 2007 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 Definition of the browser range interface.
- *
- * DO NOT USE THIS FILE DIRECTLY. Use goog.dom.Range instead.
- *
- * @author robbyw@google.com (Robby Walker)
- */
- goog.provide('goog.dom.browserrange.AbstractRange');
- goog.require('goog.array');
- goog.require('goog.asserts');
- goog.require('goog.dom');
- goog.require('goog.dom.NodeType');
- goog.require('goog.dom.RangeEndpoint');
- goog.require('goog.dom.TagName');
- goog.require('goog.dom.TextRangeIterator');
- goog.require('goog.iter');
- goog.require('goog.math.Coordinate');
- goog.require('goog.string');
- goog.require('goog.string.StringBuffer');
- goog.require('goog.userAgent');
- /**
- * The constructor for abstract ranges. Don't call this from subclasses.
- * @constructor
- */
- goog.dom.browserrange.AbstractRange = function() {};
- /**
- * @return {goog.dom.browserrange.AbstractRange} A clone of this range.
- */
- goog.dom.browserrange.AbstractRange.prototype.clone = goog.abstractMethod;
- /**
- * Returns the browser native implementation of the range. Please refrain from
- * using this function - if you find you need the range please add wrappers for
- * the functionality you need rather than just using the native range.
- * @return {Range|TextRange} The browser native range object.
- */
- goog.dom.browserrange.AbstractRange.prototype.getBrowserRange =
- goog.abstractMethod;
- /**
- * Returns the deepest node in the tree that contains the entire range.
- * @return {Node} The deepest node that contains the entire range.
- */
- goog.dom.browserrange.AbstractRange.prototype.getContainer =
- goog.abstractMethod;
- /**
- * Returns the node the range starts in.
- * @return {Node} The element or text node the range starts in.
- */
- goog.dom.browserrange.AbstractRange.prototype.getStartNode =
- goog.abstractMethod;
- /**
- * Returns the offset into the node the range starts in.
- * @return {number} The offset into the node the range starts in. For text
- * nodes, this is an offset into the node value. For elements, this is
- * an offset into the childNodes array.
- */
- goog.dom.browserrange.AbstractRange.prototype.getStartOffset =
- goog.abstractMethod;
- /**
- * @return {goog.math.Coordinate} The coordinate of the selection start node
- * and offset.
- */
- goog.dom.browserrange.AbstractRange.prototype.getStartPosition = function() {
- return this.getPosition_(true);
- };
- /**
- * Returns the node the range ends in.
- * @return {Node} The element or text node the range ends in.
- */
- goog.dom.browserrange.AbstractRange.prototype.getEndNode = goog.abstractMethod;
- /**
- * Returns the offset into the node the range ends in.
- * @return {number} The offset into the node the range ends in. For text
- * nodes, this is an offset into the node value. For elements, this is
- * an offset into the childNodes array.
- */
- goog.dom.browserrange.AbstractRange.prototype.getEndOffset =
- goog.abstractMethod;
- /**
- * @return {goog.math.Coordinate} The coordinate of the selection end node
- * and offset.
- */
- goog.dom.browserrange.AbstractRange.prototype.getEndPosition = function() {
- return this.getPosition_(false);
- };
- /**
- * @param {boolean} start Whether to get the position of the start or end.
- * @return {goog.math.Coordinate} The coordinate of the selection point.
- * @private
- */
- goog.dom.browserrange.AbstractRange.prototype.getPosition_ = function(start) {
- goog.asserts.assert(
- this.range_.getClientRects,
- 'Getting selection coordinates is not supported.');
- var rects = this.range_.getClientRects();
- if (rects.length) {
- var r = start ? rects[0] : goog.array.peek(rects);
- return new goog.math.Coordinate(
- start ? r.left : r.right, start ? r.top : r.bottom);
- }
- return null;
- };
- /**
- * Compares one endpoint of this range with the endpoint of another browser
- * native range object.
- * @param {Range|TextRange} range The browser native range to compare against.
- * @param {goog.dom.RangeEndpoint} thisEndpoint The endpoint of this range
- * to compare with.
- * @param {goog.dom.RangeEndpoint} otherEndpoint The endpoint of the other
- * range to compare with.
- * @return {number} 0 if the endpoints are equal, negative if this range
- * endpoint comes before the other range endpoint, and positive otherwise.
- */
- goog.dom.browserrange.AbstractRange.prototype.compareBrowserRangeEndpoints =
- goog.abstractMethod;
- /**
- * Tests if this range contains the given range.
- * @param {goog.dom.browserrange.AbstractRange} abstractRange The range to test.
- * @param {boolean=} opt_allowPartial If not set or false, the range must be
- * entirely contained in the selection for this function to return true.
- * @return {boolean} Whether this range contains the given range.
- */
- goog.dom.browserrange.AbstractRange.prototype.containsRange = function(
- abstractRange, opt_allowPartial) {
- // IE sometimes misreports the boundaries for collapsed ranges. So if the
- // other range is collapsed, make sure the whole range is contained. This is
- // logically equivalent, and works around IE's bug.
- var checkPartial = opt_allowPartial && !abstractRange.isCollapsed();
- var range = abstractRange.getBrowserRange();
- var start = goog.dom.RangeEndpoint.START, end = goog.dom.RangeEndpoint.END;
- try {
- if (checkPartial) {
- // There are two ways to not overlap. Being before, and being after.
- // Before is represented by this.end before range.start: comparison < 0.
- // After is represented by this.start after range.end: comparison > 0.
- // The below is the negation of not overlapping.
- return this.compareBrowserRangeEndpoints(range, end, start) >= 0 &&
- this.compareBrowserRangeEndpoints(range, start, end) <= 0;
- } else {
- // Return true if this range bounds the parameter range from both sides.
- return this.compareBrowserRangeEndpoints(range, end, end) >= 0 &&
- this.compareBrowserRangeEndpoints(range, start, start) <= 0;
- }
- } catch (e) {
- if (!goog.userAgent.IE) {
- throw e;
- }
- // IE sometimes throws exceptions when one range is invalid, i.e. points
- // to a node that has been removed from the document. Return false in this
- // case.
- return false;
- }
- };
- /**
- * Tests if this range contains the given node.
- * @param {Node} node The node to test.
- * @param {boolean=} opt_allowPartial If not set or false, the node must be
- * entirely contained in the selection for this function to return true.
- * @return {boolean} Whether this range contains the given node.
- * @suppress {missingRequire} Cannot depend on goog.dom.browserrange because it
- * creates a circular dependency.
- */
- goog.dom.browserrange.AbstractRange.prototype.containsNode = function(
- node, opt_allowPartial) {
- /** @suppress {missingRequire} Circular dep with browserrange */
- return this.containsRange(
- goog.dom.browserrange.createRangeFromNodeContents(node),
- opt_allowPartial);
- };
- /**
- * Tests if the selection is collapsed - i.e. is just a caret.
- * @return {boolean} Whether the range is collapsed.
- */
- goog.dom.browserrange.AbstractRange.prototype.isCollapsed = goog.abstractMethod;
- /**
- * @return {string} The text content of the range.
- */
- goog.dom.browserrange.AbstractRange.prototype.getText = goog.abstractMethod;
- /**
- * Returns the HTML fragment this range selects. This is slow on all browsers.
- * @return {string} HTML fragment of the range, does not include context
- * containing elements.
- */
- goog.dom.browserrange.AbstractRange.prototype.getHtmlFragment = function() {
- var output = new goog.string.StringBuffer();
- goog.iter.forEach(this, function(node, ignore, it) {
- if (node.nodeType == goog.dom.NodeType.TEXT) {
- output.append(
- goog.string.htmlEscape(
- node.nodeValue.substring(
- it.getStartTextOffset(), it.getEndTextOffset())));
- } else if (node.nodeType == goog.dom.NodeType.ELEMENT) {
- if (it.isEndTag()) {
- if (goog.dom.canHaveChildren(node)) {
- output.append('</' + node.tagName + '>');
- }
- } else {
- var shallow = node.cloneNode(false);
- var html = goog.dom.getOuterHtml(shallow);
- if (goog.userAgent.IE && node.tagName == goog.dom.TagName.LI) {
- // For an LI, IE just returns "<li>" with no closing tag
- output.append(html);
- } else {
- var index = html.lastIndexOf('<');
- output.append(index ? html.substr(0, index) : html);
- }
- }
- }
- }, this);
- return output.toString();
- };
- /**
- * Returns valid HTML for this range. This is fast on IE, and semi-fast on
- * other browsers.
- * @return {string} Valid HTML of the range, including context containing
- * elements.
- */
- goog.dom.browserrange.AbstractRange.prototype.getValidHtml =
- goog.abstractMethod;
- /**
- * Returns a RangeIterator over the contents of the range. Regardless of the
- * direction of the range, the iterator will move in document order.
- * @param {boolean=} opt_keys Unused for this iterator.
- * @return {!goog.dom.RangeIterator} An iterator over tags in the range.
- */
- goog.dom.browserrange.AbstractRange.prototype.__iterator__ = function(
- opt_keys) {
- return new goog.dom.TextRangeIterator(
- this.getStartNode(), this.getStartOffset(), this.getEndNode(),
- this.getEndOffset());
- };
- // SELECTION MODIFICATION
- /**
- * Set this range as the selection in its window.
- * @param {boolean=} opt_reverse Whether to select the range in reverse,
- * if possible.
- */
- goog.dom.browserrange.AbstractRange.prototype.select = goog.abstractMethod;
- /**
- * Removes the contents of the range from the document. As a side effect, the
- * selection will be collapsed. The behavior of content removal is normalized
- * across browsers. For instance, IE sometimes creates extra text nodes that
- * a W3C browser does not. That behavior is corrected for.
- */
- goog.dom.browserrange.AbstractRange.prototype.removeContents =
- goog.abstractMethod;
- /**
- * Surrounds the text range with the specified element (on Mozilla) or with a
- * clone of the specified element (on IE). Returns a reference to the
- * surrounding element if the operation was successful; returns null if the
- * operation failed.
- * @param {Element} element The element with which the selection is to be
- * surrounded.
- * @return {Element} The surrounding element (same as the argument on Mozilla,
- * but not on IE), or null if unsuccessful.
- */
- goog.dom.browserrange.AbstractRange.prototype.surroundContents =
- goog.abstractMethod;
- /**
- * Inserts a node before (or after) the range. The range may be disrupted
- * beyond recovery because of the way this splits nodes.
- * @param {Node} node The node to insert.
- * @param {boolean} before True to insert before, false to insert after.
- * @return {Node} The node added to the document. This may be different
- * than the node parameter because on IE we have to clone it.
- */
- goog.dom.browserrange.AbstractRange.prototype.insertNode = goog.abstractMethod;
- /**
- * Surrounds this range with the two given nodes. The range may be disrupted
- * beyond recovery because of the way this splits nodes.
- * @param {Element} startNode The node to insert at the start.
- * @param {Element} endNode The node to insert at the end.
- */
- goog.dom.browserrange.AbstractRange.prototype.surroundWithNodes =
- goog.abstractMethod;
- /**
- * Collapses the range to one of its boundary points.
- * @param {boolean} toStart Whether to collapse to the start of the range.
- */
- goog.dom.browserrange.AbstractRange.prototype.collapse = goog.abstractMethod;
|