Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/dom/abstractrange.js
2868 views
1
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Interface definitions for working with ranges
17
* in HTML documents.
18
*
19
* @author [email protected] (Robby Walker)
20
*/
21
22
23
goog.provide('goog.dom.AbstractRange');
24
goog.provide('goog.dom.RangeIterator');
25
goog.provide('goog.dom.RangeType');
26
27
goog.require('goog.dom');
28
goog.require('goog.dom.NodeType');
29
goog.require('goog.dom.SavedCaretRange');
30
goog.require('goog.dom.TagIterator');
31
goog.require('goog.userAgent');
32
33
34
/**
35
* Types of ranges.
36
* @enum {string}
37
*/
38
goog.dom.RangeType = {
39
TEXT: 'text',
40
CONTROL: 'control',
41
MULTI: 'mutli'
42
};
43
44
45
46
/**
47
* Creates a new selection with no properties. Do not use this constructor -
48
* use one of the goog.dom.Range.from* methods instead.
49
* @constructor
50
*/
51
goog.dom.AbstractRange = function() {};
52
53
54
/**
55
* Gets the browser native selection object from the given window.
56
* @param {Window} win The window to get the selection object from.
57
* @return {Object} The browser native selection object, or null if it could
58
* not be retrieved.
59
*/
60
goog.dom.AbstractRange.getBrowserSelectionForWindow = function(win) {
61
if (win.getSelection) {
62
// W3C
63
return win.getSelection();
64
} else {
65
// IE
66
var doc = win.document;
67
var sel = doc.selection;
68
if (sel) {
69
// IE has a bug where it sometimes returns a selection from the wrong
70
// document. Catching these cases now helps us avoid problems later.
71
try {
72
var range = sel.createRange();
73
// Only TextRanges have a parentElement method.
74
if (range.parentElement) {
75
if (range.parentElement().document != doc) {
76
return null;
77
}
78
} else if (
79
!range.length ||
80
/** @type {ControlRange} */ (range).item(0).document != doc) {
81
// For ControlRanges, check that the range has items, and that
82
// the first item in the range is in the correct document.
83
return null;
84
}
85
} catch (e) {
86
// If the selection is in the wrong document, and the wrong document is
87
// in a different domain, IE will throw an exception.
88
return null;
89
}
90
// TODO(user|robbyw) Sometimes IE 6 returns a selection instance
91
// when there is no selection. This object has a 'type' property equals
92
// to 'None' and a typeDetail property bound to undefined. Ideally this
93
// function should not return this instance.
94
return sel;
95
}
96
return null;
97
}
98
};
99
100
101
/**
102
* Tests if the given Object is a controlRange.
103
* @param {Object} range The range object to test.
104
* @return {boolean} Whether the given Object is a controlRange.
105
*/
106
goog.dom.AbstractRange.isNativeControlRange = function(range) {
107
// For now, tests for presence of a control range function.
108
return !!range && !!range.addElement;
109
};
110
111
112
/**
113
* @return {!goog.dom.AbstractRange} A clone of this range.
114
*/
115
goog.dom.AbstractRange.prototype.clone = goog.abstractMethod;
116
117
118
/**
119
* @return {goog.dom.RangeType} The type of range represented by this object.
120
*/
121
goog.dom.AbstractRange.prototype.getType = goog.abstractMethod;
122
123
124
/**
125
* @return {Range|TextRange} The native browser range object.
126
*/
127
goog.dom.AbstractRange.prototype.getBrowserRangeObject = goog.abstractMethod;
128
129
130
/**
131
* Sets the native browser range object, overwriting any state this range was
132
* storing.
133
* @param {Range|TextRange} nativeRange The native browser range object.
134
* @return {boolean} Whether the given range was accepted. If not, the caller
135
* will need to call goog.dom.Range.createFromBrowserRange to create a new
136
* range object.
137
*/
138
goog.dom.AbstractRange.prototype.setBrowserRangeObject = function(nativeRange) {
139
return false;
140
};
141
142
143
/**
144
* @return {number} The number of text ranges in this range.
145
*/
146
goog.dom.AbstractRange.prototype.getTextRangeCount = goog.abstractMethod;
147
148
149
/**
150
* Get the i-th text range in this range. The behavior is undefined if
151
* i >= getTextRangeCount or i < 0.
152
* @param {number} i The range number to retrieve.
153
* @return {goog.dom.TextRange} The i-th text range.
154
*/
155
goog.dom.AbstractRange.prototype.getTextRange = goog.abstractMethod;
156
157
158
/**
159
* Gets an array of all text ranges this range is comprised of. For non-multi
160
* ranges, returns a single element array containing this.
161
* @return {!Array<goog.dom.TextRange>} Array of text ranges.
162
*/
163
goog.dom.AbstractRange.prototype.getTextRanges = function() {
164
var output = [];
165
for (var i = 0, len = this.getTextRangeCount(); i < len; i++) {
166
output.push(this.getTextRange(i));
167
}
168
return output;
169
};
170
171
172
/**
173
* @return {Node} The deepest node that contains the entire range.
174
*/
175
goog.dom.AbstractRange.prototype.getContainer = goog.abstractMethod;
176
177
178
/**
179
* Returns the deepest element in the tree that contains the entire range.
180
* @return {Element} The deepest element that contains the entire range.
181
*/
182
goog.dom.AbstractRange.prototype.getContainerElement = function() {
183
var node = this.getContainer();
184
return /** @type {Element} */ (
185
node.nodeType == goog.dom.NodeType.ELEMENT ? node : node.parentNode);
186
};
187
188
189
/**
190
* @return {Node} The element or text node the range starts in. For text
191
* ranges, the range comprises all text between the start and end position.
192
* For other types of range, start and end give bounds of the range but
193
* do not imply all nodes in those bounds are selected.
194
*/
195
goog.dom.AbstractRange.prototype.getStartNode = goog.abstractMethod;
196
197
198
/**
199
* @return {number} The offset into the node the range starts in. For text
200
* nodes, this is an offset into the node value. For elements, this is
201
* an offset into the childNodes array.
202
*/
203
goog.dom.AbstractRange.prototype.getStartOffset = goog.abstractMethod;
204
205
206
/**
207
* @return {goog.math.Coordinate} The coordinate of the selection start node
208
* and offset.
209
*/
210
goog.dom.AbstractRange.prototype.getStartPosition = goog.abstractMethod;
211
212
213
/**
214
* @return {Node} The element or text node the range ends in.
215
*/
216
goog.dom.AbstractRange.prototype.getEndNode = goog.abstractMethod;
217
218
219
/**
220
* @return {number} The offset into the node the range ends in. For text
221
* nodes, this is an offset into the node value. For elements, this is
222
* an offset into the childNodes array.
223
*/
224
goog.dom.AbstractRange.prototype.getEndOffset = goog.abstractMethod;
225
226
227
/**
228
* @return {goog.math.Coordinate} The coordinate of the selection end
229
* node and offset.
230
*/
231
goog.dom.AbstractRange.prototype.getEndPosition = goog.abstractMethod;
232
233
234
/**
235
* @return {Node} The element or text node the range is anchored at.
236
*/
237
goog.dom.AbstractRange.prototype.getAnchorNode = function() {
238
return this.isReversed() ? this.getEndNode() : this.getStartNode();
239
};
240
241
242
/**
243
* @return {number} The offset into the node the range is anchored at. For
244
* text nodes, this is an offset into the node value. For elements, this
245
* is an offset into the childNodes array.
246
*/
247
goog.dom.AbstractRange.prototype.getAnchorOffset = function() {
248
return this.isReversed() ? this.getEndOffset() : this.getStartOffset();
249
};
250
251
252
/**
253
* @return {Node} The element or text node the range is focused at - i.e. where
254
* the cursor is.
255
*/
256
goog.dom.AbstractRange.prototype.getFocusNode = function() {
257
return this.isReversed() ? this.getStartNode() : this.getEndNode();
258
};
259
260
261
/**
262
* @return {number} The offset into the node the range is focused at - i.e.
263
* where the cursor is. For text nodes, this is an offset into the node
264
* value. For elements, this is an offset into the childNodes array.
265
*/
266
goog.dom.AbstractRange.prototype.getFocusOffset = function() {
267
return this.isReversed() ? this.getStartOffset() : this.getEndOffset();
268
};
269
270
271
/**
272
* @return {boolean} Whether the selection is reversed.
273
*/
274
goog.dom.AbstractRange.prototype.isReversed = function() {
275
return false;
276
};
277
278
279
/**
280
* @return {!Document} The document this selection is a part of.
281
*/
282
goog.dom.AbstractRange.prototype.getDocument = function() {
283
// Using start node in IE was crashing the browser in some cases so use
284
// getContainer for that browser. It's also faster for IE, but still slower
285
// than start node for other browsers so we continue to use getStartNode when
286
// it is not problematic. See bug 1687309.
287
return goog.dom.getOwnerDocument(
288
goog.userAgent.IE ? this.getContainer() : this.getStartNode());
289
};
290
291
292
/**
293
* @return {!Window} The window this selection is a part of.
294
*/
295
goog.dom.AbstractRange.prototype.getWindow = function() {
296
return goog.dom.getWindow(this.getDocument());
297
};
298
299
300
/**
301
* Tests if this range contains the given range.
302
* @param {goog.dom.AbstractRange} range The range to test.
303
* @param {boolean=} opt_allowPartial If true, the range can be partially
304
* contained in the selection, otherwise the range must be entirely
305
* contained.
306
* @return {boolean} Whether this range contains the given range.
307
*/
308
goog.dom.AbstractRange.prototype.containsRange = goog.abstractMethod;
309
310
311
/**
312
* Tests if this range contains the given node.
313
* @param {Node} node The node to test for.
314
* @param {boolean=} opt_allowPartial If not set or false, the node must be
315
* entirely contained in the selection for this function to return true.
316
* @return {boolean} Whether this range contains the given node.
317
*/
318
goog.dom.AbstractRange.prototype.containsNode = goog.abstractMethod;
319
320
321
322
/**
323
* Tests whether this range is valid (i.e. whether its endpoints are still in
324
* the document). A range becomes invalid when, after this object was created,
325
* either one or both of its endpoints are removed from the document. Use of
326
* an invalid range can lead to runtime errors, particularly in IE.
327
* @return {boolean} Whether the range is valid.
328
*/
329
goog.dom.AbstractRange.prototype.isRangeInDocument = goog.abstractMethod;
330
331
332
/**
333
* @return {boolean} Whether the range is collapsed.
334
*/
335
goog.dom.AbstractRange.prototype.isCollapsed = goog.abstractMethod;
336
337
338
/**
339
* @return {string} The text content of the range.
340
*/
341
goog.dom.AbstractRange.prototype.getText = goog.abstractMethod;
342
343
344
/**
345
* Returns the HTML fragment this range selects. This is slow on all browsers.
346
* The HTML fragment may not be valid HTML, for instance if the user selects
347
* from a to b inclusively in the following html:
348
*
349
* &lt;div&gt;a&lt;/div&gt;b
350
*
351
* This method will return
352
*
353
* a&lt;/div&gt;b
354
*
355
* If you need valid HTML, use {@link #getValidHtml} instead.
356
*
357
* @return {string} HTML fragment of the range, does not include context
358
* containing elements.
359
*/
360
goog.dom.AbstractRange.prototype.getHtmlFragment = goog.abstractMethod;
361
362
363
/**
364
* Returns valid HTML for this range. This is fast on IE, and semi-fast on
365
* other browsers.
366
* @return {string} Valid HTML of the range, including context containing
367
* elements.
368
*/
369
goog.dom.AbstractRange.prototype.getValidHtml = goog.abstractMethod;
370
371
372
/**
373
* Returns pastable HTML for this range. This guarantees that any child items
374
* that must have specific ancestors will have them, for instance all TDs will
375
* be contained in a TR in a TBODY in a TABLE and all LIs will be contained in
376
* a UL or OL as appropriate. This is semi-fast on all browsers.
377
* @return {string} Pastable HTML of the range, including context containing
378
* elements.
379
*/
380
goog.dom.AbstractRange.prototype.getPastableHtml = goog.abstractMethod;
381
382
383
/**
384
* Returns a RangeIterator over the contents of the range. Regardless of the
385
* direction of the range, the iterator will move in document order.
386
* @param {boolean=} opt_keys Unused for this iterator.
387
* @return {!goog.dom.RangeIterator} An iterator over tags in the range.
388
*/
389
goog.dom.AbstractRange.prototype.__iterator__ = goog.abstractMethod;
390
391
392
// RANGE ACTIONS
393
394
395
/**
396
* Sets this range as the selection in its window.
397
*/
398
goog.dom.AbstractRange.prototype.select = goog.abstractMethod;
399
400
401
/**
402
* Removes the contents of the range from the document.
403
*/
404
goog.dom.AbstractRange.prototype.removeContents = goog.abstractMethod;
405
406
407
/**
408
* Inserts a node before (or after) the range. The range may be disrupted
409
* beyond recovery because of the way this splits nodes.
410
* @param {Node} node The node to insert.
411
* @param {boolean} before True to insert before, false to insert after.
412
* @return {Node} The node added to the document. This may be different
413
* than the node parameter because on IE we have to clone it.
414
*/
415
goog.dom.AbstractRange.prototype.insertNode = goog.abstractMethod;
416
417
418
/**
419
* Replaces the range contents with (possibly a copy of) the given node. The
420
* range may be disrupted beyond recovery because of the way this splits nodes.
421
* @param {Node} node The node to insert.
422
* @return {Node} The node added to the document. This may be different
423
* than the node parameter because on IE we have to clone it.
424
*/
425
goog.dom.AbstractRange.prototype.replaceContentsWithNode = function(node) {
426
if (!this.isCollapsed()) {
427
this.removeContents();
428
}
429
430
return this.insertNode(node, true);
431
};
432
433
434
/**
435
* Surrounds this range with the two given nodes. The range may be disrupted
436
* beyond recovery because of the way this splits nodes.
437
* @param {Element} startNode The node to insert at the start.
438
* @param {Element} endNode The node to insert at the end.
439
*/
440
goog.dom.AbstractRange.prototype.surroundWithNodes = goog.abstractMethod;
441
442
443
// SAVE/RESTORE
444
445
446
/**
447
* Saves the range so that if the start and end nodes are left alone, it can
448
* be restored.
449
* @return {!goog.dom.SavedRange} A range representation that can be restored
450
* as long as the endpoint nodes of the selection are not modified.
451
*/
452
goog.dom.AbstractRange.prototype.saveUsingDom = goog.abstractMethod;
453
454
455
/**
456
* Saves the range using HTML carets. As long as the carets remained in the
457
* HTML, the range can be restored...even when the HTML is copied across
458
* documents.
459
* @return {goog.dom.SavedCaretRange?} A range representation that can be
460
* restored as long as carets are not removed. Returns null if carets
461
* could not be created.
462
*/
463
goog.dom.AbstractRange.prototype.saveUsingCarets = function() {
464
return (this.getStartNode() && this.getEndNode()) ?
465
new goog.dom.SavedCaretRange(this) :
466
null;
467
};
468
469
470
// RANGE MODIFICATION
471
472
473
/**
474
* Collapses the range to one of its boundary points.
475
* @param {boolean} toAnchor Whether to collapse to the anchor of the range.
476
*/
477
goog.dom.AbstractRange.prototype.collapse = goog.abstractMethod;
478
479
// RANGE ITERATION
480
481
482
483
/**
484
* Subclass of goog.dom.TagIterator that iterates over a DOM range. It
485
* adds functions to determine the portion of each text node that is selected.
486
* @param {Node} node The node to start traversal at. When null, creates an
487
* empty iterator.
488
* @param {boolean=} opt_reverse Whether to traverse nodes in reverse.
489
* @constructor
490
* @extends {goog.dom.TagIterator}
491
*/
492
goog.dom.RangeIterator = function(node, opt_reverse) {
493
goog.dom.TagIterator.call(this, node, opt_reverse, true);
494
};
495
goog.inherits(goog.dom.RangeIterator, goog.dom.TagIterator);
496
497
498
/**
499
* @return {number} The offset into the current node, or -1 if the current node
500
* is not a text node.
501
*/
502
goog.dom.RangeIterator.prototype.getStartTextOffset = goog.abstractMethod;
503
504
505
/**
506
* @return {number} The end offset into the current node, or -1 if the current
507
* node is not a text node.
508
*/
509
goog.dom.RangeIterator.prototype.getEndTextOffset = goog.abstractMethod;
510
511
512
/**
513
* @return {Node} node The iterator's start node.
514
*/
515
goog.dom.RangeIterator.prototype.getStartNode = goog.abstractMethod;
516
517
518
/**
519
* @return {Node} The iterator's end node.
520
*/
521
goog.dom.RangeIterator.prototype.getEndNode = goog.abstractMethod;
522
523
524
/**
525
* @return {boolean} Whether a call to next will fail.
526
*/
527
goog.dom.RangeIterator.prototype.isLast = goog.abstractMethod;
528
529