Chromium Code Reviews| Index: chrome/browser/resources/chromeos/switch_access/tree_walker.js |
| diff --git a/chrome/browser/resources/chromeos/switch_access/tree_walker.js b/chrome/browser/resources/chromeos/switch_access/tree_walker.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..77b883a691fa5c69b42e0f9e96e3fae5f15c219f |
| --- /dev/null |
| +++ b/chrome/browser/resources/chromeos/switch_access/tree_walker.js |
| @@ -0,0 +1,240 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +/** |
| + * Class to move to the appropriate node in the accessibility tree. |
| + * |
| + * @constructor |
| + */ |
| +function AutomationTreeWalker() {}; |
| + |
| +AutomationTreeWalker.prototype = { |
| + /** |
| + * Return the next interesting node after |node|. If no interesting node comes |
| + * after |node|, return the first interesting node. |
| + * |
| + * @param {chrome.automation.AutomationNode} node |
| + * @param {chrome.automation.AutomationNode} root |
| + * @return {chrome.automation.AutomationNode} |
| + */ |
| + moveToNext: function(node, root) { |
| + if (node) { |
| + let next = this.getNextNode_(node); |
|
David Tseng
2017/03/29 21:57:21
You could just have
do {
node = this...
whil
elichtenberg
2017/03/30 21:46:56
Done.
|
| + while (next && !this.isInteresting_(next)) |
| + next = this.getNextNode_(next); |
| + if (next) |
| + return next; |
| + } |
| + |
| + if (root) { |
| + console.log('Reached the last interesting node. Restarting with first.'); |
| + let next = root.firstChild; |
| + while (next && !this.isInteresting_(next)) |
| + next = this.getNextNode_(next); |
| + if (next) |
| + return next; |
| + } |
| + |
| + console.log('Found no interesting nodes to visit.'); |
| + return null; |
| + }, |
| + |
| + /** |
| + * Returns the previous interesting node before |node|. If no interesting node |
| + * comes before |node|, return the last interesting node. |
| + * |
| + * @param {chrome.automation.AutomationNode} node |
| + * @param {chrome.automation.AutomationNode} root |
| + * @return {chrome.automation.AutomationNode} |
| + */ |
| + moveToPrevious: function(node, root) { |
| + if (node) { |
| + let prev = this.getPreviousNode_(node); |
| + while (prev && !this.isInteresting_(prev)) |
| + prev = this.getPreviousNode_(prev); |
| + if (prev) |
| + return prev; |
| + } |
| + |
| + if (root) { |
| + console.log('Reached the first interesting node. Restarting with last.') |
| + let prev = this.getYoungestDescendant_(root); |
| + while (prev && !this.isInteresting_(prev)) |
| + prev = this.getPreviousNode_(prev); |
| + if (prev) |
| + return prev; |
| + } |
|
David Tseng
2017/03/29 21:57:21
You can combine this function with the one above a
elichtenberg
2017/03/30 21:46:56
Done.
|
| + |
| + console.log('Found no interesting nodes to visit.') |
| + return null; |
| + }, |
| + |
| + /** |
| + * Given a flat list of nodes in pre-order, get the node that comes after |
| + * |node|. |
| + * |
| + * @param {!chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + * @private |
| + */ |
| + getNextNode_: function(node) { |
| + // Check for child. |
| + let child = node.firstChild; |
| + if (child) |
| + return child; |
| + |
| + // No child. Check for right-sibling. |
| + let sibling = node.nextSibling; |
| + if (sibling) |
| + return sibling; |
| + |
| + // No right-sibling. Get right-sibling of closest ancestor. |
| + let ancestor = node.parent; |
| + while (ancestor) { |
| + let aunt = ancestor.nextSibling; |
| + if (aunt) |
| + return aunt; |
|
David Tseng
2017/03/29 21:57:21
Comment: very gender specific :).
elichtenberg
2017/03/30 21:46:56
Haha, no gender-neutral word for aunt or uncle yet
|
| + ancestor = ancestor.parent; |
| + } |
| + |
| + // No node found after |node|, so return null. |
| + return null; |
| + }, |
| + |
| + /** |
| + * Given a flat list of nodes in pre-order, get the node that comes before |
| + * |node|. |
| + * |
| + * @param {!chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + * @private |
| + */ |
| + getPreviousNode_: function(node) { |
| + // Check for left-sibling. Return its youngest descendant if it has one. |
| + // Otherwise, return the sibling. |
| + let sibling = node.previousSibling; |
| + if (sibling) { |
| + let descendant = this.getYoungestDescendant_(sibling); |
|
David Tseng
2017/03/29 21:57:21
return this.getYoungestDescendant_(sibling) || sib
elichtenberg
2017/03/30 21:46:56
Done.
|
| + if (descendant) |
| + return descendant; |
| + return sibling; |
| + } |
| + |
| + // No left-sibling. Check for parent. |
| + let parent = node.parent; |
|
David Tseng
2017/03/29 21:57:21
return node.parent; (no need to do any of the belo
elichtenberg
2017/03/30 21:46:56
Done.
|
| + if (parent) |
| + return parent; |
| + |
| + // No node found before |node|, so return null. |
| + return null; |
| + }, |
| + |
| + /** |
| + * Get the youngest descendant of |node| if it has one. |
| + * |
| + * @param {!chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + * @private |
| + */ |
| + getYoungestDescendant_: function(node) { |
| + if (!node.lastChild) |
| + return null; |
| + |
| + while (node.lastChild) |
| + node = node.lastChild; |
| + |
| + return node; |
| + }, |
| + |
| + /** |
| + * Returns true if |node| is interesting. |
| + * |
| + * @param {!chrome.automation.AutomationNode} node |
| + * @return {boolean} |
| + * @private |
| + */ |
| + isInteresting_: function(node) { |
| + return node.state && node.state.focusable; |
| + }, |
| + |
| + /** |
| + * Return the next sibling of |node| if it has one. |
| + * |
| + * @param {chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + */ |
| + debugMoveToNext: function(node) { |
| + if (!node) |
| + return null; |
| + |
| + let next = node.nextSibling; |
| + if (next) { |
| + return next; |
| + } else { |
| + console.log('Node is last of siblings'); |
| + console.log('\n'); |
| + return null; |
| + } |
| + }, |
| + |
| + /** |
| + * Return the previous sibling of |node| if it has one. |
| + * |
| + * @param {chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + */ |
| + debugMoveToPrevious: function(node) { |
| + if (!node) |
| + return null; |
| + |
| + let prev = node.previousSibling; |
| + if (prev) { |
| + return prev; |
| + } else { |
| + console.log('Node is first of siblings'); |
| + console.log('\n'); |
| + return null; |
| + } |
| + }, |
| + |
| + /** |
| + * Return the first child of |node| if it has one. |
| + * |
| + * @param {chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + */ |
| + debugMoveToFirstChild: function(node) { |
| + if (!node) |
| + return null; |
| + |
| + let child = node.firstChild; |
| + if (child) { |
| + return child; |
| + } else { |
| + console.log('Node has no children'); |
| + console.log('\n'); |
| + return null; |
| + } |
| + }, |
| + |
| + /** |
| + * Return the parent of |node| if it has one. |
| + * |
| + * @param {chrome.automation.AutomationNode} node |
| + * @return {chrome.automation.AutomationNode} |
| + */ |
| + debugMoveToParent: function(node) { |
| + if (!node) |
| + return null; |
| + |
| + let parent = node.parent; |
| + if (parent) { |
| + return parent; |
| + } else { |
| + console.log('Node has no parent'); |
| + console.log('\n'); |
| + return null; |
| + } |
| + } |
| +}; |