| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview The entry point for all ChromeVox2 related code for the | 6 * @fileoverview The entry point for all ChromeVox2 related code for the |
| 7 * background page. | 7 * background page. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('Background'); | 10 goog.provide('Background'); |
| 11 goog.provide('global'); | |
| 12 | 11 |
| 13 goog.require('AutomationPredicate'); | 12 goog.require('AutomationPredicate'); |
| 14 goog.require('AutomationUtil'); | 13 goog.require('AutomationUtil'); |
| 15 goog.require('ChromeVoxState'); | 14 goog.require('ChromeVoxState'); |
| 16 goog.require('LiveRegions'); | 15 goog.require('LiveRegions'); |
| 17 goog.require('NextEarcons'); | 16 goog.require('NextEarcons'); |
| 18 goog.require('Notifications'); | 17 goog.require('Notifications'); |
| 19 goog.require('Output'); | 18 goog.require('Output'); |
| 20 goog.require('Output.EventType'); | 19 goog.require('Output.EventType'); |
| 21 goog.require('PanelCommand'); | 20 goog.require('PanelCommand'); |
| 22 goog.require('constants'); | 21 goog.require('constants'); |
| 23 goog.require('cursors.Cursor'); | 22 goog.require('cursors.Cursor'); |
| 24 goog.require('cvox.BrailleKeyCommand'); | 23 goog.require('cvox.BrailleKeyCommand'); |
| 24 goog.require('cvox.ChromeVoxBackground'); |
| 25 goog.require('cvox.ChromeVoxEditableTextBase'); | 25 goog.require('cvox.ChromeVoxEditableTextBase'); |
| 26 goog.require('cvox.ChromeVoxKbHandler'); | 26 goog.require('cvox.ChromeVoxKbHandler'); |
| 27 goog.require('cvox.ClassicEarcons'); | 27 goog.require('cvox.ClassicEarcons'); |
| 28 goog.require('cvox.ExtensionBridge'); | 28 goog.require('cvox.ExtensionBridge'); |
| 29 goog.require('cvox.NavBraille'); | 29 goog.require('cvox.NavBraille'); |
| 30 | 30 |
| 31 goog.scope(function() { | 31 goog.scope(function() { |
| 32 var AutomationNode = chrome.automation.AutomationNode; | 32 var AutomationNode = chrome.automation.AutomationNode; |
| 33 var Dir = constants.Dir; | 33 var Dir = constants.Dir; |
| 34 var EventType = chrome.automation.EventType; | 34 var EventType = chrome.automation.EventType; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 * @private | 71 * @private |
| 72 */ | 72 */ |
| 73 this.currentRange_ = null; | 73 this.currentRange_ = null; |
| 74 | 74 |
| 75 /** | 75 /** |
| 76 * @type {cursors.Range} | 76 * @type {cursors.Range} |
| 77 * @private | 77 * @private |
| 78 */ | 78 */ |
| 79 this.savedRange_ = null; | 79 this.savedRange_ = null; |
| 80 | 80 |
| 81 /** | |
| 82 * Which variant of ChromeVox is active. | |
| 83 * @type {ChromeVoxMode} | |
| 84 * @private | |
| 85 */ | |
| 86 this.mode_ = ChromeVoxMode.COMPAT; | |
| 87 | |
| 88 // Manually bind all functions to |this|. | 81 // Manually bind all functions to |this|. |
| 89 for (var func in this) { | 82 for (var func in this) { |
| 90 if (typeof(this[func]) == 'function') | 83 if (typeof(this[func]) == 'function') |
| 91 this[func] = this[func].bind(this); | 84 this[func] = this[func].bind(this); |
| 92 } | 85 } |
| 93 | 86 |
| 94 /** @type {!cvox.AbstractEarcons} @private */ | 87 /** @type {!cvox.AbstractEarcons} @private */ |
| 95 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); | 88 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); |
| 96 | 89 |
| 97 /** @type {!cvox.AbstractEarcons} @private */ | 90 /** @type {!cvox.AbstractEarcons} @private */ |
| 98 this.nextEarcons_ = new NextEarcons(); | 91 this.nextEarcons_ = new NextEarcons(); |
| 99 | 92 |
| 100 // Turn cvox.ChromeVox.earcons into a getter that returns either the | 93 // Turn cvox.ChromeVox.earcons into a getter that returns either the |
| 101 // Next earcons or the Classic earcons depending on the current mode. | 94 // Next earcons or the Classic earcons depending on the current mode. |
| 102 Object.defineProperty(cvox.ChromeVox, 'earcons', { | 95 Object.defineProperty(cvox.ChromeVox, 'earcons', { |
| 103 get: (function() { | 96 get: (function() { |
| 104 if (this.mode_ === ChromeVoxMode.FORCE_NEXT || | 97 if (this.mode === ChromeVoxMode.FORCE_NEXT || |
| 105 this.mode_ === ChromeVoxMode.NEXT) { | 98 this.mode === ChromeVoxMode.NEXT) { |
| 106 return this.nextEarcons_; | 99 return this.nextEarcons_; |
| 107 } else { | 100 } else { |
| 108 return this.classicEarcons_; | 101 return this.classicEarcons_; |
| 109 } | 102 } |
| 110 }).bind(this) | 103 }).bind(this) |
| 111 }); | 104 }); |
| 112 | 105 |
| 113 if (cvox.ChromeVox.isChromeOS) { | 106 if (cvox.ChromeVox.isChromeOS) { |
| 114 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { | 107 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { |
| 115 get: function() { | 108 get: function() { |
| 116 return (this.mode_ == ChromeVoxMode.CLASSIC || this.mode_ == | 109 return (this.mode == ChromeVoxMode.CLASSIC || this.mode == |
| 117 ChromeVoxMode.COMPAT) ? | 110 ChromeVoxMode.COMPAT) ? |
| 118 'Search+Shift' : 'Search'; | 111 'Search+Shift' : 'Search'; |
| 119 }.bind(this) | 112 }.bind(this) |
| 120 }); | 113 }); |
| 121 } | 114 } |
| 122 | 115 |
| 123 Object.defineProperty(cvox.ChromeVox, 'isActive', { | 116 Object.defineProperty(cvox.ChromeVox, 'isActive', { |
| 124 get: function() { | 117 get: function() { |
| 125 return localStorage['active'] !== 'false'; | 118 return localStorage['active'] !== 'false'; |
| 126 }, | 119 }, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 140 | 133 |
| 141 // Live region handler. | 134 // Live region handler. |
| 142 this.liveRegions_ = new LiveRegions(this); | 135 this.liveRegions_ = new LiveRegions(this); |
| 143 | 136 |
| 144 /** @type {number} @private */ | 137 /** @type {number} @private */ |
| 145 this.passThroughKeyUpCount_ = 0; | 138 this.passThroughKeyUpCount_ = 0; |
| 146 | 139 |
| 147 /** @type {boolean} @private */ | 140 /** @type {boolean} @private */ |
| 148 this.inExcursion_ = false; | 141 this.inExcursion_ = false; |
| 149 | 142 |
| 143 /** |
| 144 * Stores the mode as computed the last time a current range was set. |
| 145 * @type {?ChromeVoxMode} |
| 146 */ |
| 147 this.mode_ = null; |
| 148 |
| 150 if (!chrome.accessibilityPrivate.setKeyboardListener) | 149 if (!chrome.accessibilityPrivate.setKeyboardListener) |
| 151 chrome.accessibilityPrivate.setKeyboardListener = function() {}; | 150 chrome.accessibilityPrivate.setKeyboardListener = function() {}; |
| 152 | 151 |
| 153 if (cvox.ChromeVox.isChromeOS) { | 152 if (cvox.ChromeVox.isChromeOS) { |
| 154 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( | 153 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( |
| 155 this.onAccessibilityGesture_); | 154 this.onAccessibilityGesture_); |
| 156 | 155 |
| 157 Notifications.onStartup(); | 156 Notifications.onStartup(); |
| 158 }}; | 157 }}; |
| 159 | 158 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 'swipeDown2': 'readFromHere', | 196 'swipeDown2': 'readFromHere', |
| 198 }; | 197 }; |
| 199 | 198 |
| 200 Background.prototype = { | 199 Background.prototype = { |
| 201 __proto__: ChromeVoxState.prototype, | 200 __proto__: ChromeVoxState.prototype, |
| 202 | 201 |
| 203 /** | 202 /** |
| 204 * @override | 203 * @override |
| 205 */ | 204 */ |
| 206 getMode: function() { | 205 getMode: function() { |
| 207 return this.mode_; | 206 if (localStorage['useNext'] == 'true') |
| 207 return ChromeVoxMode.FORCE_NEXT; |
| 208 |
| 209 var target; |
| 210 if (!this.getCurrentRange()) { |
| 211 chrome.automation.getFocus(function(focus) { |
| 212 target = focus; |
| 213 }); |
| 214 } else { |
| 215 target = this.getCurrentRange().start.node; |
| 216 } |
| 217 |
| 218 if (!target) |
| 219 return ChromeVoxMode.CLASSIC; |
| 220 |
| 221 // Closure complains, but clearly, |target| is not null. |
| 222 var root = |
| 223 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); |
| 224 if (!root) |
| 225 return ChromeVoxMode.COMPAT; |
| 226 if (this.isWhitelistedForCompat_(root.docUrl)) |
| 227 return ChromeVoxMode.COMPAT; |
| 228 else if (this.isWhitelistedForNext_(root.docUrl)) |
| 229 return ChromeVoxMode.NEXT; |
| 230 else |
| 231 return ChromeVoxMode.CLASSIC; |
| 208 }, | 232 }, |
| 209 | 233 |
| 210 /** | 234 /** |
| 211 * @override | 235 * Handles a mode change. |
| 236 * @param {ChromeVoxMode} newMode |
| 237 * @param {?ChromeVoxMode} oldMode Can be null at startup when no range was |
| 238 * previously set. |
| 239 * @private |
| 212 */ | 240 */ |
| 213 setMode: function(mode, opt_injectClassic) { | 241 onModeChanged_: function(newMode, oldMode) { |
| 214 // Switching key maps potentially affects the key codes that involve | 242 // Switching key maps potentially affects the key codes that involve |
| 215 // sequencing. Without resetting this list, potentially stale key codes | 243 // sequencing. Without resetting this list, potentially stale key codes |
| 216 // remain. The key codes themselves get pushed in | 244 // remain. The key codes themselves get pushed in |
| 217 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. | 245 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. |
| 218 cvox.ChromeVox.sequenceSwitchKeyCodes = []; | 246 cvox.ChromeVox.sequenceSwitchKeyCodes = []; |
| 219 if (mode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) | |
| 220 window['prefs'].switchToKeyMap('keymap_classic'); | |
| 221 else | |
| 222 window['prefs'].switchToKeyMap('keymap_next'); | |
| 223 | 247 |
| 224 if (mode == ChromeVoxMode.CLASSIC) { | 248 var selectedKeyMap = |
| 249 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT ? |
| 250 'keymap_classic' : 'keymap_next'; |
| 251 window['prefs'].switchToKeyMap(selectedKeyMap); |
| 252 |
| 253 if (newMode == ChromeVoxMode.CLASSIC) { |
| 225 if (chrome.commands && | 254 if (chrome.commands && |
| 226 chrome.commands.onCommand.hasListener(this.onGotCommand)) | 255 chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 227 chrome.commands.onCommand.removeListener(this.onGotCommand); | 256 chrome.commands.onCommand.removeListener(this.onGotCommand); |
| 228 chrome.accessibilityPrivate.setKeyboardListener(false, false); | 257 chrome.accessibilityPrivate.setKeyboardListener(false, false); |
| 258 |
| 259 if (cvox.ChromeVox.isChromeOS) |
| 260 chrome.accessibilityPrivate.setFocusRing([]); |
| 229 } else { | 261 } else { |
| 230 if (chrome.commands && | 262 if (chrome.commands && |
| 231 !chrome.commands.onCommand.hasListener(this.onGotCommand)) | 263 !chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 232 chrome.commands.onCommand.addListener(this.onGotCommand); | 264 chrome.commands.onCommand.addListener(this.onGotCommand); |
| 233 chrome.accessibilityPrivate.setKeyboardListener( | 265 chrome.accessibilityPrivate.setKeyboardListener( |
| 234 true, cvox.ChromeVox.isStickyPrefOn); | 266 true, cvox.ChromeVox.isStickyPrefOn); |
| 235 } | 267 } |
| 236 | 268 |
| 237 // note that |this.currentRange_| can *change* because the request is | 269 // note that |this.currentRange_| can *change* because the request is |
| 238 // async. Save it to ensure we're looking at the currentRange at this moment | 270 // async. Save it to ensure we're looking at the currentRange at this moment |
| 239 // in time. | 271 // in time. |
| 240 var cur = this.currentRange_; | 272 var cur = this.currentRange_; |
| 241 chrome.tabs.query({active: true, | 273 chrome.tabs.query({active: true, |
| 242 lastFocusedWindow: true}, function(tabs) { | 274 lastFocusedWindow: true}, function(tabs) { |
| 243 if (mode === ChromeVoxMode.CLASSIC) { | 275 if (newMode === ChromeVoxMode.CLASSIC) { |
| 244 // Generally, we don't want to inject classic content scripts as it is | 276 // Generally, we don't want to inject classic content scripts as it is |
| 245 // done by the extension system at document load. The exception is when | 277 // done by the extension system at document load. The exception is when |
| 246 // we toggle classic on manually as part of a user command. | 278 // we toggle classic on manually as part of a user command. |
| 247 if (opt_injectClassic) | 279 if (oldMode == ChromeVoxMode.FORCE_NEXT) |
| 248 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); | 280 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
| 249 } else if (mode === ChromeVoxMode.FORCE_NEXT) { | 281 } else if (newMode === ChromeVoxMode.FORCE_NEXT) { |
| 250 // Disable ChromeVox everywhere. | 282 // Disable ChromeVox everywhere. |
| 251 this.disableClassicChromeVox_(); | 283 this.disableClassicChromeVox_(); |
| 252 } else { | 284 } else { |
| 253 // If we're focused in the desktop tree, do nothing. | 285 // If we're focused in the desktop tree, do nothing. |
| 254 if (cur && !cur.isWebRange()) | 286 if (cur && !cur.isWebRange()) |
| 255 return; | 287 return; |
| 256 | 288 |
| 257 // If we're entering compat mode or next mode for just one tab, | 289 // If we're entering compat mode or next mode for just one tab, |
| 258 // disable Classic for that tab only. | 290 // disable Classic for that tab only. |
| 259 this.disableClassicChromeVox_(tabs); | 291 this.disableClassicChromeVox_(tabs); |
| 260 } | 292 } |
| 261 }.bind(this)); | 293 }.bind(this)); |
| 262 | 294 |
| 263 // If switching out of a ChromeVox Next mode, make sure we cancel | 295 // If switching out of a ChromeVox Next mode, make sure we cancel |
| 264 // the progress loading sound just in case. | 296 // the progress loading sound just in case. |
| 265 if ((this.mode_ === ChromeVoxMode.NEXT || | 297 if (oldMode === ChromeVoxMode.NEXT || |
| 266 this.mode_ === ChromeVoxMode.FORCE_NEXT) && | 298 oldMode === ChromeVoxMode.FORCE_NEXT) |
| 267 this.mode_ != mode) { | |
| 268 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); | 299 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
| 269 } | |
| 270 | 300 |
| 271 if (mode === ChromeVoxMode.NEXT || | 301 if (newMode === ChromeVoxMode.NEXT || |
| 272 mode === ChromeVoxMode.FORCE_NEXT) { | 302 newMode === ChromeVoxMode.FORCE_NEXT) { |
| 273 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); | 303 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); |
| 274 if (cvox.TabsApiHandler) | 304 if (cvox.TabsApiHandler) |
| 275 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; | 305 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; |
| 276 } else { | 306 } else { |
| 277 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); | 307 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); |
| 278 if (cvox.TabsApiHandler) | 308 if (cvox.TabsApiHandler) |
| 279 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; | 309 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; |
| 280 } | 310 } |
| 281 | |
| 282 // If switching to Classic from any automation-API-based mode, | |
| 283 // clear the focus ring. | |
| 284 if (mode === ChromeVoxMode.CLASSIC && mode != this.mode_) { | |
| 285 if (cvox.ChromeVox.isChromeOS) | |
| 286 chrome.accessibilityPrivate.setFocusRing([]); | |
| 287 } | |
| 288 | |
| 289 // If switching away from Classic to any automation-API-based mode, | |
| 290 // update the range based on what's focused. | |
| 291 if (this.mode_ === ChromeVoxMode.CLASSIC && mode != this.mode_) { | |
| 292 chrome.automation.getFocus((function(focus) { | |
| 293 if (focus) | |
| 294 this.setCurrentRange(cursors.Range.fromNode(focus)); | |
| 295 }).bind(this)); | |
| 296 } | |
| 297 | |
| 298 this.mode_ = mode; | |
| 299 }, | 311 }, |
| 300 | 312 |
| 301 /** | 313 /** |
| 302 * Mode refreshes takes into account both |url| and the current ChromeVox | 314 * Toggles between force next and classic/compat modes. |
| 303 * range. The latter gets used to decide if the user is or isn't in web | 315 * This toggle automatically handles deciding between classic/compat based on |
| 304 * content. The focused state also needs to be set for this info to be | 316 * the start of the current range. |
| 305 * reliable. | 317 * @param {boolean=} opt_setValue Directly set to force next (true) or |
| 306 * @override | 318 * classic/compat (false). |
| 319 * @return {boolean} True to announce current position. |
| 307 */ | 320 */ |
| 308 refreshMode: function(node) { | 321 toggleNext: function(opt_setValue) { |
| 309 // Mode changes are based upon the top level web root. | 322 var useNext; |
| 310 var root = node.root; | 323 if (opt_setValue !== undefined) |
| 311 while (root && | 324 useNext = opt_setValue; |
| 312 root.parent && | 325 else |
| 313 root.parent.root && | 326 useNext = localStorage['useNext'] != 'true'; |
| 314 root.parent.root.role != RoleType.desktop) { | |
| 315 root = root.parent.root; | |
| 316 } | |
| 317 | 327 |
| 318 var url = ''; | 328 localStorage['useNext'] = useNext; |
| 319 if (root && root.role == RoleType.rootWebArea) | 329 if (useNext) |
| 320 url = root.docUrl; | 330 this.setCurrentRangeToFocus_(); |
| 331 else |
| 332 this.setCurrentRange(null); |
| 321 | 333 |
| 322 var mode = this.mode_; | 334 var announce = Msgs.getMsg(useNext ? |
| 323 if (mode != ChromeVoxMode.FORCE_NEXT) { | 335 'switch_to_next' : 'switch_to_classic'); |
| 324 if (this.isWhitelistedForNext_(url)) { | 336 cvox.ChromeVox.tts.speak( |
| 325 mode = ChromeVoxMode.NEXT; | 337 announce, cvox.QueueMode.FLUSH, {doNotInterrupt: true}); |
| 326 } else if (this.isBlacklistedForClassic_(url) || (this.currentRange_ && | 338 Notifications.onModeChange(); |
| 327 !this.currentRange_.isWebRange() && | |
| 328 this.currentRange_.start.node.state.focused)) { | |
| 329 mode = ChromeVoxMode.COMPAT; | |
| 330 } else { | |
| 331 mode = ChromeVoxMode.CLASSIC; | |
| 332 } | |
| 333 } | |
| 334 | 339 |
| 335 this.setMode(mode); | 340 // If the new mode is Classic, return false now so we don't announce |
| 341 // anything more. |
| 342 return useNext; |
| 336 }, | 343 }, |
| 337 | 344 |
| 338 /** | 345 /** |
| 339 * @override | 346 * @override |
| 340 */ | 347 */ |
| 341 getCurrentRange: function() { | 348 getCurrentRange: function() { |
| 342 if (this.currentRange_ && this.currentRange_.isValid()) | 349 if (this.currentRange_ && this.currentRange_.isValid()) |
| 343 return this.currentRange_; | 350 return this.currentRange_; |
| 344 return null; | 351 return null; |
| 345 }, | 352 }, |
| 346 | 353 |
| 347 /** | 354 /** |
| 348 * @override | 355 * @override |
| 349 */ | 356 */ |
| 350 setCurrentRange: function(newRange) { | 357 setCurrentRange: function(newRange) { |
| 351 if (!newRange) | 358 if (!this.inExcursion_ && newRange) |
| 352 return; | |
| 353 | |
| 354 // Is the range invalid? | |
| 355 if (newRange.start.node.role === undefined || | |
| 356 newRange.end.node.role === undefined) { | |
| 357 // Restore range to the focused location. | |
| 358 chrome.automation.getFocus(function(f) { | |
| 359 newRange = cursors.Range.fromNode(f); | |
| 360 }); | |
| 361 } | |
| 362 | |
| 363 if (!this.inExcursion_) | |
| 364 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); | 359 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); |
| 365 | 360 |
| 366 this.currentRange_ = newRange; | 361 this.currentRange_ = newRange; |
| 362 var oldMode = this.mode_; |
| 363 var newMode = this.getMode(); |
| 364 if (oldMode != newMode) { |
| 365 this.onModeChanged_(newMode, oldMode); |
| 366 this.mode_ = newMode; |
| 367 } |
| 367 | 368 |
| 368 if (this.currentRange_) { | 369 if (this.currentRange_) { |
| 369 var start = this.currentRange_.start.node; | 370 var start = this.currentRange_.start.node; |
| 370 start.makeVisible(); | 371 start.makeVisible(); |
| 371 | 372 |
| 372 var root = start.root; | 373 var root = start.root; |
| 373 | |
| 374 if (!root || root.role == RoleType.desktop) | 374 if (!root || root.role == RoleType.desktop) |
| 375 return; | 375 return; |
| 376 | 376 |
| 377 var position = {}; | 377 var position = {}; |
| 378 var loc = start.location; | 378 var loc = start.location; |
| 379 position.x = loc.left + loc.width / 2; | 379 position.x = loc.left + loc.width / 2; |
| 380 position.y = loc.top + loc.height / 2; | 380 position.y = loc.top + loc.height / 2; |
| 381 var url = root.docUrl; | 381 var url = root.docUrl; |
| 382 url = url.substring(0, url.indexOf('#')) || url; | 382 url = url.substring(0, url.indexOf('#')) || url; |
| 383 cvox.ChromeVox.position[url] = position; | 383 cvox.ChromeVox.position[url] = position; |
| 384 } | 384 } |
| 385 }, | 385 }, |
| 386 | 386 |
| 387 /** Forces ChromeVox Next to be active for all tabs. */ | |
| 388 forceChromeVoxNextActive: function() { | |
| 389 this.setMode(ChromeVoxMode.FORCE_NEXT); | |
| 390 }, | |
| 391 | |
| 392 /** | 387 /** |
| 393 * Handles ChromeVox Next commands. | 388 * Handles ChromeVox Next commands. |
| 394 * @param {string} command | 389 * @param {string} command |
| 395 * @param {boolean=} opt_bypassModeCheck Always tries to execute the command | |
| 396 * regardless of mode. | |
| 397 * @return {boolean} True if the command should propagate. | 390 * @return {boolean} True if the command should propagate. |
| 398 */ | 391 */ |
| 399 onGotCommand: function(command, opt_bypassModeCheck) { | 392 onGotCommand: function(command) { |
| 400 // Check for loss of focus which results in us invalidating our current | 393 // Check for loss of focus which results in us invalidating our current |
| 401 // range. Note this call is synchronis. | 394 // range. Note this call is synchronis. |
| 402 chrome.automation.getFocus(function(focusedNode) { | 395 chrome.automation.getFocus(function(focusedNode) { |
| 403 if (this.currentRange_ && !this.currentRange_.isValid()) | 396 if (this.currentRange_ && !this.currentRange_.isValid()) |
| 404 this.currentRange_ = cursors.Range.fromNode(focusedNode); | 397 this.currentRange_ = cursors.Range.fromNode(focusedNode); |
| 405 if (!focusedNode) | 398 if (!focusedNode) |
| 406 this.currentRange_ = null; | 399 this.currentRange_ = null; |
| 407 }.bind(this)); | 400 }.bind(this)); |
| 408 | 401 |
| 402 // These commands don't require a current range and work in all modes. |
| 403 switch (command) { |
| 404 case 'toggleChromeVoxVersion': |
| 405 if (!this.toggleNext()) |
| 406 return false; |
| 407 if (this.currentRange_) |
| 408 this.navigateToRange(this.currentRange_); |
| 409 break; |
| 410 case 'showNextUpdatePage': |
| 411 var nextUpdatePage = {url: 'cvox2/background/next_update.html'}; |
| 412 chrome.tabs.create(nextUpdatePage); |
| 413 return false; |
| 414 default: |
| 415 break; |
| 416 } |
| 417 |
| 418 // Require a current range. |
| 409 if (!this.currentRange_) | 419 if (!this.currentRange_) |
| 410 return true; | 420 return true; |
| 411 | 421 |
| 412 if (this.mode_ == ChromeVoxMode.CLASSIC && !opt_bypassModeCheck) | 422 // Next/compat commands hereafter. |
| 423 if (this.mode == ChromeVoxMode.CLASSIC) |
| 413 return true; | 424 return true; |
| 414 | 425 |
| 415 var current = this.currentRange_; | 426 var current = this.currentRange_; |
| 416 var dir = Dir.FORWARD; | 427 var dir = Dir.FORWARD; |
| 417 var pred = null; | 428 var pred = null; |
| 418 var predErrorMsg = undefined; | 429 var predErrorMsg = undefined; |
| 419 var speechProps = {}; | 430 var speechProps = {}; |
| 420 switch (command) { | 431 switch (command) { |
| 421 case 'nextCharacter': | 432 case 'nextCharacter': |
| 422 speechProps['phoneticCharacters'] = true; | 433 speechProps['phoneticCharacters'] = true; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 if (this.currentRange_) { | 569 if (this.currentRange_) { |
| 559 var actionNode = this.currentRange_.start.node; | 570 var actionNode = this.currentRange_.start.node; |
| 560 if (actionNode.role == RoleType.inlineTextBox) | 571 if (actionNode.role == RoleType.inlineTextBox) |
| 561 actionNode = actionNode.parent; | 572 actionNode = actionNode.parent; |
| 562 actionNode.doDefault(); | 573 actionNode.doDefault(); |
| 563 } | 574 } |
| 564 // Skip all other processing; if focus changes, we should get an event | 575 // Skip all other processing; if focus changes, we should get an event |
| 565 // for that. | 576 // for that. |
| 566 return false; | 577 return false; |
| 567 case 'readFromHere': | 578 case 'readFromHere': |
| 568 global.isReadingContinuously = true; | 579 ChromeVoxState.isReadingContinuously = true; |
| 569 var continueReading = function() { | 580 var continueReading = function() { |
| 570 if (!global.isReadingContinuously || !this.currentRange_) | 581 if (!ChromeVoxState.isReadingContinuously || !this.currentRange_) |
| 571 return; | 582 return; |
| 572 | 583 |
| 573 var prevRange = this.currentRange_; | 584 var prevRange = this.currentRange_; |
| 574 var newRange = | 585 var newRange = |
| 575 this.currentRange_.move(cursors.Unit.DOM_NODE, Dir.FORWARD); | 586 this.currentRange_.move(cursors.Unit.DOM_NODE, Dir.FORWARD); |
| 576 | 587 |
| 577 // Stop if we've wrapped back to the document. | 588 // Stop if we've wrapped back to the document. |
| 578 var maybeDoc = newRange.start.node; | 589 var maybeDoc = newRange.start.node; |
| 579 if (maybeDoc.role == RoleType.rootWebArea && | 590 if (maybeDoc.role == RoleType.rootWebArea && |
| 580 maybeDoc.parent.root.role == RoleType.desktop) { | 591 maybeDoc.parent.root.role == RoleType.desktop) { |
| 581 global.isReadingContinuously = false; | 592 ChromeVoxState.isReadingContinuously = false; |
| 582 return; | 593 return; |
| 583 } | 594 } |
| 584 | 595 |
| 585 this.setCurrentRange(newRange); | 596 this.setCurrentRange(newRange); |
| 586 | 597 |
| 587 new Output().withRichSpeechAndBraille( | 598 new Output().withRichSpeechAndBraille( |
| 588 this.currentRange_, prevRange, Output.EventType.NAVIGATE) | 599 this.currentRange_, prevRange, Output.EventType.NAVIGATE) |
| 589 .onSpeechEnd(continueReading) | 600 .onSpeechEnd(continueReading) |
| 590 .go(); | 601 .go(); |
| 591 }.bind(this); | 602 }.bind(this); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 612 if (cvox.ChromeVox.isChromeOS) | 623 if (cvox.ChromeVox.isChromeOS) |
| 613 return false; | 624 return false; |
| 614 | 625 |
| 615 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; | 626 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; |
| 616 if (!cvox.ChromeVox.isActive) { | 627 if (!cvox.ChromeVox.isActive) { |
| 617 var msg = Msgs.getMsg('chromevox_inactive'); | 628 var msg = Msgs.getMsg('chromevox_inactive'); |
| 618 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); | 629 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); |
| 619 return false; | 630 return false; |
| 620 } | 631 } |
| 621 break; | 632 break; |
| 622 case 'toggleChromeVoxVersion': | |
| 623 var newMode; | |
| 624 if (this.mode_ == ChromeVoxMode.FORCE_NEXT) { | |
| 625 var inWeb = current.isWebRange(); | |
| 626 newMode = inWeb ? ChromeVoxMode.CLASSIC : ChromeVoxMode.COMPAT; | |
| 627 } else { | |
| 628 newMode = ChromeVoxMode.FORCE_NEXT; | |
| 629 } | |
| 630 this.setMode(newMode, true); | |
| 631 | |
| 632 var isClassic = | |
| 633 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; | |
| 634 | |
| 635 // Leaving unlocalized as 'next' isn't an official name. | |
| 636 cvox.ChromeVox.tts.speak(isClassic ? | |
| 637 'classic' : 'next', cvox.QueueMode.FLUSH, {doNotInterrupt: true}); | |
| 638 | |
| 639 // If the new mode is Classic, return now so we don't announce | |
| 640 // anything more. | |
| 641 if (newMode == ChromeVoxMode.CLASSIC) | |
| 642 return false; | |
| 643 break; | |
| 644 case 'toggleStickyMode': | 633 case 'toggleStickyMode': |
| 645 cvox.ChromeVoxBackground.setPref('sticky', | 634 cvox.ChromeVoxBackground.setPref('sticky', |
| 646 !cvox.ChromeVox.isStickyPrefOn, | 635 !cvox.ChromeVox.isStickyPrefOn, |
| 647 true); | 636 true); |
| 648 | 637 |
| 649 if (cvox.ChromeVox.isStickyPrefOn) | 638 if (cvox.ChromeVox.isStickyPrefOn) |
| 650 chrome.accessibilityPrivate.setKeyboardListener(true, true); | 639 chrome.accessibilityPrivate.setKeyboardListener(true, true); |
| 651 else | 640 else |
| 652 chrome.accessibilityPrivate.setKeyboardListener(true, false); | 641 chrome.accessibilityPrivate.setKeyboardListener(true, false); |
| 653 return false; | 642 return false; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 681 (new PanelCommand(PanelCommandType.OPEN_MENUS, 'table_strategy')) | 670 (new PanelCommand(PanelCommandType.OPEN_MENUS, 'table_strategy')) |
| 682 .send(); | 671 .send(); |
| 683 return false; | 672 return false; |
| 684 case 'toggleSearchWidget': | 673 case 'toggleSearchWidget': |
| 685 (new PanelCommand(PanelCommandType.SEARCH)).send(); | 674 (new PanelCommand(PanelCommandType.SEARCH)).send(); |
| 686 return false; | 675 return false; |
| 687 case 'showKbExplorerPage': | 676 case 'showKbExplorerPage': |
| 688 var explorerPage = {url: 'chromevox/background/kbexplorer.html'}; | 677 var explorerPage = {url: 'chromevox/background/kbexplorer.html'}; |
| 689 chrome.tabs.create(explorerPage); | 678 chrome.tabs.create(explorerPage); |
| 690 break; | 679 break; |
| 691 case 'showNextUpdatePage': | |
| 692 var nextUpdatePage = {url: 'cvox2/background/next_update.html'}; | |
| 693 chrome.tabs.create(nextUpdatePage); | |
| 694 break; | |
| 695 case 'decreaseTtsRate': | 680 case 'decreaseTtsRate': |
| 696 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, false); | 681 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, false); |
| 697 return false; | 682 return false; |
| 698 case 'increaseTtsRate': | 683 case 'increaseTtsRate': |
| 699 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, true); | 684 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, true); |
| 700 return false; | 685 return false; |
| 701 case 'decreaseTtsPitch': | 686 case 'decreaseTtsPitch': |
| 702 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, false); | 687 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, false); |
| 703 return false; | 688 return false; |
| 704 case 'increaseTtsPitch': | 689 case 'increaseTtsPitch': |
| 705 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, true); | 690 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, true); |
| 706 return false; | 691 return false; |
| 707 case 'decreaseTtsVolume': | 692 case 'decreaseTtsVolume': |
| 708 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, false); | 693 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, false); |
| 709 return false; | 694 return false; |
| 710 case 'increaseTtsVolume': | 695 case 'increaseTtsVolume': |
| 711 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, true); | 696 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, true); |
| 712 return false; | 697 return false; |
| 713 case 'stopSpeech': | 698 case 'stopSpeech': |
| 714 cvox.ChromeVox.tts.stop(); | 699 cvox.ChromeVox.tts.stop(); |
| 715 global.isReadingContinuously = false; | 700 ChromeVoxState.isReadingContinuously = false; |
| 716 return false; | 701 return false; |
| 717 case 'toggleEarcons': | 702 case 'toggleEarcons': |
| 718 cvox.AbstractEarcons.enabled = !cvox.AbstractEarcons.enabled; | 703 cvox.AbstractEarcons.enabled = !cvox.AbstractEarcons.enabled; |
| 719 var announce = cvox.AbstractEarcons.enabled ? | 704 var announce = cvox.AbstractEarcons.enabled ? |
| 720 Msgs.getMsg('earcons_on') : | 705 Msgs.getMsg('earcons_on') : |
| 721 Msgs.getMsg('earcons_off'); | 706 Msgs.getMsg('earcons_off'); |
| 722 cvox.ChromeVox.tts.speak( | 707 cvox.ChromeVox.tts.speak( |
| 723 announce, cvox.QueueMode.FLUSH, | 708 announce, cvox.QueueMode.FLUSH, |
| 724 cvox.AbstractTts.PERSONALITY_ANNOTATION); | 709 cvox.AbstractTts.PERSONALITY_ANNOTATION); |
| 725 return false; | 710 return false; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 740 case cvox.TypingEcho.NONE: | 725 case cvox.TypingEcho.NONE: |
| 741 announce = Msgs.getMsg('none_echo'); | 726 announce = Msgs.getMsg('none_echo'); |
| 742 break; | 727 break; |
| 743 } | 728 } |
| 744 cvox.ChromeVox.tts.speak( | 729 cvox.ChromeVox.tts.speak( |
| 745 announce, cvox.QueueMode.FLUSH, | 730 announce, cvox.QueueMode.FLUSH, |
| 746 cvox.AbstractTts.PERSONALITY_ANNOTATION); | 731 cvox.AbstractTts.PERSONALITY_ANNOTATION); |
| 747 return false; | 732 return false; |
| 748 case 'cyclePunctuationEcho': | 733 case 'cyclePunctuationEcho': |
| 749 cvox.ChromeVox.tts.speak(Msgs.getMsg( | 734 cvox.ChromeVox.tts.speak(Msgs.getMsg( |
| 750 global.backgroundTts.cyclePunctuationEcho()), | 735 ChromeVoxState.backgroundTts.cyclePunctuationEcho()), |
| 751 cvox.QueueMode.FLUSH); | 736 cvox.QueueMode.FLUSH); |
| 752 return false; | 737 return false; |
| 753 case 'speakTimeAndDate': | 738 case 'speakTimeAndDate': |
| 754 chrome.automation.getDesktop(function(d) { | 739 chrome.automation.getDesktop(function(d) { |
| 755 // First, try speaking the on-screen time. | 740 // First, try speaking the on-screen time. |
| 756 var allTime = d.findAll({role: RoleType.time}); | 741 var allTime = d.findAll({role: RoleType.time}); |
| 757 allTime.filter(function(t) { | 742 allTime.filter(function(t) { |
| 758 return t.root.role == RoleType.desktop; | 743 return t.root.role == RoleType.desktop; |
| 759 }); | 744 }); |
| 760 | 745 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 output.go(); | 778 output.go(); |
| 794 return false; | 779 return false; |
| 795 case 'readCurrentURL': | 780 case 'readCurrentURL': |
| 796 var output = new Output(); | 781 var output = new Output(); |
| 797 var target = this.currentRange_.start.node.root; | 782 var target = this.currentRange_.start.node.root; |
| 798 output.withString(target.docUrl || '').go(); | 783 output.withString(target.docUrl || '').go(); |
| 799 return false; | 784 return false; |
| 800 case 'reportIssue': | 785 case 'reportIssue': |
| 801 var url = Background.ISSUE_URL; | 786 var url = Background.ISSUE_URL; |
| 802 var description = {}; | 787 var description = {}; |
| 803 description['Mode'] = this.mode_; | 788 description['Mode'] = this.mode; |
| 804 description['Version'] = chrome.app.getDetails().version; | 789 description['Version'] = chrome.app.getDetails().version; |
| 805 description['Reproduction Steps'] = '%0a1.%0a2.%0a3.'; | 790 description['Reproduction Steps'] = '%0a1.%0a2.%0a3.'; |
| 806 for (var key in description) | 791 for (var key in description) |
| 807 url += key + ':%20' + description[key] + '%0a'; | 792 url += key + ':%20' + description[key] + '%0a'; |
| 808 chrome.tabs.create({url: url}); | 793 chrome.tabs.create({url: url}); |
| 809 return false; | 794 return false; |
| 810 case 'toggleBrailleCaptions': | 795 case 'toggleBrailleCaptions': |
| 811 cvox.BrailleCaptionsBackground.setActive( | 796 cvox.BrailleCaptionsBackground.setActive( |
| 812 !cvox.BrailleCaptionsBackground.isEnabled()); | 797 !cvox.BrailleCaptionsBackground.isEnabled()); |
| 813 return false; | 798 return false; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 /** | 899 /** |
| 915 * Handles key down events. | 900 * Handles key down events. |
| 916 * @param {Event} evt The key down event to process. | 901 * @param {Event} evt The key down event to process. |
| 917 * @return {boolean} True if the default action should be performed. | 902 * @return {boolean} True if the default action should be performed. |
| 918 */ | 903 */ |
| 919 onKeyDown: function(evt) { | 904 onKeyDown: function(evt) { |
| 920 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; | 905 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; |
| 921 if (cvox.ChromeVox.passThroughMode) | 906 if (cvox.ChromeVox.passThroughMode) |
| 922 return false; | 907 return false; |
| 923 | 908 |
| 924 if (this.mode_ != ChromeVoxMode.CLASSIC && | 909 if (this.mode != ChromeVoxMode.CLASSIC && |
| 925 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { | 910 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { |
| 926 evt.preventDefault(); | 911 evt.preventDefault(); |
| 927 evt.stopPropagation(); | 912 evt.stopPropagation(); |
| 928 } | 913 } |
| 929 Output.flushNextSpeechUtterance(); | 914 Output.flushNextSpeechUtterance(); |
| 930 return false; | 915 return false; |
| 931 }, | 916 }, |
| 932 | 917 |
| 933 /** | 918 /** |
| 934 * Handles key up events. | 919 * Handles key up events. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 957 chrome.tabs.create(optionsPage); | 942 chrome.tabs.create(optionsPage); |
| 958 }, | 943 }, |
| 959 | 944 |
| 960 /** | 945 /** |
| 961 * Handles a braille command. | 946 * Handles a braille command. |
| 962 * @param {!cvox.BrailleKeyEvent} evt | 947 * @param {!cvox.BrailleKeyEvent} evt |
| 963 * @param {!cvox.NavBraille} content | 948 * @param {!cvox.NavBraille} content |
| 964 * @return {boolean} True if evt was processed. | 949 * @return {boolean} True if evt was processed. |
| 965 */ | 950 */ |
| 966 onBrailleKeyEvent: function(evt, content) { | 951 onBrailleKeyEvent: function(evt, content) { |
| 967 if (this.mode_ === ChromeVoxMode.CLASSIC) | 952 if (this.mode === ChromeVoxMode.CLASSIC) |
| 968 return false; | 953 return false; |
| 969 | 954 |
| 970 switch (evt.command) { | 955 switch (evt.command) { |
| 971 case cvox.BrailleKeyCommand.PAN_LEFT: | 956 case cvox.BrailleKeyCommand.PAN_LEFT: |
| 972 this.onGotCommand('previousObject'); | 957 this.onGotCommand('previousObject'); |
| 973 break; | 958 break; |
| 974 case cvox.BrailleKeyCommand.PAN_RIGHT: | 959 case cvox.BrailleKeyCommand.PAN_RIGHT: |
| 975 this.onGotCommand('nextObject'); | 960 this.onGotCommand('nextObject'); |
| 976 break; | 961 break; |
| 977 case cvox.BrailleKeyCommand.LINE_UP: | 962 case cvox.BrailleKeyCommand.LINE_UP: |
| (...skipping 19 matching lines...) Expand all Loading... |
| 997 } | 982 } |
| 998 return true; | 983 return true; |
| 999 }, | 984 }, |
| 1000 | 985 |
| 1001 /** | 986 /** |
| 1002 * Returns true if the url should have Classic running. | 987 * Returns true if the url should have Classic running. |
| 1003 * @return {boolean} | 988 * @return {boolean} |
| 1004 * @private | 989 * @private |
| 1005 */ | 990 */ |
| 1006 shouldEnableClassicForUrl_: function(url) { | 991 shouldEnableClassicForUrl_: function(url) { |
| 1007 return this.mode_ != ChromeVoxMode.FORCE_NEXT && | 992 return this.mode != ChromeVoxMode.FORCE_NEXT && |
| 1008 !this.isBlacklistedForClassic_(url) && | 993 !this.isBlacklistedForClassic_(url) && |
| 1009 !this.isWhitelistedForNext_(url); | 994 !this.isWhitelistedForNext_(url); |
| 1010 }, | 995 }, |
| 1011 | 996 |
| 1012 /** | 997 /** |
| 998 * Compat mode is on if any of the following are true: |
| 999 * 1. a url is blacklisted for Classic. |
| 1000 * 2. the current range is not within web content. |
| 1001 * @param {string} url |
| 1002 */ |
| 1003 isWhitelistedForCompat_: function(url) { |
| 1004 return this.isBlacklistedForClassic_(url) || (this.getCurrentRange() && |
| 1005 !this.getCurrentRange().isWebRange() && |
| 1006 this.getCurrentRange().start.node.state.focused); |
| 1007 }, |
| 1008 |
| 1009 /** |
| 1013 * @param {string} url | 1010 * @param {string} url |
| 1014 * @return {boolean} | 1011 * @return {boolean} |
| 1015 * @private | 1012 * @private |
| 1016 */ | 1013 */ |
| 1017 isBlacklistedForClassic_: function(url) { | 1014 isBlacklistedForClassic_: function(url) { |
| 1018 if (this.classicBlacklistRegExp_.test(url)) | 1015 if (this.classicBlacklistRegExp_.test(url)) |
| 1019 return true; | 1016 return true; |
| 1020 url = url.substring(0, url.indexOf('#')) || url; | 1017 url = url.substring(0, url.indexOf('#')) || url; |
| 1021 return this.classicBlacklist_.has(url); | 1018 return this.classicBlacklist_.has(url); |
| 1022 }, | 1019 }, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 var url = msg['url']; | 1095 var url = msg['url']; |
| 1099 var isClassicEnabled = this.shouldEnableClassicForUrl_(url); | 1096 var isClassicEnabled = this.shouldEnableClassicForUrl_(url); |
| 1100 port.postMessage({ | 1097 port.postMessage({ |
| 1101 target: 'next', | 1098 target: 'next', |
| 1102 isClassicEnabled: isClassicEnabled | 1099 isClassicEnabled: isClassicEnabled |
| 1103 }); | 1100 }); |
| 1104 } else if (action == 'enableCompatForUrl') { | 1101 } else if (action == 'enableCompatForUrl') { |
| 1105 var url = msg['url']; | 1102 var url = msg['url']; |
| 1106 this.classicBlacklist_.add(url); | 1103 this.classicBlacklist_.add(url); |
| 1107 if (this.currentRange_ && this.currentRange_.start.node) | 1104 if (this.currentRange_ && this.currentRange_.start.node) |
| 1108 this.refreshMode(this.currentRange_.start.node); | 1105 this.setCurrentRange(this.currentRange_); |
| 1109 } else if (action == 'onCommand') { | 1106 } else if (action == 'onCommand') { |
| 1110 this.onGotCommand(msg['command']); | 1107 this.onGotCommand(msg['command']); |
| 1111 } else if (action == 'flushNextUtterance') { | 1108 } else if (action == 'flushNextUtterance') { |
| 1112 Output.flushNextSpeechUtterance(); | 1109 Output.flushNextSpeechUtterance(); |
| 1113 } | 1110 } |
| 1114 break; | 1111 break; |
| 1115 } | 1112 } |
| 1116 }, | 1113 }, |
| 1117 | 1114 |
| 1118 /** | 1115 /** |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1174 /** | 1171 /** |
| 1175 * Handles accessibility gestures from the touch screen. | 1172 * Handles accessibility gestures from the touch screen. |
| 1176 * @param {string} gesture The gesture to handle, based on the AXGesture enum | 1173 * @param {string} gesture The gesture to handle, based on the AXGesture enum |
| 1177 * defined in ui/accessibility/ax_enums.idl | 1174 * defined in ui/accessibility/ax_enums.idl |
| 1178 * @private | 1175 * @private |
| 1179 */ | 1176 */ |
| 1180 onAccessibilityGesture_: function(gesture) { | 1177 onAccessibilityGesture_: function(gesture) { |
| 1181 // If we're in classic mode, some gestures need to be handled by the | 1178 // If we're in classic mode, some gestures need to be handled by the |
| 1182 // content script. Other gestures are universal and will be handled in | 1179 // content script. Other gestures are universal and will be handled in |
| 1183 // this function. | 1180 // this function. |
| 1184 if (this.mode_ == ChromeVoxMode.CLASSIC) { | 1181 if (this.mode == ChromeVoxMode.CLASSIC) { |
| 1185 if (this.handleClassicGesture_(gesture)) | 1182 if (this.handleClassicGesture_(gesture)) |
| 1186 return; | 1183 return; |
| 1187 } | 1184 } |
| 1188 | 1185 |
| 1189 var command = Background.GESTURE_NEXT_COMMAND_MAP[gesture]; | 1186 var command = Background.GESTURE_NEXT_COMMAND_MAP[gesture]; |
| 1190 if (command) | 1187 if (command) |
| 1191 this.onGotCommand(command); | 1188 this.onGotCommand(command); |
| 1192 }, | 1189 }, |
| 1193 | 1190 |
| 1194 /** | 1191 /** |
| 1195 * Handles accessibility gestures from the touch screen when in CLASSIC | 1192 * Handles accessibility gestures from the touch screen when in CLASSIC |
| 1196 * mode, by forwarding a command to the content script. | 1193 * mode, by forwarding a command to the content script. |
| 1197 * @param {string} gesture The gesture to handle, based on the AXGesture enum | 1194 * @param {string} gesture The gesture to handle, based on the AXGesture enum |
| 1198 * defined in ui/accessibility/ax_enums.idl | 1195 * defined in ui/accessibility/ax_enums.idl |
| 1199 * @return {boolean} True if this gesture was handled. | 1196 * @return {boolean} True if this gesture was handled. |
| 1200 * @private | 1197 * @private |
| 1201 */ | 1198 */ |
| 1202 handleClassicGesture_: function(gesture) { | 1199 handleClassicGesture_: function(gesture) { |
| 1203 var command = Background.GESTURE_CLASSIC_COMMAND_MAP[gesture]; | 1200 var command = Background.GESTURE_CLASSIC_COMMAND_MAP[gesture]; |
| 1204 if (!command) | 1201 if (!command) |
| 1205 return false; | 1202 return false; |
| 1206 | 1203 |
| 1207 var msg = { | 1204 var msg = { |
| 1208 'message': 'USER_COMMAND', | 1205 'message': 'USER_COMMAND', |
| 1209 'command': command | 1206 'command': command |
| 1210 }; | 1207 }; |
| 1211 cvox.ExtensionBridge.send(msg); | 1208 cvox.ExtensionBridge.send(msg); |
| 1212 return true; | 1209 return true; |
| 1213 }, | 1210 }, |
| 1211 |
| 1212 /** @private */ |
| 1213 setCurrentRangeToFocus_: function() { |
| 1214 chrome.automation.getFocus(function(focus) { |
| 1215 if (focus) |
| 1216 this.setCurrentRange(cursors.Range.fromNode(focus)); |
| 1217 else |
| 1218 this.setCurrentRange(null); |
| 1219 }.bind(this)); |
| 1220 }, |
| 1214 }; | 1221 }; |
| 1215 | 1222 |
| 1216 /** | 1223 /** |
| 1217 * Converts a list of globs, as used in the extension manifest, to a regular | 1224 * Converts a list of globs, as used in the extension manifest, to a regular |
| 1218 * expression that matches if and only if any of the globs in the list matches. | 1225 * expression that matches if and only if any of the globs in the list matches. |
| 1219 * @param {!Array<string>} globs | 1226 * @param {!Array<string>} globs |
| 1220 * @return {!RegExp} | 1227 * @return {!RegExp} |
| 1221 * @private | 1228 * @private |
| 1222 */ | 1229 */ |
| 1223 Background.globsToRegExp_ = function(globs) { | 1230 Background.globsToRegExp_ = function(globs) { |
| 1224 return new RegExp('^(' + globs.map(function(glob) { | 1231 return new RegExp('^(' + globs.map(function(glob) { |
| 1225 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') | 1232 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') |
| 1226 .replace(/\*/g, '.*') | 1233 .replace(/\*/g, '.*') |
| 1227 .replace(/\?/g, '.'); | 1234 .replace(/\?/g, '.'); |
| 1228 }).join('|') + ')$'); | 1235 }).join('|') + ')$'); |
| 1229 }; | 1236 }; |
| 1230 | 1237 |
| 1231 /** @type {Background} */ | 1238 new Background(); |
| 1232 global.backgroundObj = new Background(); | |
| 1233 | 1239 |
| 1234 }); // goog.scope | 1240 }); // goog.scope |
| OLD | NEW |