Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(669)

Side by Side Diff: ui/accessibility/extensions/caretbrowsing/traverse_util.js

Issue 606653005: Revert "Initial checkin of accessibility extensions." (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 Google Inc.
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 Low-level DOM traversal utility functions to find the
17 * next (or previous) character, word, sentence, line, or paragraph,
18 * in a completely stateless manner without actually manipulating the
19 * selection.
20 */
21
22 /**
23 * A class to represent a cursor location in the document,
24 * like the start position or end position of a selection range.
25 *
26 * Later this may be extended to support "virtual text" for an object,
27 * like the ALT text for an image.
28 *
29 * Note: we cache the text of a particular node at the time we
30 * traverse into it. Later we should add support for dynamically
31 * reloading it.
32 * @param {Node} node The DOM node.
33 * @param {number} index The index of the character within the node.
34 * @param {string} text The cached text contents of the node.
35 * @constructor
36 */
37 Cursor = function(node, index, text) {
38 this.node = node;
39 this.index = index;
40 this.text = text;
41 };
42
43 /**
44 * @return {Cursor} A new cursor pointing to the same location.
45 */
46 Cursor.prototype.clone = function() {
47 return new Cursor(this.node, this.index, this.text);
48 };
49
50 /**
51 * Modify this cursor to point to the location that another cursor points to.
52 * @param {Cursor} otherCursor The cursor to copy from.
53 */
54 Cursor.prototype.copyFrom = function(otherCursor) {
55 this.node = otherCursor.node;
56 this.index = otherCursor.index;
57 this.text = otherCursor.text;
58 };
59
60 /**
61 * Utility functions for stateless DOM traversal.
62 * @constructor
63 */
64 TraverseUtil = function() {};
65
66 /**
67 * Gets the text representation of a node. This allows us to substitute
68 * alt text, names, or titles for html elements that provide them.
69 * @param {Node} node A DOM node.
70 * @return {string} A text string representation of the node.
71 */
72 TraverseUtil.getNodeText = function(node) {
73 if (node.constructor == Text) {
74 return node.data;
75 } else {
76 return '';
77 }
78 };
79
80 /**
81 * Return true if a node should be treated as a leaf node, because
82 * its children are properties of the object that shouldn't be traversed.
83 *
84 * TODO(dmazzoni): replace this with a predicate that detects nodes with
85 * ARIA roles and other objects that have their own description.
86 * For now we just detect a couple of common cases.
87 *
88 * @param {Node} node A DOM node.
89 * @return {boolean} True if the node should be treated as a leaf node.
90 */
91 TraverseUtil.treatAsLeafNode = function(node) {
92 return node.childNodes.length == 0 ||
93 node.nodeName == 'SELECT' ||
94 node.nodeName == 'OBJECT';
95 };
96
97 /**
98 * Return true only if a single character is whitespace.
99 * From https://developer.mozilla.org/en/Whitespace_in_the_DOM,
100 * whitespace is defined as one of the characters
101 * "\t" TAB \u0009
102 * "\n" LF \u000A
103 * "\r" CR \u000D
104 * " " SPC \u0020.
105 *
106 * @param {string} c A string containing a single character.
107 * @return {boolean} True if the character is whitespace, otherwise false.
108 */
109 TraverseUtil.isWhitespace = function(c) {
110 return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
111 };
112
113 /**
114 * Set the selection to the range between the given start and end cursors.
115 * @param {Cursor} start The desired start of the selection.
116 * @param {Cursor} end The desired end of the selection.
117 * @return {Selection} the selection object.
118 */
119 TraverseUtil.setSelection = function(start, end) {
120 var sel = window.getSelection();
121 sel.removeAllRanges();
122 var range = document.createRange();
123 range.setStart(start.node, start.index);
124 range.setEnd(end.node, end.index);
125 sel.addRange(range);
126
127 return sel;
128 };
129
130 /**
131 * Use the computed CSS style to figure out if this DOM node is currently
132 * visible.
133 * @param {Node} node A HTML DOM node.
134 * @return {boolean} Whether or not the html node is visible.
135 */
136 TraverseUtil.isVisible = function(node) {
137 if (!node.style)
138 return true;
139 var style = window.getComputedStyle(/** @type {Element} */(node), null);
140 return (!!style && style.display != 'none' && style.visibility != 'hidden');
141 };
142
143 /**
144 * Use the class name to figure out if this DOM node should be traversed.
145 * @param {Node} node A HTML DOM node.
146 * @return {boolean} Whether or not the html node should be traversed.
147 */
148 TraverseUtil.isSkipped = function(node) {
149 if (node.constructor == Text)
150 node = node.parentElement;
151 if (node.className == 'CaretBrowsing_Caret' ||
152 node.className == 'CaretBrowsing_AnimateCaret') {
153 return true;
154 }
155 return false;
156 };
157
158 /**
159 * Moves the cursor forwards until it has crossed exactly one character.
160 * @param {Cursor} cursor The cursor location where the search should start.
161 * On exit, the cursor will be immediately to the right of the
162 * character returned.
163 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
164 * initial and final cursor position will be pushed onto this array.
165 * @return {?string} The character found, or null if the bottom of the
166 * document has been reached.
167 */
168 TraverseUtil.forwardsChar = function(cursor, nodesCrossed) {
169 while (true) {
170 // Move down until we get to a leaf node.
171 var childNode = null;
172 if (!TraverseUtil.treatAsLeafNode(cursor.node)) {
173 for (var i = cursor.index; i < cursor.node.childNodes.length; i++) {
174 var node = cursor.node.childNodes[i];
175 if (TraverseUtil.isSkipped(node)) {
176 nodesCrossed.push(node);
177 continue;
178 }
179 if (TraverseUtil.isVisible(node)) {
180 childNode = node;
181 break;
182 }
183 }
184 }
185 if (childNode) {
186 cursor.node = childNode;
187 cursor.index = 0;
188 cursor.text = TraverseUtil.getNodeText(cursor.node);
189 if (cursor.node.constructor != Text) {
190 nodesCrossed.push(cursor.node);
191 }
192 continue;
193 }
194
195 // Return the next character from this leaf node.
196 if (cursor.index < cursor.text.length)
197 return cursor.text[cursor.index++];
198
199 // Move to the next sibling, going up the tree as necessary.
200 while (cursor.node != null) {
201 // Try to move to the next sibling.
202 var siblingNode = null;
203 for (var node = cursor.node.nextSibling;
204 node != null;
205 node = node.nextSibling) {
206 if (TraverseUtil.isSkipped(node)) {
207 nodesCrossed.push(node);
208 continue;
209 }
210 if (TraverseUtil.isVisible(node)) {
211 siblingNode = node;
212 break;
213 }
214 }
215 if (siblingNode) {
216 cursor.node = siblingNode;
217 cursor.text = TraverseUtil.getNodeText(siblingNode);
218 cursor.index = 0;
219
220 if (cursor.node.constructor != Text) {
221 nodesCrossed.push(cursor.node);
222 }
223
224 break;
225 }
226
227 // Otherwise, move to the parent.
228 if (cursor.node.parentNode &&
229 cursor.node.parentNode.constructor != HTMLBodyElement) {
230 cursor.node = cursor.node.parentNode;
231 cursor.text = null;
232 cursor.index = 0;
233 } else {
234 return null;
235 }
236 }
237 }
238 };
239
240 /**
241 * Moves the cursor backwards until it has crossed exactly one character.
242 * @param {Cursor} cursor The cursor location where the search should start.
243 * On exit, the cursor will be immediately to the left of the
244 * character returned.
245 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
246 * initial and final cursor position will be pushed onto this array.
247 * @return {?string} The previous character, or null if the top of the
248 * document has been reached.
249 */
250 TraverseUtil.backwardsChar = function(cursor, nodesCrossed) {
251 while (true) {
252 // Move down until we get to a leaf node.
253 var childNode = null;
254 if (!TraverseUtil.treatAsLeafNode(cursor.node)) {
255 for (var i = cursor.index - 1; i >= 0; i--) {
256 var node = cursor.node.childNodes[i];
257 if (TraverseUtil.isSkipped(node)) {
258 nodesCrossed.push(node);
259 continue;
260 }
261 if (TraverseUtil.isVisible(node)) {
262 childNode = node;
263 break;
264 }
265 }
266 }
267 if (childNode) {
268 cursor.node = childNode;
269 cursor.text = TraverseUtil.getNodeText(cursor.node);
270 if (cursor.text.length)
271 cursor.index = cursor.text.length;
272 else
273 cursor.index = cursor.node.childNodes.length;
274 if (cursor.node.constructor != Text)
275 nodesCrossed.push(cursor.node);
276 continue;
277 }
278
279 // Return the previous character from this leaf node.
280 if (cursor.text.length > 0 && cursor.index > 0) {
281 return cursor.text[--cursor.index];
282 }
283
284 // Move to the previous sibling, going up the tree as necessary.
285 while (true) {
286 // Try to move to the previous sibling.
287 var siblingNode = null;
288 for (var node = cursor.node.previousSibling;
289 node != null;
290 node = node.previousSibling) {
291 if (TraverseUtil.isSkipped(node)) {
292 nodesCrossed.push(node);
293 continue;
294 }
295 if (TraverseUtil.isVisible(node)) {
296 siblingNode = node;
297 break;
298 }
299 }
300 if (siblingNode) {
301 cursor.node = siblingNode;
302 cursor.text = TraverseUtil.getNodeText(siblingNode);
303 if (cursor.text.length)
304 cursor.index = cursor.text.length;
305 else
306 cursor.index = cursor.node.childNodes.length;
307 if (cursor.node.constructor != Text)
308 nodesCrossed.push(cursor.node);
309 break;
310 }
311
312 // Otherwise, move to the parent.
313 if (cursor.node.parentNode &&
314 cursor.node.parentNode.constructor != HTMLBodyElement) {
315 cursor.node = cursor.node.parentNode;
316 cursor.text = null;
317 cursor.index = 0;
318 } else {
319 return null;
320 }
321 }
322 }
323 };
324
325 /**
326 * Finds the next character, starting from endCursor. Upon exit, startCursor
327 * and endCursor will surround the next character. If skipWhitespace is
328 * true, will skip until a real character is found. Otherwise, it will
329 * attempt to select all of the whitespace between the initial position
330 * of endCursor and the next non-whitespace character.
331 * @param {Cursor} startCursor On exit, points to the position before
332 * the char.
333 * @param {Cursor} endCursor The position to start searching for the next
334 * char. On exit, will point to the position past the char.
335 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
336 * initial and final cursor position will be pushed onto this array.
337 * @param {boolean} skipWhitespace If true, will keep scanning until a
338 * non-whitespace character is found.
339 * @return {?string} The next char, or null if the bottom of the
340 * document has been reached.
341 */
342 TraverseUtil.getNextChar = function(
343 startCursor, endCursor, nodesCrossed, skipWhitespace) {
344
345 // Save the starting position and get the first character.
346 startCursor.copyFrom(endCursor);
347 var c = TraverseUtil.forwardsChar(endCursor, nodesCrossed);
348 if (c == null)
349 return null;
350
351 // Keep track of whether the first character was whitespace.
352 var initialWhitespace = TraverseUtil.isWhitespace(c);
353
354 // Keep scanning until we find a non-whitespace or non-skipped character.
355 while ((TraverseUtil.isWhitespace(c)) ||
356 (TraverseUtil.isSkipped(endCursor.node))) {
357 c = TraverseUtil.forwardsChar(endCursor, nodesCrossed);
358 if (c == null)
359 return null;
360 }
361 if (skipWhitespace || !initialWhitespace) {
362 // If skipWhitepace is true, or if the first character we encountered
363 // was not whitespace, return that non-whitespace character.
364 startCursor.copyFrom(endCursor);
365 startCursor.index--;
366 return c;
367 }
368 else {
369 for (var i = 0; i < nodesCrossed.length; i++) {
370 if (TraverseUtil.isSkipped(nodesCrossed[i])) {
371 // We need to make sure that startCursor and endCursor aren't
372 // surrounding a skippable node.
373 endCursor.index--;
374 startCursor.copyFrom(endCursor);
375 startCursor.index--;
376 return ' ';
377 }
378 }
379 // Otherwise, return all of the whitespace before that last character.
380 endCursor.index--;
381 return ' ';
382 }
383 };
384
385 /**
386 * Finds the previous character, starting from startCursor. Upon exit,
387 * startCursor and endCursor will surround the previous character.
388 * If skipWhitespace is true, will skip until a real character is found.
389 * Otherwise, it will attempt to select all of the whitespace between
390 * the initial position of endCursor and the next non-whitespace character.
391 * @param {Cursor} startCursor The position to start searching for the
392 * char. On exit, will point to the position before the char.
393 * @param {Cursor} endCursor The position to start searching for the next
394 * char. On exit, will point to the position past the char.
395 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
396 * initial and final cursor position will be pushed onto this array.
397 * @param {boolean} skipWhitespace If true, will keep scanning until a
398 * non-whitespace character is found.
399 * @return {?string} The previous char, or null if the top of the
400 * document has been reached.
401 */
402 TraverseUtil.getPreviousChar = function(
403 startCursor, endCursor, nodesCrossed, skipWhitespace) {
404
405 // Save the starting position and get the first character.
406 endCursor.copyFrom(startCursor);
407 var c = TraverseUtil.backwardsChar(startCursor, nodesCrossed);
408 if (c == null)
409 return null;
410
411 // Keep track of whether the first character was whitespace.
412 var initialWhitespace = TraverseUtil.isWhitespace(c);
413
414 // Keep scanning until we find a non-whitespace or non-skipped character.
415 while ((TraverseUtil.isWhitespace(c)) ||
416 (TraverseUtil.isSkipped(startCursor.node))) {
417 c = TraverseUtil.backwardsChar(startCursor, nodesCrossed);
418 if (c == null)
419 return null;
420 }
421 if (skipWhitespace || !initialWhitespace) {
422 // If skipWhitepace is true, or if the first character we encountered
423 // was not whitespace, return that non-whitespace character.
424 endCursor.copyFrom(startCursor);
425 endCursor.index++;
426 return c;
427 } else {
428 for (var i = 0; i < nodesCrossed.length; i++) {
429 if (TraverseUtil.isSkipped(nodesCrossed[i])) {
430 startCursor.index++;
431 endCursor.copyFrom(startCursor);
432 endCursor.index++;
433 return ' ';
434 }
435 }
436 // Otherwise, return all of the whitespace before that last character.
437 startCursor.index++;
438 return ' ';
439 }
440 };
441
442 /**
443 * Finds the next word, starting from endCursor. Upon exit, startCursor
444 * and endCursor will surround the next word. A word is defined to be
445 * a string of 1 or more non-whitespace characters in the same DOM node.
446 * @param {Cursor} startCursor On exit, will point to the beginning of the
447 * word returned.
448 * @param {Cursor} endCursor The position to start searching for the next
449 * word. On exit, will point to the end of the word returned.
450 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
451 * initial and final cursor position will be pushed onto this array.
452 * @return {?string} The next word, or null if the bottom of the
453 * document has been reached.
454 */
455 TraverseUtil.getNextWord = function(startCursor, endCursor,
456 nodesCrossed) {
457
458 // Find the first non-whitespace or non-skipped character.
459 var cursor = endCursor.clone();
460 var c = TraverseUtil.forwardsChar(cursor, nodesCrossed);
461 if (c == null)
462 return null;
463 while ((TraverseUtil.isWhitespace(c)) ||
464 (TraverseUtil.isSkipped(cursor.node))) {
465 c = TraverseUtil.forwardsChar(cursor, nodesCrossed);
466 if (c == null)
467 return null;
468 }
469
470 // Set startCursor to the position immediately before the first
471 // character in our word. It's safe to decrement |index| because
472 // forwardsChar guarantees that the cursor will be immediately to the
473 // right of the returned character on exit.
474 startCursor.copyFrom(cursor);
475 startCursor.index--;
476
477 // Keep building up our word until we reach a whitespace character or
478 // would cross a tag. Don't actually return any tags crossed, because this
479 // word goes up until the tag boundary but not past it.
480 endCursor.copyFrom(cursor);
481 var word = c;
482 var newNodesCrossed = [];
483 c = TraverseUtil.forwardsChar(cursor, newNodesCrossed);
484 if (c == null) {
485 return word;
486 }
487 while (!TraverseUtil.isWhitespace(c) &&
488 newNodesCrossed.length == 0) {
489 word += c;
490 endCursor.copyFrom(cursor);
491 c = TraverseUtil.forwardsChar(cursor, newNodesCrossed);
492 if (c == null) {
493 return word;
494 }
495 }
496 return word;
497 };
498
499 /**
500 * Finds the previous word, starting from startCursor. Upon exit, startCursor
501 * and endCursor will surround the previous word. A word is defined to be
502 * a string of 1 or more non-whitespace characters in the same DOM node.
503 * @param {Cursor} startCursor The position to start searching for the
504 * previous word. On exit, will point to the beginning of the
505 * word returned.
506 * @param {Cursor} endCursor On exit, will point to the end of the
507 * word returned.
508 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
509 * initial and final cursor position will be pushed onto this array.
510 * @return {?string} The previous word, or null if the bottom of the
511 * document has been reached.
512 */
513 TraverseUtil.getPreviousWord = function(startCursor, endCursor,
514 nodesCrossed) {
515 // Find the first non-whitespace or non-skipped character.
516 var cursor = startCursor.clone();
517 var c = TraverseUtil.backwardsChar(cursor, nodesCrossed);
518 if (c == null)
519 return null;
520 while ((TraverseUtil.isWhitespace(c) ||
521 (TraverseUtil.isSkipped(cursor.node)))) {
522 c = TraverseUtil.backwardsChar(cursor, nodesCrossed);
523 if (c == null)
524 return null;
525 }
526
527 // Set endCursor to the position immediately after the first
528 // character we've found (the last character of the word, since we're
529 // searching backwards).
530 endCursor.copyFrom(cursor);
531 endCursor.index++;
532
533 // Keep building up our word until we reach a whitespace character or
534 // would cross a tag. Don't actually return any tags crossed, because this
535 // word goes up until the tag boundary but not past it.
536 startCursor.copyFrom(cursor);
537 var word = c;
538 var newNodesCrossed = [];
539 c = TraverseUtil.backwardsChar(cursor, newNodesCrossed);
540 if (c == null)
541 return word;
542 while (!TraverseUtil.isWhitespace(c) &&
543 newNodesCrossed.length == 0) {
544 word = c + word;
545 startCursor.copyFrom(cursor);
546 c = TraverseUtil.backwardsChar(cursor, newNodesCrossed);
547 if (c == null)
548 return word;
549 }
550
551 return word;
552 };
553
554 /**
555 * Finds the next sentence, starting from endCursor. Upon exit,
556 * startCursor and endCursor will surround the next sentence.
557 *
558 * @param {Cursor} startCursor On exit, marks the beginning of the sentence.
559 * @param {Cursor} endCursor The position to start searching for the next
560 * sentence. On exit, will point to the end of the returned string.
561 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
562 * initial and final cursor position will be pushed onto this array.
563 * @param {Object} breakTags Associative array of tags that should break
564 * the sentence.
565 * @return {?string} The next sentence, or null if the bottom of the
566 * document has been reached.
567 */
568 TraverseUtil.getNextSentence = function(
569 startCursor, endCursor, nodesCrossed, breakTags) {
570 return TraverseUtil.getNextString(
571 startCursor, endCursor, nodesCrossed,
572 function(str, word, nodes) {
573 if (str.substr(-1) == '.')
574 return true;
575 for (var i = 0; i < nodes.length; i++) {
576 if (TraverseUtil.isSkipped(nodes[i])) {
577 return true;
578 }
579 var style = window.getComputedStyle(nodes[i], null);
580 if (style && (style.display != 'inline' ||
581 breakTags[nodes[i].tagName])) {
582 return true;
583 }
584 }
585 return false;
586 });
587 };
588
589 /**
590 * Finds the previous sentence, starting from startCursor. Upon exit,
591 * startCursor and endCursor will surround the previous sentence.
592 *
593 * @param {Cursor} startCursor The position to start searching for the next
594 * sentence. On exit, will point to the start of the returned string.
595 * @param {Cursor} endCursor On exit, the end of the returned string.
596 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
597 * initial and final cursor position will be pushed onto this array.
598 * @param {Object} breakTags Associative array of tags that should break
599 * the sentence.
600 * @return {?string} The previous sentence, or null if the bottom of the
601 * document has been reached.
602 */
603 TraverseUtil.getPreviousSentence = function(
604 startCursor, endCursor, nodesCrossed, breakTags) {
605 return TraverseUtil.getPreviousString(
606 startCursor, endCursor, nodesCrossed,
607 function(str, word, nodes) {
608 if (word.substr(-1) == '.')
609 return true;
610 for (var i = 0; i < nodes.length; i++) {
611 if (TraverseUtil.isSkipped(nodes[i])) {
612 return true;
613 }
614 var style = window.getComputedStyle(nodes[i], null);
615 if (style && (style.display != 'inline' ||
616 breakTags[nodes[i].tagName])) {
617 return true;
618 }
619 }
620 return false;
621 });
622 };
623
624 /**
625 * Finds the next line, starting from endCursor. Upon exit,
626 * startCursor and endCursor will surround the next line.
627 *
628 * @param {Cursor} startCursor On exit, marks the beginning of the line.
629 * @param {Cursor} endCursor The position to start searching for the next
630 * line. On exit, will point to the end of the returned string.
631 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
632 * initial and final cursor position will be pushed onto this array.
633 * @param {number} lineLength The maximum number of characters in a line.
634 * @param {Object} breakTags Associative array of tags that should break
635 * the line.
636 * @return {?string} The next line, or null if the bottom of the
637 * document has been reached.
638 */
639 TraverseUtil.getNextLine = function(
640 startCursor, endCursor, nodesCrossed, lineLength, breakTags) {
641 return TraverseUtil.getNextString(
642 startCursor, endCursor, nodesCrossed,
643 function(str, word, nodes) {
644 if (str.length + word.length + 1 > lineLength)
645 return true;
646 for (var i = 0; i < nodes.length; i++) {
647 if (TraverseUtil.isSkipped(nodes[i])) {
648 return true;
649 }
650 var style = window.getComputedStyle(nodes[i], null);
651 if (style && (style.display != 'inline' ||
652 breakTags[nodes[i].tagName])) {
653 return true;
654 }
655 }
656 return false;
657 });
658 };
659
660 /**
661 * Finds the previous line, starting from startCursor. Upon exit,
662 * startCursor and endCursor will surround the previous line.
663 *
664 * @param {Cursor} startCursor The position to start searching for the next
665 * line. On exit, will point to the start of the returned string.
666 * @param {Cursor} endCursor On exit, the end of the returned string.
667 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
668 * initial and final cursor position will be pushed onto this array.
669 * @param {number} lineLength The maximum number of characters in a line.
670 * @param {Object} breakTags Associative array of tags that should break
671 * the sentence.
672 * @return {?string} The previous line, or null if the bottom of the
673 * document has been reached.
674 */
675 TraverseUtil.getPreviousLine = function(
676 startCursor, endCursor, nodesCrossed, lineLength, breakTags) {
677 return TraverseUtil.getPreviousString(
678 startCursor, endCursor, nodesCrossed,
679 function(str, word, nodes) {
680 if (str.length + word.length + 1 > lineLength)
681 return true;
682 for (var i = 0; i < nodes.length; i++) {
683 if (TraverseUtil.isSkipped(nodes[i])) {
684 return true;
685 }
686 var style = window.getComputedStyle(nodes[i], null);
687 if (style && (style.display != 'inline' ||
688 breakTags[nodes[i].tagName])) {
689 return true;
690 }
691 }
692 return false;
693 });
694 };
695
696 /**
697 * Finds the next paragraph, starting from endCursor. Upon exit,
698 * startCursor and endCursor will surround the next paragraph.
699 *
700 * @param {Cursor} startCursor On exit, marks the beginning of the paragraph.
701 * @param {Cursor} endCursor The position to start searching for the next
702 * paragraph. On exit, will point to the end of the returned string.
703 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
704 * initial and final cursor position will be pushed onto this array.
705 * @return {?string} The next paragraph, or null if the bottom of the
706 * document has been reached.
707 */
708 TraverseUtil.getNextParagraph = function(startCursor, endCursor,
709 nodesCrossed) {
710 return TraverseUtil.getNextString(
711 startCursor, endCursor, nodesCrossed,
712 function(str, word, nodes) {
713 for (var i = 0; i < nodes.length; i++) {
714 if (TraverseUtil.isSkipped(nodes[i])) {
715 return true;
716 }
717 var style = window.getComputedStyle(nodes[i], null);
718 if (style && style.display != 'inline') {
719 return true;
720 }
721 }
722 return false;
723 });
724 };
725
726 /**
727 * Finds the previous paragraph, starting from startCursor. Upon exit,
728 * startCursor and endCursor will surround the previous paragraph.
729 *
730 * @param {Cursor} startCursor The position to start searching for the next
731 * paragraph. On exit, will point to the start of the returned string.
732 * @param {Cursor} endCursor On exit, the end of the returned string.
733 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
734 * initial and final cursor position will be pushed onto this array.
735 * @return {?string} The previous paragraph, or null if the bottom of the
736 * document has been reached.
737 */
738 TraverseUtil.getPreviousParagraph = function(
739 startCursor, endCursor, nodesCrossed) {
740 return TraverseUtil.getPreviousString(
741 startCursor, endCursor, nodesCrossed,
742 function(str, word, nodes) {
743 for (var i = 0; i < nodes.length; i++) {
744 if (TraverseUtil.isSkipped(nodes[i])) {
745 return true;
746 }
747 var style = window.getComputedStyle(nodes[i], null);
748 if (style && style.display != 'inline') {
749 return true;
750 }
751 }
752 return false;
753 });
754 };
755
756 /**
757 * Customizable function to return the next string of words in the DOM, based
758 * on provided functions to decide when to break one string and start
759 * the next. This can be used to get the next sentence, line, paragraph,
760 * or potentially other granularities.
761 *
762 * Finds the next contiguous string, starting from endCursor. Upon exit,
763 * startCursor and endCursor will surround the next string.
764 *
765 * The breakBefore function takes three parameters, and
766 * should return true if the string should be broken before the proposed
767 * next word:
768 * str The string so far.
769 * word The next word to be added.
770 * nodesCrossed The nodes crossed in reaching this next word.
771 *
772 * @param {Cursor} startCursor On exit, will point to the beginning of the
773 * next string.
774 * @param {Cursor} endCursor The position to start searching for the next
775 * string. On exit, will point to the end of the returned string.
776 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
777 * initial and final cursor position will be pushed onto this array.
778 * @param {function(string, string, Array.<string>)} breakBefore
779 * Function that takes the string so far, next word to be added, and
780 * nodes crossed, and returns true if the string should be ended before
781 * adding this word.
782 * @return {?string} The next string, or null if the bottom of the
783 * document has been reached.
784 */
785 TraverseUtil.getNextString = function(
786 startCursor, endCursor, nodesCrossed, breakBefore) {
787 // Get the first word and set the start cursor to the start of the
788 // first word.
789 var wordStartCursor = endCursor.clone();
790 var wordEndCursor = endCursor.clone();
791 var newNodesCrossed = [];
792 var str = '';
793 var word = TraverseUtil.getNextWord(
794 wordStartCursor, wordEndCursor, newNodesCrossed);
795 if (word == null)
796 return null;
797 startCursor.copyFrom(wordStartCursor);
798
799 // Always add the first word when the string is empty, and then keep
800 // adding more words as long as breakBefore returns false
801 while (!str || !breakBefore(str, word, newNodesCrossed)) {
802 // Append this word, set the end cursor to the end of this word, and
803 // update the returned list of nodes crossed to include ones we crossed
804 // in reaching this word.
805 if (str)
806 str += ' ';
807 str += word;
808 nodesCrossed = nodesCrossed.concat(newNodesCrossed);
809 endCursor.copyFrom(wordEndCursor);
810
811 // Get the next word and go back to the top of the loop.
812 newNodesCrossed = [];
813 word = TraverseUtil.getNextWord(
814 wordStartCursor, wordEndCursor, newNodesCrossed);
815 if (word == null)
816 return str;
817 }
818
819 return str;
820 };
821
822 /**
823 * Customizable function to return the previous string of words in the DOM,
824 * based on provided functions to decide when to break one string and start
825 * the next. See getNextString, above, for more details.
826 *
827 * Finds the previous contiguous string, starting from startCursor. Upon exit,
828 * startCursor and endCursor will surround the next string.
829 *
830 * @param {Cursor} startCursor The position to start searching for the
831 * previous string. On exit, will point to the beginning of the
832 * string returned.
833 * @param {Cursor} endCursor On exit, will point to the end of the
834 * string returned.
835 * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
836 * initial and final cursor position will be pushed onto this array.
837 * @param {function(string, string, Array.<string>)} breakBefore
838 * Function that takes the string so far, the word to be added, and
839 * nodes crossed, and returns true if the string should be ended before
840 * adding this word.
841 * @return {?string} The next string, or null if the top of the
842 * document has been reached.
843 */
844 TraverseUtil.getPreviousString = function(
845 startCursor, endCursor, nodesCrossed, breakBefore) {
846 // Get the first word and set the end cursor to the end of the
847 // first word.
848 var wordStartCursor = startCursor.clone();
849 var wordEndCursor = startCursor.clone();
850 var newNodesCrossed = [];
851 var str = '';
852 var word = TraverseUtil.getPreviousWord(
853 wordStartCursor, wordEndCursor, newNodesCrossed);
854 if (word == null)
855 return null;
856 endCursor.copyFrom(wordEndCursor);
857
858 // Always add the first word when the string is empty, and then keep
859 // adding more words as long as breakBefore returns false
860 while (!str || !breakBefore(str, word, newNodesCrossed)) {
861 // Prepend this word, set the start cursor to the start of this word, and
862 // update the returned list of nodes crossed to include ones we crossed
863 // in reaching this word.
864 if (str)
865 str = ' ' + str;
866 str = word + str;
867 nodesCrossed = nodesCrossed.concat(newNodesCrossed);
868 startCursor.copyFrom(wordStartCursor);
869 v
870 // Get the previous word and go back to the top of the loop.
871 newNodesCrossed = [];
872 word = TraverseUtil.getPreviousWord(
873 wordStartCursor, wordEndCursor, newNodesCrossed);
874 if (word == null)
875 return str;
876 }
877
878 return str;
879 };
OLDNEW
« no previous file with comments | « ui/accessibility/extensions/caretbrowsing/options.js ('k') | ui/accessibility/extensions/highcontrast/background.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698