Commit d731e183 authored by Anastasia Helfinstein's avatar Anastasia Helfinstein Committed by Commit Bot

[Switch Access] Listen to locationChanged on all ancestors

When a window is resized, a locationChanged event is not fired on its
descendants (e.g. the maximize button, the web contents). So Switch
Access' locationChanged handler should listen to events on all of the
current node's ancestors as well.

Also adds support for listening to multiple nodes with
RepeatedEventListener.

AX-Relnotes: n/a.
Bug: 1105296
Change-Id: Idba74866ef71fa0adebb1e08647a860404afb43e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2300825Reviewed-by: default avatarKatie Dektar <katie@chromium.org>
Commit-Queue: Anastasia Helfinstein <anastasi@google.com>
Cr-Commit-Position: refs/heads/master@{#789248}
parent adb0670a
...@@ -8,19 +8,37 @@ ...@@ -8,19 +8,37 @@
*/ */
class RepeatedEventHandler { class RepeatedEventHandler {
/** /**
* @param {!chrome.automation.AutomationNode} node * @param {!chrome.automation.AutomationNode |
* !Array<!chrome.automation.AutomationNode>} nodes
* @param {!chrome.automation.EventType} type * @param {!chrome.automation.EventType} type
* @param {!function(!chrome.automation.AutomationEvent)} callback * @param {!function(!chrome.automation.AutomationEvent)} callback
* @param {boolean} exact_match Whether to ignore events where the target is * @param {{exactMatch: (boolean|undefined), capture: (boolean|undefined),
* not the provided node. * allAncestors: (boolean|undefined)}} options
* @param {boolean} capture * exactMatch True if events should only be handled if the provided node is
* the target.
* capture True if events for children of |node| should be handled before
* they reach the target node; false to be handled after the target
* node.
* allAncestors True if a listener should be added to all ancestors of the
* provided nodes.
*/ */
constructor(node, type, callback, exact_match = false, capture = false) { constructor(nodes, type, callback, options = {}) {
/** @private {!Array<!chrome.automation.AutomationEvent>} */ /** @private {!Array<!chrome.automation.AutomationEvent>} */
this.eventStack_ = []; this.eventStack_ = [];
/** @private {!chrome.automation.AutomationNode} */ /** @private {!Array<chrome.automation.AutomationNode>} */
this.node_ = node; this.nodes_ = nodes instanceof Array ? nodes : [nodes];
if (options.allAncestors) {
nodes = this.nodes_; // Make sure nodes is an array.
this.nodes_ = [];
for (let node of nodes) {
while (node) {
this.nodes_.push(node);
node = node.parent;
}
}
}
/** @private {!chrome.automation.EventType} */ /** @private {!chrome.automation.EventType} */
this.type_ = type; this.type_ = type;
...@@ -29,20 +47,24 @@ class RepeatedEventHandler { ...@@ -29,20 +47,24 @@ class RepeatedEventHandler {
this.callback_ = callback; this.callback_ = callback;
/** @private {boolean} */ /** @private {boolean} */
this.exact_match_ = exact_match; this.exactMatch_ = options.exactMatch || false;
/** @private {boolean} */ /** @private {boolean} */
this.capture_ = capture; this.capture_ = options.capture || false;
/** @private {!function(!chrome.automation.AutomationEvent)} */ /** @private {!function(!chrome.automation.AutomationEvent)} */
this.handler_ = this.onEvent_.bind(this); this.handler_ = this.onEvent_.bind(this);
node.addEventListener(type, this.handler_, capture); for (const node of this.nodes_) {
node.addEventListener(this.type_, this.handler_, this.capture_);
}
} }
/** Stops listening or handling future events. */ /** Stops listening or handling future events. */
stopListening() { stopListening() {
this.node_.removeEventListener(this.type_, this.handler_, this.capture_); for (const node of this.nodes_) {
node.removeEventListener(this.type_, this.handler_, this.capture_);
}
} }
/** /**
...@@ -61,7 +83,7 @@ class RepeatedEventHandler { ...@@ -61,7 +83,7 @@ class RepeatedEventHandler {
} }
const event = this.eventStack_.pop(); const event = this.eventStack_.pop();
if (this.exact_match_ && event.target !== this.node_) { if (this.exactMatch_ && !this.nodes_.includes(event.target)) {
return; return;
} }
this.eventStack_ = []; this.eventStack_ = [];
......
...@@ -92,7 +92,8 @@ class BackButtonNode extends SAChildNode { ...@@ -92,7 +92,8 @@ class BackButtonNode extends SAChildNode {
this.locationChangedHandler_ = new RepeatedEventHandler( this.locationChangedHandler_ = new RepeatedEventHandler(
this.group_.automationNode, this.group_.automationNode,
chrome.automation.EventType.LOCATION_CHANGED, chrome.automation.EventType.LOCATION_CHANGED,
() => FocusRingManager.setFocusedNode(this), true /* exact_match */); () => FocusRingManager.setFocusedNode(this),
{exactMatch: true, allAncestors: true});
} }
} }
......
...@@ -123,7 +123,8 @@ class NodeWrapper extends SAChildNode { ...@@ -123,7 +123,8 @@ class NodeWrapper extends SAChildNode {
super.onFocus(); super.onFocus();
this.locationChangedHandler_ = new RepeatedEventHandler( this.locationChangedHandler_ = new RepeatedEventHandler(
this.baseNode_, chrome.automation.EventType.LOCATION_CHANGED, this.baseNode_, chrome.automation.EventType.LOCATION_CHANGED,
() => FocusRingManager.setFocusedNode(this), true /* exact_match */); () => FocusRingManager.setFocusedNode(this),
{exactMatch: true, allAncestors: true});
} }
/** @override */ /** @override */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment