Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / chromevox / walkers / abstract_node_walker.js
blob19faec63ec99dc1e6646ff9fdc9488fb675cb1b0
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * @fileoverview A base class for walkers that have a concept of lowest-level
7  * node. Base classes must override the stopNodeDescent method to define
8  * what a lowest-level node is. Then this walker will use those nodes as the
9  * set of valid CursorSelections.
10  */
13 goog.provide('cvox.AbstractNodeWalker');
15 goog.require('cvox.AbstractWalker');
16 goog.require('cvox.CursorSelection');
17 goog.require('cvox.DomUtil');
19 /**
20  * @constructor
21  * @extends {cvox.AbstractWalker}
22  */
23 cvox.AbstractNodeWalker = function() {
24   goog.base(this);
26   /**
27    * To keep track of and break infinite loops when trying to call next on
28    * a body that does not DomUtil.hasContent().
29    * @type {boolean}
30    * @private
31    */
32   this.wasBegin_ = false;
34 goog.inherits(cvox.AbstractNodeWalker, cvox.AbstractWalker);
36 /**
37  * @override
38  */
39 cvox.AbstractNodeWalker.prototype.next = function(sel) {
40   var r = sel.isReversed();
41   var node = sel.end.node || document.body;
43   do {
44     node = cvox.DomUtil.directedNextLeafLikeNode(node, r,
45         goog.bind(this.stopNodeDescent, this));
46     if (!node) {
47       return null;
48     }
49     // and repeat all of the above until we have a node that is not empty
50   } while (node && !cvox.DomUtil.hasContent(node));
52   return cvox.CursorSelection.fromNode(node).setReversed(r);
55 /**
56  * @override
57  */
58 cvox.AbstractNodeWalker.prototype.sync = function(sel) {
59   var ret = this.privateSync_(sel);
60   this.wasBegin_ = false;
61   return ret;
65 /**
66  * Private version of sync to ensure that when a body has no content, we
67  * don't do an infinite loop trying to find an empty node.
68  * @param {!cvox.CursorSelection} sel The selection.
69  * @return {cvox.CursorSelection} The synced selection.
70  * @private
71  */
72 cvox.AbstractNodeWalker.prototype.privateSync_ = function(sel) {
73   var r = sel.isReversed();
75   if (sel.equals(cvox.CursorSelection.fromBody())) {
76     if (this.wasBegin_) {
77       // if body is empty, we return just the body selection
78       return cvox.CursorSelection.fromBody().setReversed(r);
79     }
80     this.wasBegin_ = true;
81   }
83   var node = sel.start.node;
85   while (node != document.body && node.parentNode &&
86       this.stopNodeDescent(node.parentNode)) {
87     node = node.parentNode;
88   }
90   while (!this.stopNodeDescent(node)) {
91     node = cvox.DomUtil.directedFirstChild(node, r);
92   }
94   var n = cvox.CursorSelection.fromNode(node);
95   if (!cvox.DomUtil.hasContent(node)) {
96     n = this.next(/** @type {!cvox.CursorSelection} */
97         (cvox.CursorSelection.fromNode(node)).setReversed(r));
98   }
99   if (n) {
100     return n.setReversed(r);
101   }
102   return this.begin({reversed: r});
106  * Returns true if this is "a leaf node" or lower. That is,
107  * it is at the lowest valid level or lower for this granularity.
108  * RESTRICTION: true for a node => true for all child nodes
109  * RESTRICTION: true if node has no children
110  * @param {!Node} node The node to check.
111  * @return {boolean} true if this is at the "leaf node" level or lower
112  * for this granularity.
113  * @protected
114  */
115 cvox.AbstractNodeWalker.prototype.stopNodeDescent = goog.abstractMethod;