diff options
Diffstat (limited to 'chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js')
-rw-r--r-- | chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js | 248 |
1 files changed, 103 insertions, 145 deletions
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index 523e200..b7ba66a 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 |