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.
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.
13 goog
.provide('cvox.AbstractNodeWalker');
15 goog
.require('cvox.AbstractWalker');
16 goog
.require('cvox.CursorSelection');
17 goog
.require('cvox.DomUtil');
21 * @extends {cvox.AbstractWalker}
23 cvox
.AbstractNodeWalker = function() {
27 * To keep track of and break infinite loops when trying to call next on
28 * a body that does not DomUtil.hasContent().
32 this.wasBegin_
= false;
34 goog
.inherits(cvox
.AbstractNodeWalker
, cvox
.AbstractWalker
);
39 cvox
.AbstractNodeWalker
.prototype.next = function(sel
) {
40 var r
= sel
.isReversed();
41 var node
= sel
.end
.node
|| document
.body
;
44 node
= cvox
.DomUtil
.directedNextLeafLikeNode(node
, r
,
45 goog
.bind(this.stopNodeDescent
, this));
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
);
58 cvox
.AbstractNodeWalker
.prototype.sync = function(sel
) {
59 var ret
= this.privateSync_(sel
);
60 this.wasBegin_
= false;
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.
72 cvox
.AbstractNodeWalker
.prototype.privateSync_ = function(sel
) {
73 var r
= sel
.isReversed();
75 if (sel
.equals(cvox
.CursorSelection
.fromBody())) {
77 // if body is empty, we return just the body selection
78 return cvox
.CursorSelection
.fromBody().setReversed(r
);
80 this.wasBegin_
= true;
83 var node
= sel
.start
.node
;
85 while (node
!= document
.body
&& node
.parentNode
&&
86 this.stopNodeDescent(node
.parentNode
)) {
87 node
= node
.parentNode
;
90 while (!this.stopNodeDescent(node
)) {
91 node
= cvox
.DomUtil
.directedFirstChild(node
, r
);
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
));
100 return n
.setReversed(r
);
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.
115 cvox
.AbstractNodeWalker
.prototype.stopNodeDescent
= goog
.abstractMethod
;