aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/dom/browserrange/abstractrange.js
blob: 8875b33d0750cd03868a6eb9643ed7d5b53f7f21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// 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)
 * @author ojan@google.com (Ojan Vafai)
 * @author jparent@google.com (Julie Parent)
 */


goog.provide('goog.dom.browserrange.AbstractRange');

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.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;


/**
 * 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;


/**
 * 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;
  /** {@preserveTry} */
  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.
 */
goog.dom.browserrange.AbstractRange.prototype.containsNode = function(node,
    opt_allowPartial) {
  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;