OLD | NEW |
---|---|
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 /** | 5 /** |
6 * Class to manage interactions with the accessibility tree, including moving | 6 * Class to manage interactions with the accessibility tree, including moving |
7 * to and selecting nodes. | 7 * to and selecting nodes. |
8 * | 8 * |
9 * @constructor | 9 * @constructor |
10 */ | 10 */ |
11 function AutomationManager() { | 11 function AutomationManager() { |
12 /** | 12 /** |
13 * Currently selected node. | 13 * Currently highlighted node. |
14 * | 14 * |
15 * @private {chrome.automation.AutomationNode} | 15 * @private {chrome.automation.AutomationNode} |
16 */ | 16 */ |
17 this.node_ = null; | 17 this.node_ = null; |
18 | 18 |
19 /** | 19 /** |
20 * Root node (i.e., the desktop). | 20 * The root of the subtree that the user is navigating through. |
21 * | 21 * |
22 * @private {chrome.automation.AutomationNode} | 22 * @private {chrome.automation.AutomationNode} |
23 */ | 23 */ |
24 this.root_ = null; | 24 this.scope_ = null; |
25 | |
26 /** | |
27 * The desktop node. | |
28 * | |
29 * @private {chrome.automation.AutomationNode} | |
30 */ | |
31 this.desktop_ = null; | |
32 | |
33 /** | |
34 * A list of past subtree roots. Allows user to traverse back to previous | |
dmazzoni
2017/05/05 18:23:19
Would it be more clear to say this is a list of pa
elichtenberg
2017/05/06 00:13:53
Done.
| |
35 * groups after selecting one or more groups. | |
36 * | |
37 * @private {Array<chrome.automation.AutomationNode>} | |
38 */ | |
39 this.oldScopes_ = []; | |
25 | 40 |
26 /** | 41 /** |
27 * Moves to the appropriate node in the accessibility tree. | 42 * Moves to the appropriate node in the accessibility tree. |
28 * | 43 * |
29 * @private {AutomationTreeWalker} | 44 * @private {AutomationTreeWalker} |
30 */ | 45 */ |
31 this.treeWalker_ = null; | 46 this.treeWalker_ = null; |
32 | 47 |
33 this.init_(); | 48 this.init_(); |
34 }; | 49 }; |
35 | 50 |
36 AutomationManager.prototype = { | 51 AutomationManager.prototype = { |
37 /** | 52 /** |
38 * Set this.node_ and this.root_ to the desktop node, and initialize the | 53 * Set this.node_, this.root_, and this.desktop_ to the desktop node, and |
39 * tree walker. | 54 * creates an initial tree walker. |
40 * | 55 * |
41 * @private | 56 * @private |
42 */ | 57 */ |
43 init_: function() { | 58 init_: function() { |
44 this.treeWalker_ = new AutomationTreeWalker(); | |
45 | |
46 chrome.automation.getDesktop(function(desktop) { | 59 chrome.automation.getDesktop(function(desktop) { |
47 this.node_ = desktop; | 60 this.node_ = desktop; |
48 this.root_ = desktop; | 61 this.scope_ = desktop; |
62 this.desktop_ = desktop; | |
63 this.treeWalker_ = this.createTreeWalker_(desktop); | |
49 console.log('AutomationNode for desktop is loaded'); | 64 console.log('AutomationNode for desktop is loaded'); |
50 this.printNode_(this.node_); | 65 this.printNode_(this.node_); |
51 }.bind(this)); | 66 }.bind(this)); |
52 }, | 67 }, |
53 | 68 |
54 /** | 69 /** |
55 * Set this.node_ to the next/previous interesting node, and then highlight | 70 * Set this.node_ to the next/previous interesting node, and then highlight |
56 * it on the screen. If no interesting node is found, set this.node_ to the | 71 * it on the screen. If no interesting node is found, set this.node_ to the |
57 * first/last interesting node. If |doNext| is true, will search for next | 72 * first/last interesting node. If |doNext| is true, will search for next |
58 * node. Otherwise, will search for previous node. | 73 * node. Otherwise, will search for previous node. |
59 * | 74 * |
60 * @param {boolean} doNext | 75 * @param {boolean} doNext |
61 */ | 76 */ |
62 moveToNode: function(doNext) { | 77 moveToNode: function(doNext) { |
63 let node = this.treeWalker_.moveToNode(this.node_, this.root_, doNext); | 78 if (!this.treeWalker_) |
79 return; | |
80 | |
81 let node = this.treeWalker_.moveToNode(doNext); | |
64 if (node) { | 82 if (node) { |
65 this.node_ = node; | 83 this.node_ = node; |
66 this.printNode_(this.node_); | 84 this.printNode_(this.node_); |
67 chrome.accessibilityPrivate.setFocusRing([this.node_.location]); | 85 chrome.accessibilityPrivate.setFocusRing([this.node_.location]); |
68 } | 86 } |
69 }, | 87 }, |
70 | 88 |
71 /** | 89 /** |
72 * Perform the default action on the currently selected node. | 90 * Select the currently highlighted node. If the node is a group, create a |
dmazzoni
2017/05/05 18:23:19
Also document what happens if you're on the curren
elichtenberg
2017/05/06 00:13:53
Done.
| |
91 * new tree walker for the new subtree the user is scanning through. | |
92 * Otherwise, meaning the node is interesting, perform the default action on | |
93 * it. | |
73 */ | 94 */ |
74 doDefault: function() { | 95 selectCurrentNode: function() { |
75 if (!this.node_) | 96 if (!this.node_ || !this.scope_ || !this.treeWalker_) |
76 return; | 97 return; |
77 | 98 |
99 if (this.node_ === this.scope_) { | |
100 let oldScope = this.oldScopes_.pop(); | |
101 | |
102 // Don't let user select the top-level root node (i.e., the desktop node). | |
103 if (!oldScope) | |
dmazzoni
2017/05/05 18:25:52
One possible bug - it's possible that the old scop
elichtenberg
2017/05/06 00:13:53
Done.
| |
104 return; | |
105 | |
106 this.scope_ = oldScope; | |
107 this.treeWalker_ = this.createTreeWalker_(this.scope_, this.node_); | |
108 return; | |
109 } | |
110 | |
111 if (AutomationPredicate.isGroup(this.node_, this.scope_)) { | |
112 this.oldScopes_.push(this.scope_); | |
113 this.scope_ = this.node_; | |
114 this.treeWalker_ = this.createTreeWalker_(this.scope_); | |
115 return; | |
116 } | |
117 | |
78 this.node_.doDefault(); | 118 this.node_.doDefault(); |
79 }, | 119 }, |
80 | 120 |
121 /** | |
122 * Create an AutomationTreeWalker for the subtree with |scope| as its root. | |
123 * If |opt_start| is defined, the tree walker will start walking the tree | |
124 * from |opt_start|; otherwise, it will start from |scope|. | |
125 * | |
126 * @param {!chrome.automation.AutomationNode} scope | |
127 * @param {!chrome.automation.AutomationNode=} opt_start | |
128 * @return {!AutomationTreeWalker} | |
129 */ | |
130 createTreeWalker_: function(scope, opt_start) { | |
131 // If no explicit start node, start walking the tree from |scope|. | |
dmazzoni
2017/05/05 18:23:19
Does it start at |scope|, or at the first child?
elichtenberg
2017/05/06 00:13:53
I agree. I changed selectCurrentNode so that when
| |
132 let start = opt_start || scope; | |
133 | |
134 let leafPred = function(node) { | |
135 return (node !== scope && AutomationPredicate.isSubtreeLeaf(node, scope)) | |
136 || !AutomationPredicate.isInterestingSubtree(node); | |
137 }; | |
138 let visitPred = function(node) { | |
139 // Avoid visiting the top-level root node (i.e., the desktop node). | |
140 return node !== this.desktop_ | |
141 && AutomationPredicate.isSubtreeLeaf(node, scope); | |
142 }.bind(this); | |
143 | |
144 let restrictions = { | |
145 leaf: leafPred, | |
146 visit: visitPred | |
147 }; | |
148 return new AutomationTreeWalker(start, scope, restrictions); | |
149 }, | |
150 | |
81 // TODO(elichtenberg): Move print functions to a custom logger class. Only | 151 // TODO(elichtenberg): Move print functions to a custom logger class. Only |
82 // log when debuggingEnabled is true. | 152 // log when debuggingEnabled is true. |
83 /** | 153 /** |
84 * Print out details about a node. | 154 * Print out details about a node. |
85 * | 155 * |
86 * @param {chrome.automation.AutomationNode} node | 156 * @param {chrome.automation.AutomationNode} node |
87 * @private | 157 * @private |
88 */ | 158 */ |
89 printNode_: function(node) { | 159 printNode_: function(node) { |
90 if (node) { | 160 if (node) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
148 */ | 218 */ |
149 debugMoveToParent: function() { | 219 debugMoveToParent: function() { |
150 let parent = this.treeWalker_.debugMoveToParent(this.node_); | 220 let parent = this.treeWalker_.debugMoveToParent(this.node_); |
151 if (parent) { | 221 if (parent) { |
152 this.node_ = parent; | 222 this.node_ = parent; |
153 this.printNode_(this.node_); | 223 this.printNode_(this.node_); |
154 chrome.accessibilityPrivate.setFocusRing([this.node_.location]); | 224 chrome.accessibilityPrivate.setFocusRing([this.node_.location]); |
155 } | 225 } |
156 } | 226 } |
157 }; | 227 }; |
OLD | NEW |