Chromium Code Reviews| 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 |