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

Side by Side Diff: chrome/browser/resources/chromeos/switch_access/switch_access.js

Issue 2738893003: Use keys 1 through 3 to switch between and click on focusable elements. (Closed)
Patch Set: Created 3 years, 9 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
« no previous file with comments | « chrome/browser/chromeos/accessibility/switch_access_event_handler.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 var AutomationNode = chrome.automation.AutomationNode; 5 let AutomationNode = chrome.automation.AutomationNode;
6 6
7 let debuggingEnabled = true;
7 /** 8 /**
8 * @constructor 9 * @constructor
9 */ 10 */
10 var SwitchAccess = function() { 11 let SwitchAccess = function() {
11 console.log("Switch access is enabled"); 12 console.log("Switch access is enabled");
12 13
13 // Currently selected node. 14 // Currently selected node.
14 /** @private {AutomationNode} */ 15 /** @private {AutomationNode} */
15 this.node_ = null; 16 this.node_ = null;
16 17
18 // Root node (i.e., the desktop).
19 /** @private {AutomationNode} */
20 this.root_ = null;
21
17 // List of nodes to push to / pop from in case this.node_ is lost. 22 // List of nodes to push to / pop from in case this.node_ is lost.
18 /** @private {!Array<!AutomationNode>} */ 23 /** @private {!Array<!AutomationNode>} */
19 this.ancestorList_ = []; 24 this.ancestorList_ = [];
20 25
21 chrome.automation.getDesktop(function(desktop) { 26 chrome.automation.getDesktop(function(desktop) {
22 this.node_ = desktop; 27 this.node_ = desktop;
28 this.root_ = desktop;
23 console.log("AutomationNode for desktop is loaded"); 29 console.log("AutomationNode for desktop is loaded");
24 this.printDetails_(); 30 this.printDetails_();
25 31
26 document.addEventListener("keyup", function(event) { 32 document.addEventListener("keyup", function(event) {
27 if (event.key === "1") { 33 if (event.key === "1") {
dmazzoni 2017/03/09 00:00:01 Use a switch instead of several if statements May
elichtenberg 2017/03/09 19:31:44 Rather than having two separate switch statements
28 console.log("1 = go to previous element"); 34 console.log("1 = go to previous element");
29 this.moveToPrevious_(); 35 this.moveToPrevious_();
30 } else if (event.key === "2") { 36 } else if (event.key === "2") {
31 console.log("2 = go to next element"); 37 console.log("2 = go to next element");
32 this.moveToNext_(); 38 this.moveToNext_();
33 } else if (event.key === "3") { 39 } else if (event.key === "3") {
34 console.log("3 = go to child element"); 40 console.log("3 = do default on element");
35 this.moveToFirstChild_(); 41 this.doDefault_();
36 } else if (event.key === "4") { 42 } else if (debuggingEnabled) {
37 console.log("4 = go to parent element"); 43 if (event.key === "6") {
38 this.moveToParent_(); 44 console.log("6 = go to previous element (debug mode)");
39 } else if (event.key === "5") { 45 this.debugMoveToPrevious_();
40 console.log("5 is not yet implemented"); 46 } else if (event.key === "7") {
41 console.log("\n"); 47 console.log("7 = go to next element (debug mode)");
42 } 48 this.debugMoveToNext_();
43 chrome.accessibilityPrivate.setFocusRing([this.node_.location]); 49 } else if (event.key === "8") {
50 console.log("8 = go to child element (debug mode)");
51 this.debugMoveToFirstChild_();
52 } else if (event.key === "9") {
53 console.log("9 = go to parent element (debug mode)");
54 this.debugMoveToParent_();
55 }
56 }
57 if (this.node_) {
58 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
59 }
44 }.bind(this)); 60 }.bind(this));
45 }.bind(this)); 61 }.bind(this));
46 }; 62 };
47 63
48 SwitchAccess.prototype = { 64 SwitchAccess.prototype = {
49 /** 65 /**
66 * Set this.node_ to the previous interesting node. If no interesting node
67 * comes before this.node_, set this.node_ to the last interesting node.
68 *
69 * @private
70 */
71 moveToPrevious_: function() {
72 let prev = null;
73 if (this.node_) {
74 prev = this.getPreviousNode_(this.node_);
75 }
76 if (prev) {
77 this.node_ = prev;
78 } else if (this.root_) {
79 console.log("Reached the first interesting node. Restarting with last.");
80 this.node_ = this.getInterestingDescendant_(this.root_, false);
81 } else {
82 console.log("Found no interesting nodes to visit");
83 }
84 this.printNode_(this.node_);
85 console.log("\n");
86 },
87
88 /**
89 * Set this.node_ to the next interesting node. If no interesting node comes
90 * after this.node_, set this.node_ to the first interesting node.
91 *
92 * @private
93 */
94 moveToNext_: function() {
95 let next = null;
96 if (this.node_) {
97 next = this.getNextNode_(this.node_);
98 }
99 if (next) {
100 this.node_ = next;
101 } else if (this.root_) {
102 console.log("Reached the last interesting node. Restarting with first.");
103 this.node_ = this.getInterestingDescendant_(this.root_, true);
104 } else {
105 console.log("Found no interesting nodes to visit");
106 }
107 this.printNode_(this.node_);
108 console.log("\n");
109 },
110
111 /**
112 * Given a flat list of nodes in pre-order that are considered interesting,
113 * get the node that comes after |node|.
114 *
115 * @param {!AutomationNode} node
116 * @return {AutomationNode}
117 * @private
118 */
119 getNextNode_: function(node) {
120 // Check descendants.
121 let descendant = this.getInterestingDescendant_(node, true);
122 if (descendant) {
123 return descendant;
124 }
125
126 // No interesting descendant. Check right-siblings and their descendants.
127 let siblingOrDescendant =
128 this.getInterestingSiblingOrDescendant_(node, false);
129 if (siblingOrDescendant) {
130 return siblingOrDescendant;
131 }
132
133 // No interesting right-sibling or descendant of it. Check ancestors and
134 // other relatives that come after |node|.
135 let ancestorOrRelative =
136 this.getInterestingAncestorOrRelative_(node, false);
137 if (ancestorOrRelative) {
138 return ancestorOrRelative;
139 }
140
141 // No interesting node found after |node|, so return null.
142 return null;
143 },
144
145 /**
146 * Given a flat list of nodes in pre-order that are considered interesting,
147 * get the node that comes before |node|.
148 *
149 * @param {!AutomationNode} node
150 * @return {AutomationNode}
151 * @private
152 */
153 getPreviousNode_: function(node) {
154 // Check left-siblings and their descendants.
155 let siblingOrDescendant =
156 this.getInterestingSiblingOrDescendant_(node, true);
157 if (siblingOrDescendant) {
158 return siblingOrDescendant;
159 }
160
161 // No interesting left-sibling or descendant of it. Check ancestors and
162 // other relatives that come before |node|.
163 let ancestorOrRelative = this.getInterestingAncestorOrRelative_(node, true);
164 if (ancestorOrRelative) {
165 return ancestorOrRelative;
166 }
167
168 // No interesting node found before |node|, so return null.
169 return null;
170 },
171
172
173 /**
174 * Find a descendant of |node| that is considered interesting.
175 * If |startAtFirstChild| is true, this function will start by checking the
176 * lowest index child, one level below |node|.
177 * If |startAtFirstChild| is false, this function will start by checking the
178 * leaf descendants of the highest index child.
179 *
180 * @param {!AutomationNode} node
181 * @param {boolean} startAtFirstChild
182 * @return {AutomationNode}
183 * @private
184 */
185 getInterestingDescendant_: function(node, startAtFirstChild) {
186 if (startAtFirstChild) {
187 let child = node.firstChild;
188 while (child) {
189 if (this.isInteresting_(child)) {
dmazzoni 2017/03/09 00:00:01 Right now you have calls to isInteresting througho
elichtenberg 2017/03/09 19:31:44 Done.
190 return child;
191 }
192 let descendant = this.getInterestingDescendant_(child, true);
193 if (descendant) {
194 return descendant;
195 }
196 child = child.nextSibling;
197 }
198 } else {
199 let child = node.lastChild;
200 while (child) {
201 let descendant = this.getInterestingDescendant_(child, false);
202 if (descendant) {
203 return descendant;
204 }
205 if (this.isInteresting_(child)) {
206 return child;
207 }
208 child = child.previousSibling;
209 }
210 }
211 return null;
212 },
213
214 /**
215 * Find a sibling or descendant of a sibling of |node| that is considered
216 * interesting.
217 * If |checkPreviousSibling| is true, this function will only look at |node|'s
218 * lower index sibilngs, and it will first check the sibling's descendants.
219 * If |checkPreviousSibling| is false, this function will only look at
220 * |node|'s higher index siblings, and it will check the sibling before its
221 * descendants.
222 *
223 * @param {!AutomationNode} node
224 * @param {boolean} checkPreviousSibling
225 * @return {AutomationNode}
226 * @private
227 */
228 getInterestingSiblingOrDescendant_: function(node, checkPreviousSibling) {
229 if (checkPreviousSibling) {
230 let sibling = node.previousSibling;
231 while (sibling) {
232 let descendant = this.getInterestingDescendant_(sibling, false);
233 if (descendant) {
234 return descendant;
235 }
236 if (this.isInteresting_(sibling)) {
237 return sibling;
238 }
239 sibling = sibling.previousSibling;
240 }
241 } else {
242 let sibling = node.nextSibling;
243 while (sibling) {
244 if (this.isInteresting_(sibling)) {
245 return sibling;
246 }
247 let descendant = this.getInterestingDescendant_(sibling, true);
248 if (descendant) {
249 return descendant;
250 }
251 sibling = sibling.nextSibling;
252 }
253 }
254 return null;
255 },
256
257 /**
258 * Find an ancestor or other relative of |node| that is considered
259 * interesting.
260 * If |findPrevious| is true, will check nodes that come before |node| in
261 * pre-order, starting with |node|'s parent.
262 * If |findPrevious| is false, will check nodes that come after |node| in
263 * pre-order, not including any descendants or direct ancestors.
264 *
265 * @param {!AutomationNode} node
266 * @param {boolean} findPrevious
267 * @return {AutomationNode}
268 * @private
269 */
270 getInterestingAncestorOrRelative_: function(node, findPrevious) {
271 let ancestor = node.parent;
272 while (ancestor) {
273 if (findPrevious && this.isInteresting_(ancestor)) {
274 return ancestor;
275 }
276 let relative =
277 this.getInterestingSiblingOrDescendant_(ancestor, findPrevious);
278 if (relative) {
279 return relative;
280 }
281 ancestor = ancestor.parent;
282 }
283 return null;
284 },
285
286 /**
287 * Returns true if |node| is interesting.
288 *
289 * @param {!AutomationNode} node
290 * @return {boolean}
291 * @private
292 */
293 isInteresting_: function(node) {
294 if (node.state && node.state.focusable) {
295 return true;
296 } else {
297 return false;
298 }
299 },
300
301 /**
50 * Move to the previous sibling of this.node_ if it has one. 302 * Move to the previous sibling of this.node_ if it has one.
51 */ 303 *
52 moveToPrevious_: function() { 304 * @private
53 var previous = this.node_.previousSibling; 305 */
306 debugMoveToPrevious_: function() {
307 let previous = this.node_.previousSibling;
54 if (previous) { 308 if (previous) {
55 this.node_ = previous; 309 this.node_ = previous;
56 this.printDetails_(); 310 this.printDetails_();
57 } else { 311 } else {
58 console.log("Node is first of siblings"); 312 console.log("Node is first of siblings");
59 console.log("\n"); 313 console.log("\n");
60 } 314 }
61 }, 315 },
62 316
63 /** 317 /**
64 * Move to the next sibling of this.node_ if it has one. 318 * Move to the next sibling of this.node_ if it has one.
319 *
320 * @private
65 */ 321 */
66 moveToNext_: function() { 322 debugMoveToNext_: function() {
67 var next = this.node_.nextSibling; 323 let next = this.node_.nextSibling;
68 if (next) { 324 if (next) {
69 this.node_ = next; 325 this.node_ = next;
70 this.printDetails_(); 326 this.printDetails_();
71 } else { 327 } else {
72 console.log("Node is last of siblings"); 328 console.log("Node is last of siblings");
73 console.log("\n"); 329 console.log("\n");
74 } 330 }
75 }, 331 },
76 332
77 /** 333 /**
78 * Move to the first child of this.node_ if it has one. 334 * Move to the first child of this.node_ if it has one.
335 *
336 * @private
79 */ 337 */
80 moveToFirstChild_: function() { 338 debugMoveToFirstChild_: function() {
81 var child = this.node_.firstChild; 339 let child = this.node_.firstChild;
82 if (child) { 340 if (child) {
83 this.ancestorList_.push(this.node_); 341 this.ancestorList_.push(this.node_);
84 this.node_ = child; 342 this.node_ = child;
85 this.printDetails_(); 343 this.printDetails_();
86 } else { 344 } else {
87 console.log("Node has no children"); 345 console.log("Node has no children");
88 console.log("\n"); 346 console.log("\n");
89 } 347 }
90 }, 348 },
91 349
92 /** 350 /**
93 * Move to the parent of this.node_ if it has one. If it does not have a 351 * Move to the parent of this.node_ if it has one. If it does not have a
94 * parent but it is not the top level root node, then this.node_ lost track of 352 * parent but it is not the top level root node, then this.node_ lost track of
95 * its neighbors, and we move to an ancestor node. 353 * its neighbors, and we move to an ancestor node.
354 *
355 * @private
96 */ 356 */
97 moveToParent_: function() { 357 debugMoveToParent_: function() {
98 var parent = this.node_.parent; 358 let parent = this.node_.parent;
99 if (parent) { 359 if (parent) {
100 this.ancestorList_.pop(); 360 this.ancestorList_.pop();
101 this.node_ = parent; 361 this.node_ = parent;
102 this.printDetails_(); 362 this.printDetails_();
103 } else if (this.ancestorList_.length === 0) { 363 } else if (this.ancestorList_.length === 0) {
104 console.log("Node has no parent"); 364 console.log("Node has no parent");
105 console.log("\n"); 365 console.log("\n");
106 } else { 366 } else {
107 console.log( 367 console.log(
108 "Node could not find its parent, so moved to recent ancestor"); 368 "Node could not find its parent, so moved to recent ancestor");
109 var ancestor = this.ancestorList_.pop(); 369 let ancestor = this.ancestorList_.pop();
110 this.node_ = ancestor; 370 this.node_ = ancestor;
111 this.printDetails_(); 371 this.printDetails_();
112 } 372 }
113 }, 373 },
114 374
115 /** 375 /**
376 * Perform the default action on the currently selected node.
377 *
378 * @private
379 */
380 doDefault_: function() {
381 let state = this.node_.state;
382 if (state && state.focusable) {
383 console.log("Node was focusable, doing default on it")
384 } else if (state) {
385 console.log("Node was not focusable, but still doing default");
386 } else {
387 console.log("Node has no state, still doing default");
388 }
389 console.log("\n");
390 this.node_.doDefault();
391 },
392
393 /**
116 * Print out details about the currently selected node and the list of 394 * Print out details about the currently selected node and the list of
117 * ancestors. 395 * ancestors.
118 * 396 *
119 * @private 397 * @private
120 */ 398 */
121 printDetails_: function() { 399 printDetails_: function() {
122 this.printNode_(this.node_); 400 this.printNode_(this.node_);
123 console.log(this.ancestorList_); 401 console.log(this.ancestorList_);
124 console.log("\n"); 402 console.log("\n");
125 }, 403 },
126 404
127 /** 405 /**
128 * Print out details about a node. 406 * Print out details about a node.
129 * 407 *
130 * @param {AutomationNode} node 408 * @param {AutomationNode} node
131 * @private 409 * @private
132 */ 410 */
133 printNode_: function(node) { 411 printNode_: function(node) {
134 if (node) { 412 if (node) {
135 console.log("Name = " + node.name); 413 console.log("Name = " + node.name);
136 console.log("Role = " + node.role); 414 console.log("Role = " + node.role);
137 if (!node.parent) { 415 if (!node.parent) {
138 console.log("At index " + node.indexInParent + ", has no parent"); 416 console.log("At index " + node.indexInParent + ", has no parent");
139 } else { 417 } else {
140 var numSiblings = node.parent.children.length; 418 let numSiblings = node.parent.children.length;
141 console.log( 419 console.log(
142 "At index " + node.indexInParent + ", there are " 420 "At index " + node.indexInParent + ", there are "
143 + numSiblings + " siblings"); 421 + numSiblings + " siblings");
144 } 422 }
145 console.log("Has " + node.children.length + " children"); 423 console.log("Has " + node.children.length + " children");
146 } else { 424 } else {
147 console.log("Node is null"); 425 console.log("Node is null");
148 } 426 }
149 console.log(node); 427 console.log(node);
150 } 428 }
151 }; 429 };
152 430
153 new SwitchAccess(); 431 window.switchAccess = new SwitchAccess();
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/accessibility/switch_access_event_handler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698