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 523e200d0959ad5b670da9a1f74dd328354a809d..b7ba66a5df10207d47e76a7f239185fc0b7726aa 100644 |
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js |
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js |
@@ -8,11 +8,12 @@ |
*/ |
goog.provide('Background'); |
-goog.provide('ChromeVoxMode'); |
goog.provide('global'); |
goog.require('AutomationPredicate'); |
goog.require('AutomationUtil'); |
+goog.require('ChromeVoxState'); |
+goog.require('LiveRegions'); |
goog.require('NextEarcons'); |
goog.require('Output'); |
goog.require('Output.EventType'); |
@@ -31,21 +32,13 @@ var EventType = chrome.automation.EventType; |
var RoleType = chrome.automation.RoleType; |
/** |
- * All possible modes ChromeVox can run. |
- * @enum {string} |
- */ |
-ChromeVoxMode = { |
- CLASSIC: 'classic', |
- COMPAT: 'compat', |
- NEXT: 'next', |
- FORCE_NEXT: 'force_next' |
-}; |
- |
-/** |
* ChromeVox2 background page. |
* @constructor |
+ * @extends {ChromeVoxState} |
*/ |
Background = function() { |
+ ChromeVoxState.call(this); |
+ |
/** |
* A list of site substring patterns to use with ChromeVox next. Keep these |
* strings relatively specific. |
@@ -127,35 +120,115 @@ Background = function() { |
// Classic keymap. |
cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromDefaults(); |
- chrome.automation.addTreeChangeObserver(this.onTreeChange); |
+ // Live region handler. |
+ this.liveRegions_ = new LiveRegions(this); |
}; |
Background.prototype = { |
- /** Forces ChromeVox Next to be active for all tabs. */ |
- forceChromeVoxNextActive: function() { |
- this.setChromeVoxMode(ChromeVoxMode.FORCE_NEXT); |
- }, |
+ __proto__: ChromeVoxState.prototype, |
- /** @type {ChromeVoxMode} */ |
- get mode() { |
+ /** |
+ * @override |
+ */ |
+ getMode: function() { |
return this.mode_; |
}, |
- /** @type {cursors.Range} */ |
- get currentRange() { |
+ /** |
+ * @override |
+ */ |
+ setMode: function(mode, opt_injectClassic) { |
+ // Switching key maps potentially affects the key codes that involve |
+ // sequencing. Without resetting this list, potentially stale key codes |
+ // remain. The key codes themselves get pushed in |
+ // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. |
+ cvox.ChromeVox.sequenceSwitchKeyCodes = []; |
+ if (mode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) |
+ cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromDefaults(); |
+ else |
+ cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromNext(); |
+ |
+ if (mode == ChromeVoxMode.CLASSIC) { |
+ if (chrome.commands && |
+ chrome.commands.onCommand.hasListener(this.onGotCommand)) |
+ chrome.commands.onCommand.removeListener(this.onGotCommand); |
+ } else { |
+ if (chrome.commands && |
+ !chrome.commands.onCommand.hasListener(this.onGotCommand)) |
+ chrome.commands.onCommand.addListener(this.onGotCommand); |
+ } |
+ |
+ chrome.tabs.query({active: true}, function(tabs) { |
+ if (mode === ChromeVoxMode.CLASSIC) { |
+ // Generally, we don't want to inject classic content scripts as it is |
+ // done by the extension system at document load. The exception is when |
+ // we toggle classic on manually as part of a user command. |
+ if (opt_injectClassic) |
+ cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
+ } else { |
+ // When in compat mode, if the focus is within the desktop tree proper, |
+ // then do not disable content scripts. |
+ if (this.currentRange_ && |
+ this.currentRange_.start.node.root.role == RoleType.desktop) |
+ return; |
+ |
+ this.disableClassicChromeVox_(); |
+ } |
+ }.bind(this)); |
+ |
+ // If switching out of a ChromeVox Next mode, make sure we cancel |
+ // the progress loading sound just in case. |
+ if ((this.mode_ === ChromeVoxMode.NEXT || |
+ this.mode_ === ChromeVoxMode.FORCE_NEXT) && |
+ this.mode_ != mode) { |
+ cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
+ } |
+ |
+ this.mode_ = mode; |
+ }, |
+ |
+ /** |
+ * @override |
+ */ |
+ refreshMode: function(url) { |
+ var mode = this.mode_; |
+ if (mode != ChromeVoxMode.FORCE_NEXT) { |
+ if (this.isWhitelistedForNext_(url)) |
+ mode = ChromeVoxMode.NEXT; |
+ else if (this.isBlacklistedForClassic_(url)) |
+ mode = ChromeVoxMode.COMPAT; |
+ else |
+ mode = ChromeVoxMode.CLASSIC; |
+ } |
+ |
+ this.setMode(mode); |
+ }, |
+ |
+ /** |
+ * @override |
+ */ |
+ getCurrentRange: function() { |
return this.currentRange_; |
}, |
- set currentRange(value) { |
- if (!value) |
+ /** |
+ * @override |
+ */ |
+ setCurrentRange: function(newRange) { |
+ if (!newRange) |
return; |
- this.currentRange_ = value; |
+ this.currentRange_ = newRange; |
if (this.currentRange_) |
this.currentRange_.start.node.makeVisible(); |
}, |
+ /** Forces ChromeVox Next to be active for all tabs. */ |
+ forceChromeVoxNextActive: function() { |
+ this.setMode(ChromeVoxMode.FORCE_NEXT); |
+ }, |
+ |
/** |
* Handles ChromeVox Next commands. |
* @param {string} command |
@@ -331,8 +404,8 @@ Background.prototype = { |
.onSpeechEnd(function() { continueReading(prevRange); }) |
.go(); |
prevRange = this.currentRange_; |
- this.currentRange = |
- this.currentRange.move(cursors.Unit.NODE, Dir.FORWARD); |
+ this.setCurrentRange( |
+ this.currentRange_.move(cursors.Unit.NODE, Dir.FORWARD)); |
if (!this.currentRange_ || this.currentRange_.equals(prevRange)) |
global.isReadingContinuously = false; |
@@ -372,7 +445,7 @@ Background.prototype = { |
} else { |
newMode = ChromeVoxMode.FORCE_NEXT; |
} |
- this.setChromeVoxMode(newMode, true); |
+ this.setMode(newMode, true); |
var isClassic = |
newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; |
@@ -408,7 +481,7 @@ Background.prototype = { |
actionNode.focus(); |
var prevRange = this.currentRange_; |
- this.currentRange = current; |
+ this.setCurrentRange(current); |
new Output().withSpeechAndBraille( |
this.currentRange_, prevRange, Output.EventType.NAVIGATE) |
@@ -429,6 +502,8 @@ Background.prototype = { |
evt.preventDefault(); |
evt.stopPropagation(); |
} |
+ |
+ Output.flushNextSpeechUtterance(); |
}, |
/** |
@@ -481,67 +556,6 @@ Background.prototype = { |
}, |
/** |
- * Refreshes the current mode based on a url. |
- * @param {string} url |
- */ |
- refreshMode: function(url) { |
- var mode = this.mode_; |
- if (mode != ChromeVoxMode.FORCE_NEXT) { |
- if (this.isWhitelistedForNext_(url)) |
- mode = ChromeVoxMode.NEXT; |
- else if (this.isBlacklistedForClassic_(url)) |
- mode = ChromeVoxMode.COMPAT; |
- else |
- mode = ChromeVoxMode.CLASSIC; |
- } |
- |
- this.setChromeVoxMode(mode); |
- }, |
- |
- /** |
- * Called when the automation tree is changed. |
- * @param {chrome.automation.TreeChange} treeChange |
- */ |
- onTreeChange: function(treeChange) { |
- if (this.mode_ === ChromeVoxMode.CLASSIC || !cvox.ChromeVox.isActive) |
- return; |
- |
- var node = treeChange.target; |
- if (!node.containerLiveStatus) |
- return; |
- |
- if (node.containerLiveRelevant.indexOf('additions') >= 0 && |
- treeChange.type == 'nodeCreated') |
- this.outputLiveRegionChange_(node, null); |
- if (node.containerLiveRelevant.indexOf('text') >= 0 && |
- treeChange.type == 'nodeChanged') |
- this.outputLiveRegionChange_(node, null); |
- if (node.containerLiveRelevant.indexOf('removals') >= 0 && |
- treeChange.type == 'nodeRemoved') |
- this.outputLiveRegionChange_(node, '@live_regions_removed'); |
- }, |
- |
- /** |
- * Given a node that needs to be spoken as part of a live region |
- * change and an additional optional format string, output the |
- * live region description. |
- * @param {!chrome.automation.AutomationNode} node The changed node. |
- * @param {?string} opt_prependFormatStr If set, a format string for |
- * cvox2.Output to prepend to the output. |
- * @private |
- */ |
- outputLiveRegionChange_: function(node, opt_prependFormatStr) { |
- var range = cursors.Range.fromNode(node); |
- var output = new Output(); |
- if (opt_prependFormatStr) { |
- output.format(opt_prependFormatStr); |
- } |
- output.withSpeech(range, null, Output.EventType.NAVIGATE); |
- output.withSpeechCategory(cvox.TtsCategory.LIVE); |
- output.go(); |
- }, |
- |
- /** |
* Returns true if the url should have Classic running. |
* @return {boolean} |
* @private |
@@ -583,62 +597,6 @@ Background.prototype = { |
}, |
/** |
- * Sets the current ChromeVox mode. |
- * @param {ChromeVoxMode} mode |
- * @param {boolean=} opt_injectClassic Injects ChromeVox classic into tabs; |
- * defaults to false. |
- */ |
- setChromeVoxMode: function(mode, opt_injectClassic) { |
- // Switching key maps potentially affects the key codes that involve |
- // sequencing. Without resetting this list, potentially stale key codes |
- // remain. The key codes themselves get pushed in |
- // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. |
- cvox.ChromeVox.sequenceSwitchKeyCodes = []; |
- if (mode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) |
- cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromDefaults(); |
- else |
- cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromNext(); |
- |
- if (mode == ChromeVoxMode.CLASSIC) { |
- if (chrome.commands && |
- chrome.commands.onCommand.hasListener(this.onGotCommand)) |
- chrome.commands.onCommand.removeListener(this.onGotCommand); |
- } else { |
- if (chrome.commands && |
- !chrome.commands.onCommand.hasListener(this.onGotCommand)) |
- chrome.commands.onCommand.addListener(this.onGotCommand); |
- } |
- |
- chrome.tabs.query({active: true}, function(tabs) { |
- if (mode === ChromeVoxMode.CLASSIC) { |
- // Generally, we don't want to inject classic content scripts as it is |
- // done by the extension system at document load. The exception is when |
- // we toggle classic on manually as part of a user command. |
- if (opt_injectClassic) |
- cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
- } else { |
- // When in compat mode, if the focus is within the desktop tree proper, |
- // then do not disable content scripts. |
- if (this.currentRange_ && |
- this.currentRange_.start.node.root.role == RoleType.desktop) |
- return; |
- |
- this.disableClassicChromeVox_(); |
- } |
- }.bind(this)); |
- |
- // If switching out of a ChromeVox Next mode, make sure we cancel |
- // the progress loading sound just in case. |
- if ((this.mode_ === ChromeVoxMode.NEXT || |
- this.mode_ === ChromeVoxMode.FORCE_NEXT) && |
- this.mode_ != mode) { |
- cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
- } |
- |
- this.mode_ = mode; |
- }, |
- |
- /** |
* @param {!Spannable} text |
* @param {number} position |
* @private |