| Index: chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
|
| diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
|
| index f26ecc76ceac3bdcc491a4a46ab5b00a90bf64f3..ff79976ed11b1108c25c8e4fbe75bcc117270034 100644
|
| --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
|
| +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
|
| @@ -11,6 +11,8 @@ goog.provide('cvox2.Background');
|
| goog.provide('cvox2.global');
|
|
|
| goog.require('cvox.TabsApiHandler');
|
| +goog.require('cvox2.AutomationPredicates');
|
| +goog.require('cvox2.AutomationUtil');
|
|
|
| /** Classic Chrome accessibility API. */
|
| cvox2.global.accessibility =
|
| @@ -32,6 +34,14 @@ cvox2.Background = function() {
|
| cvox.ChromeVox.braille,
|
| cvox.ChromeVox.earcons);
|
|
|
| + /** @type {AutomationNode} @private */
|
| + this.currentNode_ = null;
|
| +
|
| + /** @type {cvox.TabsApiHandler} @private */
|
| + this.tabsHandler_ = new cvox.TabsApiHandler(cvox.ChromeVox.tts,
|
| + cvox.ChromeVox.braille,
|
| + cvox.ChromeVox.earcons);
|
| +
|
| // Only needed with unmerged ChromeVox classic loaded before.
|
| cvox2.global.accessibility.setAccessibilityEnabled(false);
|
|
|
| @@ -66,9 +76,8 @@ cvox2.Background.prototype = {
|
| return;
|
| }
|
|
|
| - if (!chrome.commands.onCommand.hasListeners()) {
|
| + if (!chrome.commands.onCommand.hasListeners())
|
| chrome.commands.onCommand.addListener(this.onGotCommand);
|
| - }
|
|
|
| this.disableClassicChromeVox_(tab.id);
|
|
|
| @@ -83,25 +92,116 @@ cvox2.Background.prototype = {
|
| onGotTree: function(root) {
|
| // Register all automation event listeners.
|
| root.addEventListener(chrome.automation.EventType.focus,
|
| - this.onAutomationEvent.bind(this),
|
| + this.onFocus,
|
| + true);
|
| + root.addEventListener(chrome.automation.EventType.loadComplete,
|
| + this.onLayoutOrLoadComplete,
|
| true);
|
| + root.addEventListener(chrome.automation.EventType.layoutComplete,
|
| + this.onLayoutOrLoadComplete,
|
| + true);
|
| +
|
| + if (root.attributes.docLoaded)
|
| + this.onLayoutOrLoadComplete({target: root});
|
| },
|
|
|
| /**
|
| - * A generic handler for all desktop automation events.
|
| - * @param {AutomationEvent} evt The event.
|
| + * Handles chrome.commands.onCommand.
|
| + * @param {string} command
|
| */
|
| - onAutomationEvent: function(evt) {
|
| - var output = evt.target.attributes.name + ' ' + evt.target.role;
|
| + onGotCommand: function(command) {
|
| + if (!this.current_)
|
| + return;
|
| +
|
| + var previous = this.current_;
|
| + var current = this.current_;
|
| +
|
| + // Reverse?
|
| + var r = false;
|
| + var pred = null;
|
| + switch (command) {
|
| + case 'nextHeading':
|
| + r = false;
|
| + pred = cvox2.AutomationPredicates.heading;
|
| + break;
|
| + case 'previousHeading':
|
| + r = true;
|
| + pred = cvox2.AutomationPredicates.heading;
|
| + break;
|
| + case 'nextLine':
|
| + r = false;
|
| + pred = cvox2.AutomationPredicates.inlineTextBox;
|
| + break;
|
| + case 'previousLine':
|
| + r = true;
|
| + pred = cvox2.AutomationPredicates.inlineTextBox;
|
| + break;
|
| + case 'nextLink':
|
| + r = false;
|
| + pred = cvox2.AutomationPredicates.link;
|
| + break;
|
| + case 'previousLink':
|
| + r = true;
|
| + pred = cvox2.AutomationPredicates.link;
|
| + break;
|
| + case 'nextElement':
|
| + current = current.role == chrome.automation.RoleType.inlineTextBox ?
|
| + current.parent() : current;
|
| + current = cvox2.AutomationUtil.findNextNode(current,
|
| + false,
|
| + cvox2.AutomationPredicates.inlineTextBox);
|
| + current = current ? current.parent() : current;
|
| + break;
|
| + case 'previousElement':
|
| + current = current.role == chrome.automation.RoleType.inlineTextBox ?
|
| + current.parent() : current;
|
| + current = cvox2.AutomationUtil.findNextNode(current,
|
| + true,
|
| + cvox2.AutomationPredicates.inlineTextBox);
|
| + current = current ? current.parent() : current;
|
| + break;
|
| + }
|
| +
|
| + if (pred)
|
| + current = cvox2.AutomationUtil.findNextNode(current, r, pred);
|
| +
|
| + if (current)
|
| + current.focus();
|
| +
|
| + this.onFocus({target: current || previous});
|
| + },
|
| +
|
| + /**
|
| + * Provides all feedback once ChromeVox's focus changes.
|
| + * @param {Object} evt
|
| + */
|
| + onFocus: function(evt) {
|
| + var node = evt.target;
|
| + if (!node)
|
| + return;
|
| + var container = node;
|
| + while (container && (container.role == 'inlineTextBox' ||
|
| + container.role == 'staticText'))
|
| + container = container.parent();
|
| +
|
| + var role = container ? container.role : node.role;
|
| +
|
| + var output =
|
| + [node.attributes.name, node.attributes.value, role].join(', ');
|
| cvox.ChromeVox.tts.speak(output, cvox.AbstractTts.QUEUE_MODE_FLUSH);
|
| cvox.ChromeVox.braille.write(cvox.NavBraille.fromText(output));
|
| + this.current_ = node;
|
| },
|
|
|
| /**
|
| - * Handles chrome.commands.onCommand.
|
| - * @param {string} command
|
| + * Provides all feedback once a load complete event fires.
|
| + * @param {Object} evt
|
| */
|
| - onGotCommand: function(command) {
|
| + onLayoutOrLoadComplete: function(evt) {
|
| + this.current_ = cvox2.AutomationUtil.findDeepestNode(evt.target,
|
| + false,
|
| + cvox2.AutomationPredicates.inlineTextBox);
|
| + this.onFocus({target: this.current_});
|
| },
|
|
|
| /**
|
| @@ -117,7 +217,7 @@ cvox2.Background.prototype = {
|
|
|
| /**
|
| * Disables classic ChromeVox.
|
| - * @param {number} tabId The tab where ChromeVox classic is running.
|
| + * @param {number} tabId The tab where ChromeVox classic is running in.
|
| */
|
| disableClassicChromeVox_: function(tabId) {
|
| chrome.tabs.executeScript(
|
|
|