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

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: Formatting changes based on CL comments. 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
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;
23 console.log("AutomationNode for desktop is loaded"); 28 this.root_ = desktop;
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 switch (event.key) {
28 console.log("1 = go to previous element"); 34 case '1':
29 this.moveToPrevious_(); 35 console.log('1 = go to previous element');
30 } else if (event.key === "2") { 36 this.moveToPrevious_();
31 console.log("2 = go to next element"); 37 break;
32 this.moveToNext_(); 38 case '2':
33 } else if (event.key === "3") { 39 console.log('2 = go to next element');
34 console.log("3 = go to child element"); 40 this.moveToNext_();
35 this.moveToFirstChild_(); 41 break;
36 } else if (event.key === "4") { 42 case '3':
37 console.log("4 = go to parent element"); 43 console.log('3 = do default on element');
38 this.moveToParent_(); 44 this.doDefault_();
39 } else if (event.key === "5") { 45 break;
40 console.log("5 is not yet implemented"); 46 }
41 console.log("\n"); 47 if (debuggingEnabled) {
42 } 48 switch (event.key) {
43 chrome.accessibilityPrivate.setFocusRing([this.node_.location]); 49 case '6':
50 console.log('6 = go to previous element (debug mode)');
51 this.debugMoveToPrevious_();
52 break;
53 case '7':
54 console.log('7 = go to next element (debug mode)');
55 this.debugMoveToNext_();
56 break;
57 case '8':
58 console.log('8 = go to child element (debug mode)');
59 this.debugMoveToFirstChild_();
60 break;
61 case '9':
62 console.log('9 = go to parent element (debug mode)');
63 this.debugMoveToParent_();
64 break;
65 }
66 }
67 if (this.node_)
68 chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
44 }.bind(this)); 69 }.bind(this));
45 }.bind(this)); 70 }.bind(this));
46 }; 71 };
47 72
48 SwitchAccess.prototype = { 73 SwitchAccess.prototype = {
49 /** 74 /**
75 * Set this.node_ to the previous interesting node. If no interesting node
76 * comes before this.node_, set this.node_ to the last interesting node.
77 *
78 * @private
79 */
80 moveToPrevious_: function() {
81 if (this.node_) {
82 let prev = this.getPreviousNode_(this.node_);
83 while (prev && !this.isInteresting_(prev)) {
84 prev = this.getPreviousNode_(prev);
85 }
86 if (prev) {
87 this.node_ = prev;
88 this.printNode_(this.node_);
89 return;
90 }
91 }
92
93 if (this.root_) {
94 console.log('Reached the first interesting node. Restarting with last.')
95 let prev = this.getYoungestDescendant_(this.root_);
96 while (prev && !this.isInteresting_(prev)) {
97 prev = this.getPreviousNode_(prev);
98 }
99 if (prev) {
100 this.node_ = prev;
101 this.printNode_(this.node_);
102 return;
103 }
104 }
105
106 console.log('Found no interesting nodes to visit.')
107 },
108
109 /**
110 * Set this.node_ to the next interesting node. If no interesting node comes
111 * after this.node_, set this.node_ to the first interesting node.
112 *
113 * @private
114 */
115 moveToNext_: function() {
116 if (this.node_) {
117 let next = this.getNextNode_(this.node_);
118 while (next && !this.isInteresting_(next))
119 next = this.getNextNode_(next);
120 if (next) {
121 this.node_ = next;
122 this.printNode_(this.node_);
123 return;
124 }
125 }
126
127 if (this.root_) {
128 console.log('Reached the last interesting node. Restarting with first.');
129 let next = this.root_.firstChild;
130 while (next && !this.isInteresting_(next))
131 next = this.getNextNode_(next);
132 if (next) {
133 this.node_ = next;
134 this.printNode_(this.node_);
135 return;
136 }
137 }
138
139 console.log('Found no interesting nodes to visit.');
140 },
141
142 /**
143 * Given a flat list of nodes in pre-order, get the node that comes after
144 * |node|.
145 *
146 * @param {!AutomationNode} node
147 * @return {AutomationNode}
148 * @private
149 */
150 getNextNode_: function(node) {
151 // Check for child.
152 let child = node.firstChild;
153 if (child)
154 return child;
155
156 // No child. Check for right-sibling.
157 let sibling = node.nextSibling;
158 if (sibling)
159 return sibling;
160
161 // No right-sibling. Get right-sibling of closest ancestor.
162 let ancestor = node.parent;
163 while (ancestor) {
164 let aunt = ancestor.nextSibling;
165 if (aunt)
166 return aunt;
167 ancestor = ancestor.parent;
168 }
169
170 // No node found after |node|, so return null.
171 return null;
172 },
173
174 /**
175 * Given a flat list of nodes in pre-order, get the node that comes before
176 * |node|.
177 *
178 * @param {!AutomationNode} node
179 * @return {AutomationNode}
180 * @private
181 */
182 getPreviousNode_: function(node) {
183 // Check for left-sibling. Return its youngest descendant if it has one.
184 // Otherwise, return the sibling.
185 let sibling = node.previousSibling;
186 if (sibling) {
187 let descendant = this.getYoungestDescendant_(sibling);
188 if (descendant)
189 return descendant;
190 return sibling;
191 }
192
193 // No left-sibling. Check for parent.
194 let parent = node.parent;
195 if (parent)
196 return parent;
197
198 // No node found before |node|, so return null.
199 return null;
200 },
201
202 /**
203 * Get the youngest descendant of |node| if it has one.
204 *
205 * @param {!AutomationNode} node
206 * @return {AutomationNode}
207 * @private
208 */
209 getYoungestDescendant_: function(node) {
210 if (!node.lastChild)
211 return null;
212
213 while (node.lastChild)
214 node = node.lastChild;
215
216 return node;
217 },
218
219 /**
220 * Returns true if |node| is interesting.
221 *
222 * @param {!AutomationNode} node
223 * @return {boolean}
224 * @private
225 */
226 isInteresting_: function(node) {
227 return node.state && node.state.focusable;
228 },
229
230 /**
50 * Move to the previous sibling of this.node_ if it has one. 231 * Move to the previous sibling of this.node_ if it has one.
51 */ 232 *
52 moveToPrevious_: function() { 233 * @private
53 var previous = this.node_.previousSibling; 234 */
235 debugMoveToPrevious_: function() {
236 let previous = this.node_.previousSibling;
54 if (previous) { 237 if (previous) {
55 this.node_ = previous; 238 this.node_ = previous;
56 this.printDetails_(); 239 this.printDetails_();
57 } else { 240 } else {
58 console.log("Node is first of siblings"); 241 console.log('Node is first of siblings');
59 console.log("\n"); 242 console.log('\n');
60 } 243 }
61 }, 244 },
62 245
63 /** 246 /**
64 * Move to the next sibling of this.node_ if it has one. 247 * Move to the next sibling of this.node_ if it has one.
65 */ 248 *
66 moveToNext_: function() { 249 * @private
67 var next = this.node_.nextSibling; 250 */
251 debugMoveToNext_: function() {
252 let next = this.node_.nextSibling;
68 if (next) { 253 if (next) {
69 this.node_ = next; 254 this.node_ = next;
70 this.printDetails_(); 255 this.printDetails_();
71 } else { 256 } else {
72 console.log("Node is last of siblings"); 257 console.log('Node is last of siblings');
73 console.log("\n"); 258 console.log('\n');
74 } 259 }
75 }, 260 },
76 261
77 /** 262 /**
78 * Move to the first child of this.node_ if it has one. 263 * Move to the first child of this.node_ if it has one.
79 */ 264 *
80 moveToFirstChild_: function() { 265 * @private
81 var child = this.node_.firstChild; 266 */
267 debugMoveToFirstChild_: function() {
268 let child = this.node_.firstChild;
82 if (child) { 269 if (child) {
83 this.ancestorList_.push(this.node_); 270 this.ancestorList_.push(this.node_);
84 this.node_ = child; 271 this.node_ = child;
85 this.printDetails_(); 272 this.printDetails_();
86 } else { 273 } else {
87 console.log("Node has no children"); 274 console.log('Node has no children');
88 console.log("\n"); 275 console.log('\n');
89 } 276 }
90 }, 277 },
91 278
92 /** 279 /**
93 * Move to the parent of this.node_ if it has one. If it does not have a 280 * 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 281 * 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. 282 * its neighbors, and we move to an ancestor node.
283 *
284 * @private
96 */ 285 */
97 moveToParent_: function() { 286 debugMoveToParent_: function() {
98 var parent = this.node_.parent; 287 let parent = this.node_.parent;
99 if (parent) { 288 if (parent) {
100 this.ancestorList_.pop(); 289 this.ancestorList_.pop();
101 this.node_ = parent; 290 this.node_ = parent;
102 this.printDetails_(); 291 this.printDetails_();
103 } else if (this.ancestorList_.length === 0) { 292 } else if (this.ancestorList_.length === 0) {
104 console.log("Node has no parent"); 293 console.log('Node has no parent');
105 console.log("\n"); 294 console.log('\n');
106 } else { 295 } else {
107 console.log( 296 console.log(
108 "Node could not find its parent, so moved to recent ancestor"); 297 'Node could not find its parent, so moved to recent ancestor');
109 var ancestor = this.ancestorList_.pop(); 298 let ancestor = this.ancestorList_.pop();
110 this.node_ = ancestor; 299 this.node_ = ancestor;
111 this.printDetails_(); 300 this.printDetails_();
112 } 301 }
113 }, 302 },
114 303
115 /** 304 /**
305 * Perform the default action on the currently selected node.
306 *
307 * @private
308 */
309 doDefault_: function() {
310 let state = this.node_.state;
311 if (state && state.focusable)
312 console.log('Node was focusable, doing default on it')
313 else if (state)
314 console.log('Node was not focusable, but still doing default');
315 else
316 console.log('Node has no state, still doing default');
317 console.log('\n');
318 this.node_.doDefault();
319 },
320
321 // TODO(elichtenberg): Move print functions to a custom logger class. Only
322 // log when debuggingEnabled is true.
323 /**
116 * Print out details about the currently selected node and the list of 324 * Print out details about the currently selected node and the list of
117 * ancestors. 325 * ancestors.
118 * 326 *
119 * @private 327 * @private
120 */ 328 */
121 printDetails_: function() { 329 printDetails_: function() {
122 this.printNode_(this.node_); 330 this.printNode_(this.node_);
123 console.log(this.ancestorList_); 331 console.log(this.ancestorList_);
124 console.log("\n"); 332 console.log('\n');
125 }, 333 },
126 334
127 /** 335 /**
128 * Print out details about a node. 336 * Print out details about a node.
129 * 337 *
130 * @param {AutomationNode} node 338 * @param {AutomationNode} node
131 * @private 339 * @private
132 */ 340 */
133 printNode_: function(node) { 341 printNode_: function(node) {
134 if (node) { 342 if (node) {
135 console.log("Name = " + node.name); 343 console.log('Name = ' + node.name);
136 console.log("Role = " + node.role); 344 console.log('Role = ' + node.role);
137 if (!node.parent) { 345 if (!node.parent)
138 console.log("At index " + node.indexInParent + ", has no parent"); 346 console.log('At index ' + node.indexInParent + ', has no parent');
139 } else { 347 else {
140 var numSiblings = node.parent.children.length; 348 let numSiblings = node.parent.children.length;
141 console.log( 349 console.log(
142 "At index " + node.indexInParent + ", there are " 350 'At index ' + node.indexInParent + ', there are '
143 + numSiblings + " siblings"); 351 + numSiblings + ' siblings');
144 } 352 }
145 console.log("Has " + node.children.length + " children"); 353 console.log('Has ' + node.children.length + ' children');
146 } else { 354 } else {
147 console.log("Node is null"); 355 console.log('Node is null');
148 } 356 }
149 console.log(node); 357 console.log(node);
358 console.log('\n');
150 } 359 }
151 }; 360 };
152 361
153 new SwitchAccess(); 362 window.switchAccess = new SwitchAccess();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698