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

Side by Side Diff: chrome/browser/resources/access_chromevox/common/linear_dom_walker.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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 | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 /**
6 * @fileoverview A JavaScript class for walking the DOM.
7 */
8
9
10 goog.provide('cvox.LinearDomWalker');
11
12 goog.require('cvox.DomUtil');
13 goog.require('cvox.XpathUtil');
14
15 /**
16 * @constructor
17 */
18 cvox.LinearDomWalker = function() {
19 this.currentNode = null;
20 this.currentAncestors = new Array();
21 this.previousNode = null;
22 this.useSmartNav = true;
23 };
24
25 /**
26 * @type {number}
27 * If a node contains more characters than this, it should not be treated
28 * as a leaf node by the smart navigation algorithm.
29 *
30 * This number was determined by looking at the average number of
31 * characters in a paragraph:
32 * http://www.fullondesign.co.uk/design/usability/
33 * 285-how-many-characters-per-a-page-is-normal.htm
34 * and then trying it out on a few popular websites (CNN, BBC,
35 * Google Search, etc.) and making sure it made sense.
36 */
37 cvox.LinearDomWalker.SMARTNAV_MAX_CHARCOUNT = 1500;
38
39 /**
40 * @type {string}
41 * If a node contains any of these elements, it should not be treated
42 * as a leaf node by the smart navigation algorithm.
43 */
44 cvox.LinearDomWalker.SMARTNAV_BREAKOUT_XPATH = './/blockquote |' +
45 './/button |' +
46 './/code |' +
47 './/form |' +
48 './/frame |' +
49 './/h1 |' +
50 './/h2 |' +
51 './/h3 |' +
52 './/h4 |' +
53 './/h5 |' +
54 './/h6 |' +
55 './/hr |' +
56 './/iframe |' +
57 './/input |' +
58 './/object |' +
59 './/ol |' +
60 './/p |' +
61 './/pre |' +
62 './/select |' +
63 './/table |' +
64 './/tr |' +
65 './/ul |' +
66 // Aria widget roles
67 './/*[@role="alert"] |' +
68 './/*[@role="alertdialog"] |' +
69 './/*[@role="button"] |' +
70 './/*[@role="checkbox"] |' +
71 './/*[@role="combobox"] |' +
72 './/*[@role="dialog"] |' +
73 './/*[@role="log"] |' +
74 './/*[@role="marquee"] |' +
75 './/*[@role="menubar"] |' +
76 './/*[@role="progressbar"] |' +
77 './/*[@role="radio"] |' +
78 './/*[@role="radiogroup"] |' +
79 './/*[@role="scrollbar"] |' +
80 './/*[@role="slider"] |' +
81 './/*[@role="spinbutton"] |' +
82 './/*[@role="status"] |' +
83 './/*[@role="tab"] |' +
84 './/*[@role="tabpanel"] |' +
85 './/*[@role="textbox"] |' +
86 './/*[@role="toolbar"] |' +
87 './/*[@role="tooltip"] |' +
88 './/*[@role="treeitem"] |' +
89 // Aria structure roles
90 './/*[@role="article"] |' +
91 './/*[@role="document"] |' +
92 './/*[@role="group"] |' +
93 './/*[@role="heading"] |' +
94 './/*[@role="img"] |' +
95 './/*[@role="list"] |' +
96 './/*[@role="math"] |' +
97 './/*[@role="region"] |' +
98 './/*[@role="row"] |' +
99 './/*[@role="separator"]';
100
101 /**
102 * Gets the currentNode for the cvox.LinearDomWalker.
103 * @return {Node} The the current node.
104 */
105 cvox.LinearDomWalker.prototype.getCurrentNode = function() {
106 return this.currentNode;
107 };
108
109 /**
110 * Sets the currentNode for the cvox.LinearDomWalker.
111 * @param {Node} node The node that should be treated as the current node.
112 */
113 cvox.LinearDomWalker.prototype.setCurrentNode = function(node) {
114 this.currentNode = node;
115 this.currentAncestors = new Array();
116 var ancestor = this.currentNode;
117 while (ancestor) {
118 this.currentAncestors.push(ancestor);
119 ancestor = ancestor.parentNode;
120 }
121 this.currentAncestors.reverse();
122 };
123
124 /**
125 * Moves to the next node.
126 *
127 * @return {Node} The current node.
128 */
129 cvox.LinearDomWalker.prototype.next = function() {
130 this.previousNode = this.currentNode;
131
132 /* Make sure the handle to the current element is still valid (attached to the
133 * document); if it isn't, use the cached list of ancestors to find a valid
134 * node, then resume navigation from that point.
135 * The current node can be invalidated by AJAX changing content.
136 */
137 if (this.currentNode &&
138 !cvox.DomUtil.isAttachedToDocument(this.currentNode)) {
139 for (var i = this.currentAncestors.length - 1, ancestor;
140 ancestor = this.currentAncestors[i]; i--) {
141 if (cvox.DomUtil.isAttachedToDocument(ancestor)) {
142 this.setCurrentNode(ancestor);
143 // Previous-Next sequence to put us back at the correct level.
144 this.previous();
145 this.next();
146 break;
147 }
148 }
149 }
150
151 return this.nextContentNode();
152 };
153
154 /**
155 * Moves to the previous node.
156 *
157 * @return {Node} The current node.
158 */
159 cvox.LinearDomWalker.prototype.previous = function() {
160 this.previousNode = this.currentNode;
161
162 /* Make sure the handle to the current element is still valid (attached to the
163 * document); if it isn't, use the cached list of ancestors to find a valid
164 * node, then resume navigation from that point.
165 * The current node can be invalidated by AJAX changing content.
166 */
167 if (this.currentNode &&
168 !cvox.DomUtil.isAttachedToDocument(this.currentNode)) {
169 for (var i = this.currentAncestors.length - 1, ancestor;
170 ancestor = this.currentAncestors[i]; i--) {
171 if (cvox.DomUtil.isAttachedToDocument(ancestor)) {
172 this.setCurrentNode(ancestor);
173 // Next-previous sequence to put us back at the correct level.
174 this.next();
175 this.previous();
176 break;
177 }
178 }
179 }
180
181 return this.prevContentNode();
182 };
183
184 /**
185 * Moves to the next node.
186 * @return {Node} The current node.
187 */
188 cvox.LinearDomWalker.prototype.nextNode = function() {
189 if (!this.currentNode) {
190 this.setCurrentNode(document.body);
191 } else {
192 while (this.currentNode && (!this.currentNode.nextSibling)) {
193 this.setCurrentNode(this.currentNode.parentNode);
194 }
195 if (this.currentNode && this.currentNode.nextSibling) {
196 this.setCurrentNode(this.currentNode.nextSibling);
197 }
198 }
199 if (!this.currentNode) {
200 return null;
201 }
202 while (!this.isLeafNode(this.currentNode)) {
203 this.setCurrentNode(this.currentNode.firstChild);
204 }
205 return this.currentNode;
206 };
207
208 /**
209 * Moves to the next node that has content.
210 * @return {Node} The current node.
211 */
212 cvox.LinearDomWalker.prototype.nextContentNode = function() {
213 this.nextNode();
214 while (this.currentNode && !cvox.DomUtil.hasContent(this.currentNode)) {
215 this.nextNode();
216 }
217 return this.currentNode;
218 };
219
220 /**
221 * Moves to the previous node.
222 * @return {Node} The current node.
223 */
224 cvox.LinearDomWalker.prototype.prevNode = function() {
225 if (!this.currentNode) {
226 this.setCurrentNode(document.body);
227 } else {
228 while (this.currentNode && (!this.currentNode.previousSibling)) {
229 this.setCurrentNode(this.currentNode.parentNode);
230 }
231 if (this.currentNode && this.currentNode.previousSibling) {
232 this.setCurrentNode(this.currentNode.previousSibling);
233 }
234 }
235 if (!this.currentNode) {
236 return null;
237 }
238 while (!this.isLeafNode(this.currentNode)) {
239 this.setCurrentNode(this.currentNode.lastChild);
240 }
241 return this.currentNode;
242 };
243
244 /**
245 * Moves to the previous node that has content.
246 * @return {Node} The current node.
247 */
248 cvox.LinearDomWalker.prototype.prevContentNode = function() {
249 this.prevNode();
250 while (this.currentNode && !cvox.DomUtil.hasContent(this.currentNode)) {
251 this.prevNode();
252 }
253 return this.currentNode;
254 };
255
256 /**
257 * Returns an array of ancestors that are unique for the current node when
258 * compared to the previous node. Having such an array is useful in generating
259 * the node information (identifying when interesting node boundaries have been
260 * crossed, etc.).
261 *
262 * @return {Array.<Node>} An array of unique ancestors for the current node.
263 */
264 cvox.LinearDomWalker.prototype.getUniqueAncestors = function() {
265 return cvox.DomUtil.getUniqueAncestors(this.previousNode,
266 this.currentNode);
267 };
268
269 /**
270 * Checks if Smart Nav is enabled.
271 * @return {boolean} Whether Smart Nav is enabled.
272 */
273 cvox.LinearDomWalker.prototype.getSmartNavEnabled = function() {
274 return this.useSmartNav;
275 };
276
277 /**
278 * Enables/disables Smart Nav.
279 * @param {boolean} enableSmartNav - Whether Smart Nav should be enabled.
280 */
281 cvox.LinearDomWalker.prototype.setSmartNavEnabled = function(enableSmartNav) {
282 this.useSmartNav = enableSmartNav;
283 };
284
285
286 /**
287 * Determines if the a node should be treated as a leaf node.
288 * Based on DomUtil.isLeafNode - if SmartNav is enabled, then a few additional
289 * heuristics will be applied to determine if a node can be treated as a leaf
290 * node for smoother reading.
291 * @param {Node} targetNode to check.
292 * @return {boolean} True if targetNode can be considered a leaf node.
293 */
294 cvox.LinearDomWalker.prototype.isLeafNode = function(targetNode) {
295 if (cvox.DomUtil.isLeafNode(targetNode)) {
296 return true;
297 }
298 if (!this.useSmartNav) {
299 return false;
300 }
301 var content = cvox.DomUtil.getText(targetNode);
302 if (content.length > cvox.LinearDomWalker.SMARTNAV_MAX_CHARCOUNT) {
303 return false;
304 }
305 if (content.replace(/\s/g, '') === '') {
306 // Text only contains whitespace
307 return false;
308 }
309 var breakingNodes = cvox.XpathUtil.evalXPath(
310 cvox.LinearDomWalker.SMARTNAV_BREAKOUT_XPATH, targetNode);
311 for (var i = 0, node; node = breakingNodes[i]; i++) {
312 if (cvox.DomUtil.hasContent(node)) {
313 return false;
314 }
315 }
316 return true;
317 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698