| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * Class to move to the appropriate node in the accessibility tree. |
| 7 * |
| 8 * @constructor |
| 9 */ |
| 10 function AutomationTreeWalker() {}; |
| 11 |
| 12 AutomationTreeWalker.prototype = { |
| 13 /** |
| 14 * Return the next/previous interesting node from |start|. If no interesting |
| 15 * node is found, return the first/last interesting node. If |doNext| is true, |
| 16 * will search for next node. Otherwise, will search for previous node. |
| 17 * |
| 18 * @param {chrome.automation.AutomationNode} start |
| 19 * @param {chrome.automation.AutomationNode} root |
| 20 * @param {boolean} doNext |
| 21 * @return {chrome.automation.AutomationNode} |
| 22 */ |
| 23 moveToNode: function(start, root, doNext) { |
| 24 let node = start; |
| 25 if (node) { |
| 26 do { |
| 27 node = doNext ? this.getNextNode_(node) : this.getPreviousNode_(node); |
| 28 } while (node && !this.isInteresting_(node)); |
| 29 if (node) |
| 30 return node; |
| 31 } |
| 32 |
| 33 if (root) { |
| 34 console.log( |
| 35 'Restarting search for node at ' + (doNext ? 'first' : 'last')); |
| 36 node = doNext ? root.firstChild : this.getYoungestDescendant_(root); |
| 37 while (node && !this.isInteresting_(node)) |
| 38 node = doNext ? this.getNextNode_(node) : this.getPreviousNode_(node); |
| 39 if (node) |
| 40 return node; |
| 41 } |
| 42 |
| 43 console.log('Found no interesting nodes to visit.'); |
| 44 return null; |
| 45 }, |
| 46 |
| 47 /** |
| 48 * Given a flat list of nodes in pre-order, get the node that comes after |
| 49 * |node|. |
| 50 * |
| 51 * @param {!chrome.automation.AutomationNode} node |
| 52 * @return {!chrome.automation.AutomationNode|undefined} |
| 53 * @private |
| 54 */ |
| 55 getNextNode_: function(node) { |
| 56 // Check for child. |
| 57 let child = node.firstChild; |
| 58 if (child) |
| 59 return child; |
| 60 |
| 61 // No child. Check for right-sibling. |
| 62 let sibling = node.nextSibling; |
| 63 if (sibling) |
| 64 return sibling; |
| 65 |
| 66 // No right-sibling. Get right-sibling of closest ancestor. |
| 67 let ancestor = node.parent; |
| 68 while (ancestor) { |
| 69 let aunt = ancestor.nextSibling; |
| 70 if (aunt) |
| 71 return aunt; |
| 72 ancestor = ancestor.parent; |
| 73 } |
| 74 |
| 75 // No node found after |node|, so return undefined. |
| 76 return undefined; |
| 77 }, |
| 78 |
| 79 /** |
| 80 * Given a flat list of nodes in pre-order, get the node that comes before |
| 81 * |node|. |
| 82 * |
| 83 * @param {!chrome.automation.AutomationNode} node |
| 84 * @return {!chrome.automation.AutomationNode|undefined} |
| 85 * @private |
| 86 */ |
| 87 getPreviousNode_: function(node) { |
| 88 // Check for left-sibling. If a left-sibling exists, return its youngest |
| 89 // descendant if it has one, or otherwise return the sibling. |
| 90 let sibling = node.previousSibling; |
| 91 if (sibling) |
| 92 return this.getYoungestDescendant_(sibling) || sibling; |
| 93 |
| 94 // No left-sibling. Return parent if it exists; otherwise return undefined. |
| 95 return node.parent; |
| 96 }, |
| 97 |
| 98 /** |
| 99 * Get the youngest descendant of |node| if it has one. |
| 100 * |
| 101 * @param {!chrome.automation.AutomationNode} node |
| 102 * @return {!chrome.automation.AutomationNode|undefined} |
| 103 * @private |
| 104 */ |
| 105 getYoungestDescendant_: function(node) { |
| 106 if (!node.lastChild) |
| 107 return undefined; |
| 108 |
| 109 while (node.lastChild) |
| 110 node = node.lastChild; |
| 111 |
| 112 return node; |
| 113 }, |
| 114 |
| 115 /** |
| 116 * Returns true if |node| is interesting. |
| 117 * |
| 118 * @param {!chrome.automation.AutomationNode} node |
| 119 * @return {boolean|undefined} |
| 120 * @private |
| 121 */ |
| 122 isInteresting_: function(node) { |
| 123 return node.state && node.state.focusable; |
| 124 }, |
| 125 |
| 126 /** |
| 127 * Return the next sibling of |node| if it has one. |
| 128 * |
| 129 * @param {chrome.automation.AutomationNode} node |
| 130 * @return {chrome.automation.AutomationNode} |
| 131 */ |
| 132 debugMoveToNext: function(node) { |
| 133 if (!node) |
| 134 return null; |
| 135 |
| 136 let next = node.nextSibling; |
| 137 if (next) { |
| 138 return next; |
| 139 } else { |
| 140 console.log('Node is last of siblings'); |
| 141 console.log('\n'); |
| 142 return null; |
| 143 } |
| 144 }, |
| 145 |
| 146 /** |
| 147 * Return the previous sibling of |node| if it has one. |
| 148 * |
| 149 * @param {chrome.automation.AutomationNode} node |
| 150 * @return {chrome.automation.AutomationNode} |
| 151 */ |
| 152 debugMoveToPrevious: function(node) { |
| 153 if (!node) |
| 154 return null; |
| 155 |
| 156 let prev = node.previousSibling; |
| 157 if (prev) { |
| 158 return prev; |
| 159 } else { |
| 160 console.log('Node is first of siblings'); |
| 161 console.log('\n'); |
| 162 return null; |
| 163 } |
| 164 }, |
| 165 |
| 166 /** |
| 167 * Return the first child of |node| if it has one. |
| 168 * |
| 169 * @param {chrome.automation.AutomationNode} node |
| 170 * @return {chrome.automation.AutomationNode} |
| 171 */ |
| 172 debugMoveToFirstChild: function(node) { |
| 173 if (!node) |
| 174 return null; |
| 175 |
| 176 let child = node.firstChild; |
| 177 if (child) { |
| 178 return child; |
| 179 } else { |
| 180 console.log('Node has no children'); |
| 181 console.log('\n'); |
| 182 return null; |
| 183 } |
| 184 }, |
| 185 |
| 186 /** |
| 187 * Return the parent of |node| if it has one. |
| 188 * |
| 189 * @param {chrome.automation.AutomationNode} node |
| 190 * @return {chrome.automation.AutomationNode} |
| 191 */ |
| 192 debugMoveToParent: function(node) { |
| 193 if (!node) |
| 194 return null; |
| 195 |
| 196 let parent = node.parent; |
| 197 if (parent) { |
| 198 return parent; |
| 199 } else { |
| 200 console.log('Node has no parent'); |
| 201 console.log('\n'); |
| 202 return null; |
| 203 } |
| 204 } |
| 205 }; |
| OLD | NEW |