| Index: chrome/browser/resources/chromeos/switch_access/switch_access.js
|
| diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access.js b/chrome/browser/resources/chromeos/switch_access/switch_access.js
|
| index 5b35495f867bbb23f49876b9496628f1582a6585..6333888bc62a6722cc3b744a8d85a0bcdb9e2783 100644
|
| --- a/chrome/browser/resources/chromeos/switch_access/switch_access.js
|
| +++ b/chrome/browser/resources/chromeos/switch_access/switch_access.js
|
| @@ -2,90 +2,277 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -var AutomationNode = chrome.automation.AutomationNode;
|
| +let AutomationNode = chrome.automation.AutomationNode;
|
|
|
| +let debuggingEnabled = true;
|
| /**
|
| * @constructor
|
| */
|
| -var SwitchAccess = function() {
|
| - console.log("Switch access is enabled");
|
| +let SwitchAccess = function() {
|
| + console.log('Switch access is enabled');
|
|
|
| // Currently selected node.
|
| /** @private {AutomationNode} */
|
| this.node_ = null;
|
|
|
| + // Root node (i.e., the desktop).
|
| + /** @private {AutomationNode} */
|
| + this.root_ = null;
|
| +
|
| // List of nodes to push to / pop from in case this.node_ is lost.
|
| /** @private {!Array<!AutomationNode>} */
|
| this.ancestorList_ = [];
|
|
|
| chrome.automation.getDesktop(function(desktop) {
|
| this.node_ = desktop;
|
| - console.log("AutomationNode for desktop is loaded");
|
| + this.root_ = desktop;
|
| + console.log('AutomationNode for desktop is loaded');
|
| this.printDetails_();
|
|
|
| - document.addEventListener("keyup", function(event) {
|
| - if (event.key === "1") {
|
| - console.log("1 = go to previous element");
|
| - this.moveToPrevious_();
|
| - } else if (event.key === "2") {
|
| - console.log("2 = go to next element");
|
| - this.moveToNext_();
|
| - } else if (event.key === "3") {
|
| - console.log("3 = go to child element");
|
| - this.moveToFirstChild_();
|
| - } else if (event.key === "4") {
|
| - console.log("4 = go to parent element");
|
| - this.moveToParent_();
|
| - } else if (event.key === "5") {
|
| - console.log("5 is not yet implemented");
|
| - console.log("\n");
|
| + document.addEventListener('keyup', function(event) {
|
| + switch (event.key) {
|
| + case '1':
|
| + console.log('1 = go to previous element');
|
| + this.moveToPrevious_();
|
| + break;
|
| + case '2':
|
| + console.log('2 = go to next element');
|
| + this.moveToNext_();
|
| + break;
|
| + case '3':
|
| + console.log('3 = do default on element');
|
| + this.doDefault_();
|
| + break;
|
| + }
|
| + if (debuggingEnabled) {
|
| + switch (event.key) {
|
| + case '6':
|
| + console.log('6 = go to previous element (debug mode)');
|
| + this.debugMoveToPrevious_();
|
| + break;
|
| + case '7':
|
| + console.log('7 = go to next element (debug mode)');
|
| + this.debugMoveToNext_();
|
| + break;
|
| + case '8':
|
| + console.log('8 = go to child element (debug mode)');
|
| + this.debugMoveToFirstChild_();
|
| + break;
|
| + case '9':
|
| + console.log('9 = go to parent element (debug mode)');
|
| + this.debugMoveToParent_();
|
| + break;
|
| + }
|
| }
|
| - chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
|
| + if (this.node_)
|
| + chrome.accessibilityPrivate.setFocusRing([this.node_.location]);
|
| }.bind(this));
|
| }.bind(this));
|
| };
|
|
|
| SwitchAccess.prototype = {
|
| /**
|
| - * Move to the previous sibling of this.node_ if it has one.
|
| + * Set this.node_ to the previous interesting node. If no interesting node
|
| + * comes before this.node_, set this.node_ to the last interesting node.
|
| + *
|
| + * @private
|
| */
|
| moveToPrevious_: function() {
|
| - var previous = this.node_.previousSibling;
|
| + if (this.node_) {
|
| + let prev = this.getPreviousNode_(this.node_);
|
| + while (prev && !this.isInteresting_(prev)) {
|
| + prev = this.getPreviousNode_(prev);
|
| + }
|
| + if (prev) {
|
| + this.node_ = prev;
|
| + this.printNode_(this.node_);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (this.root_) {
|
| + console.log('Reached the first interesting node. Restarting with last.')
|
| + let prev = this.getYoungestDescendant_(this.root_);
|
| + while (prev && !this.isInteresting_(prev)) {
|
| + prev = this.getPreviousNode_(prev);
|
| + }
|
| + if (prev) {
|
| + this.node_ = prev;
|
| + this.printNode_(this.node_);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + console.log('Found no interesting nodes to visit.')
|
| + },
|
| +
|
| + /**
|
| + * Set this.node_ to the next interesting node. If no interesting node comes
|
| + * after this.node_, set this.node_ to the first interesting node.
|
| + *
|
| + * @private
|
| + */
|
| + moveToNext_: function() {
|
| + if (this.node_) {
|
| + let next = this.getNextNode_(this.node_);
|
| + while (next && !this.isInteresting_(next))
|
| + next = this.getNextNode_(next);
|
| + if (next) {
|
| + this.node_ = next;
|
| + this.printNode_(this.node_);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (this.root_) {
|
| + console.log('Reached the last interesting node. Restarting with first.');
|
| + let next = this.root_.firstChild;
|
| + while (next && !this.isInteresting_(next))
|
| + next = this.getNextNode_(next);
|
| + if (next) {
|
| + this.node_ = next;
|
| + this.printNode_(this.node_);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + console.log('Found no interesting nodes to visit.');
|
| + },
|
| +
|
| + /**
|
| + * Given a flat list of nodes in pre-order, get the node that comes after
|
| + * |node|.
|
| + *
|
| + * @param {!AutomationNode} node
|
| + * @return {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;
|
| + 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 {!AutomationNode} node
|
| + * @return {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);
|
| + if (descendant)
|
| + return descendant;
|
| + return sibling;
|
| + }
|
| +
|
| + // No left-sibling. Check for parent.
|
| + let parent = node.parent;
|
| + 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 {!AutomationNode} node
|
| + * @return {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 {!AutomationNode} node
|
| + * @return {boolean}
|
| + * @private
|
| + */
|
| + isInteresting_: function(node) {
|
| + return node.state && node.state.focusable;
|
| + },
|
| +
|
| + /**
|
| + * Move to the previous sibling of this.node_ if it has one.
|
| + *
|
| + * @private
|
| + */
|
| + debugMoveToPrevious_: function() {
|
| + let previous = this.node_.previousSibling;
|
| if (previous) {
|
| this.node_ = previous;
|
| this.printDetails_();
|
| } else {
|
| - console.log("Node is first of siblings");
|
| - console.log("\n");
|
| + console.log('Node is first of siblings');
|
| + console.log('\n');
|
| }
|
| },
|
|
|
| /**
|
| * Move to the next sibling of this.node_ if it has one.
|
| + *
|
| + * @private
|
| */
|
| - moveToNext_: function() {
|
| - var next = this.node_.nextSibling;
|
| + debugMoveToNext_: function() {
|
| + let next = this.node_.nextSibling;
|
| if (next) {
|
| this.node_ = next;
|
| this.printDetails_();
|
| } else {
|
| - console.log("Node is last of siblings");
|
| - console.log("\n");
|
| + console.log('Node is last of siblings');
|
| + console.log('\n');
|
| }
|
| },
|
|
|
| /**
|
| * Move to the first child of this.node_ if it has one.
|
| + *
|
| + * @private
|
| */
|
| - moveToFirstChild_: function() {
|
| - var child = this.node_.firstChild;
|
| + debugMoveToFirstChild_: function() {
|
| + let child = this.node_.firstChild;
|
| if (child) {
|
| this.ancestorList_.push(this.node_);
|
| this.node_ = child;
|
| this.printDetails_();
|
| } else {
|
| - console.log("Node has no children");
|
| - console.log("\n");
|
| + console.log('Node has no children');
|
| + console.log('\n');
|
| }
|
| },
|
|
|
| @@ -93,26 +280,47 @@ SwitchAccess.prototype = {
|
| * Move to the parent of this.node_ if it has one. If it does not have a
|
| * parent but it is not the top level root node, then this.node_ lost track of
|
| * its neighbors, and we move to an ancestor node.
|
| + *
|
| + * @private
|
| */
|
| - moveToParent_: function() {
|
| - var parent = this.node_.parent;
|
| + debugMoveToParent_: function() {
|
| + let parent = this.node_.parent;
|
| if (parent) {
|
| this.ancestorList_.pop();
|
| this.node_ = parent;
|
| this.printDetails_();
|
| } else if (this.ancestorList_.length === 0) {
|
| - console.log("Node has no parent");
|
| - console.log("\n");
|
| + console.log('Node has no parent');
|
| + console.log('\n');
|
| } else {
|
| console.log(
|
| - "Node could not find its parent, so moved to recent ancestor");
|
| - var ancestor = this.ancestorList_.pop();
|
| + 'Node could not find its parent, so moved to recent ancestor');
|
| + let ancestor = this.ancestorList_.pop();
|
| this.node_ = ancestor;
|
| this.printDetails_();
|
| }
|
| },
|
|
|
| /**
|
| + * Perform the default action on the currently selected node.
|
| + *
|
| + * @private
|
| + */
|
| + doDefault_: function() {
|
| + let state = this.node_.state;
|
| + if (state && state.focusable)
|
| + console.log('Node was focusable, doing default on it')
|
| + else if (state)
|
| + console.log('Node was not focusable, but still doing default');
|
| + else
|
| + console.log('Node has no state, still doing default');
|
| + console.log('\n');
|
| + this.node_.doDefault();
|
| + },
|
| +
|
| + // TODO(elichtenberg): Move print functions to a custom logger class. Only
|
| + // log when debuggingEnabled is true.
|
| + /**
|
| * Print out details about the currently selected node and the list of
|
| * ancestors.
|
| *
|
| @@ -121,7 +329,7 @@ SwitchAccess.prototype = {
|
| printDetails_: function() {
|
| this.printNode_(this.node_);
|
| console.log(this.ancestorList_);
|
| - console.log("\n");
|
| + console.log('\n');
|
| },
|
|
|
| /**
|
| @@ -132,22 +340,23 @@ SwitchAccess.prototype = {
|
| */
|
| printNode_: function(node) {
|
| if (node) {
|
| - console.log("Name = " + node.name);
|
| - console.log("Role = " + node.role);
|
| - if (!node.parent) {
|
| - console.log("At index " + node.indexInParent + ", has no parent");
|
| - } else {
|
| - var numSiblings = node.parent.children.length;
|
| + console.log('Name = ' + node.name);
|
| + console.log('Role = ' + node.role);
|
| + if (!node.parent)
|
| + console.log('At index ' + node.indexInParent + ', has no parent');
|
| + else {
|
| + let numSiblings = node.parent.children.length;
|
| console.log(
|
| - "At index " + node.indexInParent + ", there are "
|
| - + numSiblings + " siblings");
|
| + 'At index ' + node.indexInParent + ', there are '
|
| + + numSiblings + ' siblings');
|
| }
|
| - console.log("Has " + node.children.length + " children");
|
| + console.log('Has ' + node.children.length + ' children');
|
| } else {
|
| - console.log("Node is null");
|
| + console.log('Node is null');
|
| }
|
| console.log(node);
|
| + console.log('\n');
|
| }
|
| };
|
|
|
| -new SwitchAccess();
|
| +window.switchAccess = new SwitchAccess();
|
|
|