Chromium Code Reviews| 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'); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 63 * @private | 63 * @private |
| 64 */ | 64 */ |
| 65 this.currentRange_ = null; | 65 this.currentRange_ = null; |
| 66 | 66 |
| 67 /** | 67 /** |
| 68 * @type {cursors.Range} | 68 * @type {cursors.Range} |
| 69 * @private | 69 * @private |
| 70 */ | 70 */ |
| 71 this.savedRange_ = null; | 71 this.savedRange_ = null; |
| 72 | 72 |
| 73 /** | |
| 74 * Which variant of ChromeVox is active. | |
| 75 * @type {ChromeVoxMode} | |
| 76 * @private | |
| 77 */ | |
| 78 this.mode_ = ChromeVoxMode.COMPAT; | |
| 79 | |
| 80 // Manually bind all functions to |this|. | 73 // Manually bind all functions to |this|. |
| 81 for (var func in this) { | 74 for (var func in this) { |
| 82 if (typeof(this[func]) == 'function') | 75 if (typeof(this[func]) == 'function') |
| 83 this[func] = this[func].bind(this); | 76 this[func] = this[func].bind(this); |
| 84 } | 77 } |
| 85 | 78 |
| 86 /** @type {!cvox.AbstractEarcons} @private */ | 79 /** @type {!cvox.AbstractEarcons} @private */ |
| 87 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); | 80 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); |
| 88 | 81 |
| 89 /** @type {!cvox.AbstractEarcons} @private */ | 82 /** @type {!cvox.AbstractEarcons} @private */ |
| 90 this.nextEarcons_ = new NextEarcons(); | 83 this.nextEarcons_ = new NextEarcons(); |
| 91 | 84 |
| 92 // Turn cvox.ChromeVox.earcons into a getter that returns either the | 85 // Turn cvox.ChromeVox.earcons into a getter that returns either the |
| 93 // Next earcons or the Classic earcons depending on the current mode. | 86 // Next earcons or the Classic earcons depending on the current mode. |
| 94 Object.defineProperty(cvox.ChromeVox, 'earcons', { | 87 Object.defineProperty(cvox.ChromeVox, 'earcons', { |
| 95 get: (function() { | 88 get: (function() { |
| 96 if (this.mode_ === ChromeVoxMode.FORCE_NEXT || | 89 if (this.mode === ChromeVoxMode.FORCE_NEXT || |
| 97 this.mode_ === ChromeVoxMode.NEXT) { | 90 this.mode === ChromeVoxMode.NEXT) { |
| 98 return this.nextEarcons_; | 91 return this.nextEarcons_; |
| 99 } else { | 92 } else { |
| 100 return this.classicEarcons_; | 93 return this.classicEarcons_; |
| 101 } | 94 } |
| 102 }).bind(this) | 95 }).bind(this) |
| 103 }); | 96 }); |
| 104 | 97 |
| 105 if (cvox.ChromeVox.isChromeOS) { | 98 if (cvox.ChromeVox.isChromeOS) { |
| 106 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { | 99 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { |
| 107 get: function() { | 100 get: function() { |
| 108 return (this.mode_ == ChromeVoxMode.CLASSIC || this.mode_ == | 101 return (this.mode == ChromeVoxMode.CLASSIC || this.mode == |
| 109 ChromeVoxMode.COMPAT) ? | 102 ChromeVoxMode.COMPAT) ? |
| 110 'Search+Shift' : 'Search'; | 103 'Search+Shift' : 'Search'; |
| 111 }.bind(this) | 104 }.bind(this) |
| 112 }); | 105 }); |
| 113 } | 106 } |
| 114 | 107 |
| 115 Object.defineProperty(cvox.ChromeVox, 'isActive', { | 108 Object.defineProperty(cvox.ChromeVox, 'isActive', { |
| 116 get: function() { | 109 get: function() { |
| 117 return localStorage['active'] !== 'false'; | 110 return localStorage['active'] !== 'false'; |
| 118 }, | 111 }, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 132 | 125 |
| 133 // Live region handler. | 126 // Live region handler. |
| 134 this.liveRegions_ = new LiveRegions(this); | 127 this.liveRegions_ = new LiveRegions(this); |
| 135 | 128 |
| 136 /** @type {number} @private */ | 129 /** @type {number} @private */ |
| 137 this.passThroughKeyUpCount_ = 0; | 130 this.passThroughKeyUpCount_ = 0; |
| 138 | 131 |
| 139 /** @type {boolean} @private */ | 132 /** @type {boolean} @private */ |
| 140 this.inExcursion_ = false; | 133 this.inExcursion_ = false; |
| 141 | 134 |
| 135 /** | |
| 136 * Stores the mode as computed the last time a current range was set. | |
| 137 * @type {?ChromeVoxMode} | |
| 138 */ | |
| 139 this.mode_ = null; | |
| 140 if (localStorage['useNext'] == 'true') | |
|
dmazzoni
2016/06/22 05:23:33
nit: maybe a blank line before this to better asso
| |
| 141 this.setCurrentRangeToFocus_(); | |
| 142 else | |
| 143 this.setCurrentRange(null); | |
| 144 | |
| 142 if (!chrome.accessibilityPrivate.setKeyboardListener) | 145 if (!chrome.accessibilityPrivate.setKeyboardListener) |
| 143 chrome.accessibilityPrivate.setKeyboardListener = function() {}; | 146 chrome.accessibilityPrivate.setKeyboardListener = function() {}; |
| 144 | 147 |
| 145 if (cvox.ChromeVox.isChromeOS) { | 148 if (cvox.ChromeVox.isChromeOS) { |
| 146 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( | 149 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( |
| 147 this.onAccessibilityGesture_); | 150 this.onAccessibilityGesture_); |
| 148 | 151 |
| 149 Notifications.onStartup(); | 152 Notifications.onStartup(); |
| 150 }}; | 153 }}; |
| 151 | 154 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 'swipeDown2': 'readFromHere', | 192 'swipeDown2': 'readFromHere', |
| 190 }; | 193 }; |
| 191 | 194 |
| 192 Background.prototype = { | 195 Background.prototype = { |
| 193 __proto__: ChromeVoxState.prototype, | 196 __proto__: ChromeVoxState.prototype, |
| 194 | 197 |
| 195 /** | 198 /** |
| 196 * @override | 199 * @override |
| 197 */ | 200 */ |
| 198 getMode: function() { | 201 getMode: function() { |
| 199 return this.mode_; | 202 if (localStorage['useNext'] == 'true') |
| 203 return ChromeVoxMode.FORCE_NEXT; | |
| 204 | |
| 205 var target; | |
| 206 if (!this.getCurrentRange()) { | |
| 207 chrome.automation.getFocus(function(focus) { | |
| 208 target = focus; | |
| 209 }); | |
| 210 } else { | |
| 211 target = this.getCurrentRange().start.node; | |
| 212 } | |
| 213 | |
| 214 if (!target) | |
| 215 return ChromeVoxMode.CLASSIC; | |
| 216 | |
| 217 // Closure complains, but clearly, |target| is not null. | |
| 218 var root = | |
| 219 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); | |
| 220 if (!root) | |
| 221 return ChromeVoxMode.COMPAT; | |
| 222 if (this.isWhitelistedForCompat_(root.docUrl)) | |
| 223 return ChromeVoxMode.COMPAT; | |
| 224 else if (this.isWhitelistedForNext_(root.docUrl)) | |
| 225 return ChromeVoxMode.NEXT; | |
| 226 else | |
| 227 return ChromeVoxMode.CLASSIC; | |
| 200 }, | 228 }, |
| 201 | 229 |
| 202 /** | 230 /** |
| 203 * @override | 231 * Handles a mode change. |
| 232 * @param {ChromeVoxMode} newMode | |
| 233 * @param {?ChromeVoxMode} oldMode | |
|
dmazzoni
2016/06/22 05:23:33
Docstring for this maybe saying it can be null to
| |
| 234 * @private | |
| 204 */ | 235 */ |
| 205 setMode: function(mode, opt_injectClassic) { | 236 onModeChanged_: function(newMode, oldMode) { |
| 206 // Switching key maps potentially affects the key codes that involve | 237 // Switching key maps potentially affects the key codes that involve |
| 207 // sequencing. Without resetting this list, potentially stale key codes | 238 // sequencing. Without resetting this list, potentially stale key codes |
| 208 // remain. The key codes themselves get pushed in | 239 // remain. The key codes themselves get pushed in |
| 209 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. | 240 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. |
| 210 cvox.ChromeVox.sequenceSwitchKeyCodes = []; | 241 cvox.ChromeVox.sequenceSwitchKeyCodes = []; |
| 211 if (mode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) | 242 if (window['prefs']) { |
| 212 window['prefs'].switchToKeyMap('keymap_classic'); | 243 if (newMode === ChromeVoxMode.CLASSIC || newMode === ChromeVoxMode.COMPAT) |
| 213 else | 244 window['prefs'].switchToKeyMap('keymap_classic'); |
| 214 window['prefs'].switchToKeyMap('keymap_next'); | 245 else |
| 246 window['prefs'].switchToKeyMap('keymap_next'); | |
| 247 } | |
| 215 | 248 |
| 216 if (mode == ChromeVoxMode.CLASSIC) { | 249 if (newMode == ChromeVoxMode.CLASSIC) { |
| 217 if (chrome.commands && | 250 if (chrome.commands && |
| 218 chrome.commands.onCommand.hasListener(this.onGotCommand)) | 251 chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 219 chrome.commands.onCommand.removeListener(this.onGotCommand); | 252 chrome.commands.onCommand.removeListener(this.onGotCommand); |
| 220 chrome.accessibilityPrivate.setKeyboardListener(false, false); | 253 chrome.accessibilityPrivate.setKeyboardListener(false, false); |
| 221 } else { | 254 |
| 255 if (cvox.ChromeVox.isChromeOS) | |
| 256 chrome.accessibilityPrivate.setFocusRing([]); | |
| 257 } else if (oldMode) { | |
| 222 if (chrome.commands && | 258 if (chrome.commands && |
| 223 !chrome.commands.onCommand.hasListener(this.onGotCommand)) | 259 !chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 224 chrome.commands.onCommand.addListener(this.onGotCommand); | 260 chrome.commands.onCommand.addListener(this.onGotCommand); |
| 225 chrome.accessibilityPrivate.setKeyboardListener( | 261 chrome.accessibilityPrivate.setKeyboardListener( |
| 226 true, cvox.ChromeVox.isStickyPrefOn); | 262 true, cvox.ChromeVox.isStickyPrefOn); |
| 227 } | 263 } |
| 228 | 264 |
| 229 // note that |this.currentRange_| can *change* because the request is | 265 // note that |this.currentRange_| can *change* because the request is |
| 230 // async. Save it to ensure we're looking at the currentRange at this moment | 266 // async. Save it to ensure we're looking at the currentRange at this moment |
| 231 // in time. | 267 // in time. |
| 232 var cur = this.currentRange_; | 268 var cur = this.currentRange_; |
| 233 chrome.tabs.query({active: true}, function(tabs) { | 269 chrome.tabs.query({active: true}, function(tabs) { |
| 234 if (mode === ChromeVoxMode.CLASSIC) { | 270 if (newMode === ChromeVoxMode.CLASSIC) { |
| 235 // Generally, we don't want to inject classic content scripts as it is | 271 // Generally, we don't want to inject classic content scripts as it is |
| 236 // done by the extension system at document load. The exception is when | 272 // done by the extension system at document load. The exception is when |
| 237 // we toggle classic on manually as part of a user command. | 273 // we toggle classic on manually as part of a user command. |
| 238 if (opt_injectClassic) | 274 if (oldMode == ChromeVoxMode.FORCE_NEXT) |
| 239 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); | 275 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
| 240 } else { | 276 } else if (oldMode) { |
| 241 // When in compat mode, if the focus is within the desktop tree proper, | 277 // When in compat mode, if the focus is within the desktop tree proper, |
| 242 // then do not disable content scripts. | 278 // then do not disable content scripts. |
| 243 if (cur && !cur.isWebRange()) | 279 if (cur && !cur.isWebRange()) |
| 244 return; | 280 return; |
| 245 | 281 |
| 246 this.disableClassicChromeVox_(); | 282 this.disableClassicChromeVox_(); |
| 247 } | 283 } |
| 248 }.bind(this)); | 284 }.bind(this)); |
| 249 | 285 |
| 250 // If switching out of a ChromeVox Next mode, make sure we cancel | 286 // If switching out of a ChromeVox Next mode, make sure we cancel |
| 251 // the progress loading sound just in case. | 287 // the progress loading sound just in case. |
| 252 if ((this.mode_ === ChromeVoxMode.NEXT || | 288 if (oldMode === ChromeVoxMode.NEXT || |
| 253 this.mode_ === ChromeVoxMode.FORCE_NEXT) && | 289 oldMode === ChromeVoxMode.FORCE_NEXT) |
| 254 this.mode_ != mode) { | |
| 255 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); | 290 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
| 256 } | |
| 257 | 291 |
| 258 if (mode === ChromeVoxMode.NEXT || | 292 if (newMode === ChromeVoxMode.NEXT || |
| 259 mode === ChromeVoxMode.FORCE_NEXT) { | 293 newMode === ChromeVoxMode.FORCE_NEXT) { |
| 260 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); | 294 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); |
| 261 if (cvox.TabsApiHandler) | 295 if (cvox.TabsApiHandler) |
| 262 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; | 296 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; |
| 263 } else { | 297 } else if (oldMode) { |
| 264 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); | 298 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); |
| 265 if (cvox.TabsApiHandler) | 299 if (cvox.TabsApiHandler) |
| 266 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; | 300 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; |
| 267 } | 301 } |
| 268 | |
| 269 // If switching to Classic from any automation-API-based mode, | |
| 270 // clear the focus ring. | |
| 271 if (mode === ChromeVoxMode.CLASSIC && mode != this.mode_) { | |
| 272 if (cvox.ChromeVox.isChromeOS) | |
| 273 chrome.accessibilityPrivate.setFocusRing([]); | |
| 274 } | |
| 275 | |
| 276 // If switching away from Classic to any automation-API-based mode, | |
| 277 // update the range based on what's focused. | |
| 278 if (this.mode_ === ChromeVoxMode.CLASSIC && mode != this.mode_) { | |
| 279 chrome.automation.getFocus((function(focus) { | |
| 280 if (focus) | |
| 281 this.setCurrentRange(cursors.Range.fromNode(focus)); | |
| 282 }).bind(this)); | |
| 283 } | |
| 284 | |
| 285 this.mode_ = mode; | |
| 286 }, | 302 }, |
| 287 | 303 |
| 288 /** | 304 /** |
| 289 * Mode refreshes takes into account both |url| and the current ChromeVox | 305 * Toggles between force next and classic/compat modes. |
| 290 * range. The latter gets used to decide if the user is or isn't in web | 306 * This toggle automatically handles deciding between classic/compat based on |
| 291 * content. The focused state also needs to be set for this info to be | 307 * the start of the current range. |
| 292 * reliable. | 308 * @param {boolean=} opt_setValue Directly set to force next (true) or |
| 293 * @override | 309 * classic/compat (false). |
| 310 * @return {boolean} True to announce current position. | |
| 294 */ | 311 */ |
| 295 refreshMode: function(node) { | 312 toggleNext: function(opt_setValue) { |
| 296 // Mode changes are based upon the top level web root. | 313 var useNext; |
| 297 var root = node.root; | 314 if (opt_setValue !== undefined) |
| 298 while (root && | 315 useNext = opt_setValue; |
| 299 root.parent && | 316 else |
| 300 root.parent.root && | 317 useNext = localStorage['useNext'] != 'true'; |
| 301 root.parent.root.role != RoleType.desktop) { | |
| 302 root = root.parent.root; | |
| 303 } | |
| 304 | 318 |
| 305 var url = ''; | 319 localStorage['useNext'] = useNext; |
| 306 if (root && root.role == RoleType.rootWebArea) | 320 if (useNext) |
| 307 url = root.docUrl; | 321 this.setCurrentRangeToFocus_(); |
| 322 else | |
| 323 this.setCurrentRange(null); | |
| 308 | 324 |
| 309 var mode = this.mode_; | 325 var announce = Msgs.getMsg(useNext ? |
| 310 if (mode != ChromeVoxMode.FORCE_NEXT) { | 326 'switch_to_next' : 'switch_to_classic'); |
| 311 if (this.isWhitelistedForNext_(url)) { | 327 cvox.ChromeVox.tts.speak( |
| 312 mode = ChromeVoxMode.NEXT; | 328 announce, cvox.QueueMode.FLUSH, {doNotInterrupt: true}); |
| 313 } else if (this.isBlacklistedForClassic_(url) || (this.currentRange_ && | 329 Notifications.onModeChange(); |
| 314 !this.currentRange_.isWebRange() && | |
| 315 this.currentRange_.start.node.state.focused)) { | |
| 316 mode = ChromeVoxMode.COMPAT; | |
| 317 } else { | |
| 318 mode = ChromeVoxMode.CLASSIC; | |
| 319 } | |
| 320 } | |
| 321 | 330 |
| 322 this.setMode(mode); | 331 // If the new mode is Classic, return false now so we don't announce |
| 332 // anything more. | |
| 333 return useNext; | |
| 323 }, | 334 }, |
| 324 | 335 |
| 325 /** | 336 /** |
| 326 * @override | 337 * @override |
| 327 */ | 338 */ |
| 328 getCurrentRange: function() { | 339 getCurrentRange: function() { |
| 329 if (this.currentRange_ && this.currentRange_.isValid()) | 340 if (this.currentRange_ && this.currentRange_.isValid()) |
| 330 return this.currentRange_; | 341 return this.currentRange_; |
| 331 return null; | 342 return null; |
| 332 }, | 343 }, |
| 333 | 344 |
| 334 /** | 345 /** |
| 335 * @override | 346 * @override |
| 336 */ | 347 */ |
| 337 setCurrentRange: function(newRange) { | 348 setCurrentRange: function(newRange) { |
| 338 if (!newRange) | 349 if (!this.inExcursion_ && newRange) |
| 339 return; | |
| 340 | |
| 341 // Is the range invalid? | |
| 342 if (newRange.start.node.role === undefined || | |
| 343 newRange.end.node.role === undefined) { | |
| 344 // Restore range to the focused location. | |
| 345 chrome.automation.getFocus(function(f) { | |
| 346 newRange = cursors.Range.fromNode(f); | |
| 347 }); | |
| 348 } | |
| 349 | |
| 350 if (!this.inExcursion_) | |
| 351 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); | 350 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); |
| 352 | 351 |
| 353 this.currentRange_ = newRange; | 352 this.currentRange_ = newRange; |
| 353 var oldMode = this.mode_; | |
| 354 var newMode = this.getMode(); | |
| 355 if (oldMode != newMode) { | |
| 356 this.onModeChanged_(newMode, oldMode); | |
| 357 this.mode_ = newMode; | |
| 358 } | |
| 354 | 359 |
| 355 if (this.currentRange_) { | 360 if (this.currentRange_) { |
| 356 var start = this.currentRange_.start.node; | 361 var start = this.currentRange_.start.node; |
| 357 start.makeVisible(); | 362 start.makeVisible(); |
| 358 | 363 |
| 359 var root = start.root; | 364 var root = start.root; |
| 360 | |
| 361 if (!root || root.role == RoleType.desktop) | 365 if (!root || root.role == RoleType.desktop) |
| 362 return; | 366 return; |
| 363 | 367 |
| 364 var position = {}; | 368 var position = {}; |
| 365 var loc = start.location; | 369 var loc = start.location; |
| 366 position.x = loc.left + loc.width / 2; | 370 position.x = loc.left + loc.width / 2; |
| 367 position.y = loc.top + loc.height / 2; | 371 position.y = loc.top + loc.height / 2; |
| 368 var url = root.docUrl; | 372 var url = root.docUrl; |
| 369 url = url.substring(0, url.indexOf('#')) || url; | 373 url = url.substring(0, url.indexOf('#')) || url; |
| 370 cvox.ChromeVox.position[url] = position; | 374 cvox.ChromeVox.position[url] = position; |
| 371 } | 375 } |
| 372 }, | 376 }, |
| 373 | 377 |
| 374 /** Forces ChromeVox Next to be active for all tabs. */ | |
| 375 forceChromeVoxNextActive: function() { | |
| 376 this.setMode(ChromeVoxMode.FORCE_NEXT); | |
| 377 }, | |
| 378 | |
| 379 /** | 378 /** |
| 380 * Handles ChromeVox Next commands. | 379 * Handles ChromeVox Next commands. |
| 381 * @param {string} command | 380 * @param {string} command |
| 382 * @param {boolean=} opt_bypassModeCheck Always tries to execute the command | 381 * @param {boolean=} opt_bypassModeCheck Always tries to execute the command |
| 383 * regardless of mode. | 382 * regardless of mode. |
| 384 * @return {boolean} True if the command should propagate. | 383 * @return {boolean} True if the command should propagate. |
| 385 */ | 384 */ |
| 386 onGotCommand: function(command, opt_bypassModeCheck) { | 385 onGotCommand: function(command, opt_bypassModeCheck) { |
| 387 // Check for loss of focus which results in us invalidating our current | 386 // Check for loss of focus which results in us invalidating our current |
| 388 // range. Note this call is synchronis. | 387 // range. Note this call is synchronis. |
| 389 chrome.automation.getFocus(function(focusedNode) { | 388 chrome.automation.getFocus(function(focusedNode) { |
| 390 if (this.currentRange_ && !this.currentRange_.isValid()) | 389 if (this.currentRange_ && !this.currentRange_.isValid()) |
| 391 this.currentRange_ = cursors.Range.fromNode(focusedNode); | 390 this.currentRange_ = cursors.Range.fromNode(focusedNode); |
| 392 if (!focusedNode) | 391 if (!focusedNode) |
| 393 this.currentRange_ = null; | 392 this.currentRange_ = null; |
| 394 }.bind(this)); | 393 }.bind(this)); |
| 395 | 394 |
| 396 if (!this.currentRange_) | 395 if (!this.currentRange_) |
| 397 return true; | 396 return true; |
| 398 | 397 |
| 399 if (this.mode_ == ChromeVoxMode.CLASSIC && !opt_bypassModeCheck) | 398 if (this.mode == ChromeVoxMode.CLASSIC && !opt_bypassModeCheck) |
| 400 return true; | 399 return true; |
| 401 | 400 |
| 402 var current = this.currentRange_; | 401 var current = this.currentRange_; |
| 403 var dir = Dir.FORWARD; | 402 var dir = Dir.FORWARD; |
| 404 var pred = null; | 403 var pred = null; |
| 405 var predErrorMsg = undefined; | 404 var predErrorMsg = undefined; |
| 406 var speechProps = {}; | 405 var speechProps = {}; |
| 407 switch (command) { | 406 switch (command) { |
| 408 case 'nextCharacter': | 407 case 'nextCharacter': |
| 409 speechProps['phoneticCharacters'] = true; | 408 speechProps['phoneticCharacters'] = true; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 return false; | 599 return false; |
| 601 | 600 |
| 602 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; | 601 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; |
| 603 if (!cvox.ChromeVox.isActive) { | 602 if (!cvox.ChromeVox.isActive) { |
| 604 var msg = Msgs.getMsg('chromevox_inactive'); | 603 var msg = Msgs.getMsg('chromevox_inactive'); |
| 605 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); | 604 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); |
| 606 return false; | 605 return false; |
| 607 } | 606 } |
| 608 break; | 607 break; |
| 609 case 'toggleChromeVoxVersion': | 608 case 'toggleChromeVoxVersion': |
| 610 var newMode; | 609 if (!this.toggleNext()) |
| 611 if (this.mode_ == ChromeVoxMode.FORCE_NEXT) { | 610 return false; |
| 612 var inWeb = current.isWebRange(); | |
| 613 newMode = inWeb ? ChromeVoxMode.CLASSIC : ChromeVoxMode.COMPAT; | |
| 614 } else { | |
| 615 newMode = ChromeVoxMode.FORCE_NEXT; | |
| 616 } | |
| 617 this.setMode(newMode, true); | |
| 618 | |
| 619 var isClassic = | |
| 620 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; | |
| 621 | |
| 622 // Leaving unlocalized as 'next' isn't an official name. | |
| 623 cvox.ChromeVox.tts.speak(isClassic ? | |
| 624 'classic' : 'next', cvox.QueueMode.FLUSH, {doNotInterrupt: true}); | |
| 625 | |
| 626 // If the new mode is Classic, return now so we don't announce | |
| 627 // anything more. | |
| 628 if (newMode == ChromeVoxMode.CLASSIC) | |
| 629 return false; | |
| 630 break; | 611 break; |
| 631 case 'toggleStickyMode': | 612 case 'toggleStickyMode': |
| 632 cvox.ChromeVoxBackground.setPref('sticky', | 613 cvox.ChromeVoxBackground.setPref('sticky', |
| 633 !cvox.ChromeVox.isStickyPrefOn, | 614 !cvox.ChromeVox.isStickyPrefOn, |
| 634 true); | 615 true); |
| 635 | 616 |
| 636 if (cvox.ChromeVox.isStickyPrefOn) | 617 if (cvox.ChromeVox.isStickyPrefOn) |
| 637 chrome.accessibilityPrivate.setKeyboardListener(true, true); | 618 chrome.accessibilityPrivate.setKeyboardListener(true, true); |
| 638 else | 619 else |
| 639 chrome.accessibilityPrivate.setKeyboardListener(true, false); | 620 chrome.accessibilityPrivate.setKeyboardListener(true, false); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 780 output.go(); | 761 output.go(); |
| 781 return false; | 762 return false; |
| 782 case 'readCurrentURL': | 763 case 'readCurrentURL': |
| 783 var output = new Output(); | 764 var output = new Output(); |
| 784 var target = this.currentRange_.start.node.root; | 765 var target = this.currentRange_.start.node.root; |
| 785 output.withString(target.docUrl || '').go(); | 766 output.withString(target.docUrl || '').go(); |
| 786 return false; | 767 return false; |
| 787 case 'reportIssue': | 768 case 'reportIssue': |
| 788 var url = Background.ISSUE_URL; | 769 var url = Background.ISSUE_URL; |
| 789 var description = {}; | 770 var description = {}; |
| 790 description['Mode'] = this.mode_; | 771 description['Mode'] = this.mode; |
| 791 description['Version'] = chrome.app.getDetails().version; | 772 description['Version'] = chrome.app.getDetails().version; |
| 792 description['Reproduction Steps'] = '%0a1.%0a2.%0a3.'; | 773 description['Reproduction Steps'] = '%0a1.%0a2.%0a3.'; |
| 793 for (var key in description) | 774 for (var key in description) |
| 794 url += key + ':%20' + description[key] + '%0a'; | 775 url += key + ':%20' + description[key] + '%0a'; |
| 795 chrome.tabs.create({url: url}); | 776 chrome.tabs.create({url: url}); |
| 796 return false; | 777 return false; |
| 797 case 'toggleBrailleCaptions': | 778 case 'toggleBrailleCaptions': |
| 798 cvox.BrailleCaptionsBackground.setActive( | 779 cvox.BrailleCaptionsBackground.setActive( |
| 799 !cvox.BrailleCaptionsBackground.isEnabled()); | 780 !cvox.BrailleCaptionsBackground.isEnabled()); |
| 800 return false; | 781 return false; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 901 /** | 882 /** |
| 902 * Handles key down events. | 883 * Handles key down events. |
| 903 * @param {Event} evt The key down event to process. | 884 * @param {Event} evt The key down event to process. |
| 904 * @return {boolean} True if the default action should be performed. | 885 * @return {boolean} True if the default action should be performed. |
| 905 */ | 886 */ |
| 906 onKeyDown: function(evt) { | 887 onKeyDown: function(evt) { |
| 907 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; | 888 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; |
| 908 if (cvox.ChromeVox.passThroughMode) | 889 if (cvox.ChromeVox.passThroughMode) |
| 909 return false; | 890 return false; |
| 910 | 891 |
| 911 if (this.mode_ != ChromeVoxMode.CLASSIC && | 892 if (this.mode != ChromeVoxMode.CLASSIC && |
| 912 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { | 893 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { |
| 913 evt.preventDefault(); | 894 evt.preventDefault(); |
| 914 evt.stopPropagation(); | 895 evt.stopPropagation(); |
| 915 } | 896 } |
| 916 Output.flushNextSpeechUtterance(); | 897 Output.flushNextSpeechUtterance(); |
| 917 return false; | 898 return false; |
| 918 }, | 899 }, |
| 919 | 900 |
| 920 /** | 901 /** |
| 921 * Handles key up events. | 902 * Handles key up events. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 944 chrome.tabs.create(optionsPage); | 925 chrome.tabs.create(optionsPage); |
| 945 }, | 926 }, |
| 946 | 927 |
| 947 /** | 928 /** |
| 948 * Handles a braille command. | 929 * Handles a braille command. |
| 949 * @param {!cvox.BrailleKeyEvent} evt | 930 * @param {!cvox.BrailleKeyEvent} evt |
| 950 * @param {!cvox.NavBraille} content | 931 * @param {!cvox.NavBraille} content |
| 951 * @return {boolean} True if evt was processed. | 932 * @return {boolean} True if evt was processed. |
| 952 */ | 933 */ |
| 953 onBrailleKeyEvent: function(evt, content) { | 934 onBrailleKeyEvent: function(evt, content) { |
| 954 if (this.mode_ === ChromeVoxMode.CLASSIC) | 935 if (this.mode === ChromeVoxMode.CLASSIC) |
| 955 return false; | 936 return false; |
| 956 | 937 |
| 957 switch (evt.command) { | 938 switch (evt.command) { |
| 958 case cvox.BrailleKeyCommand.PAN_LEFT: | 939 case cvox.BrailleKeyCommand.PAN_LEFT: |
| 959 this.onGotCommand('previousObject'); | 940 this.onGotCommand('previousObject'); |
| 960 break; | 941 break; |
| 961 case cvox.BrailleKeyCommand.PAN_RIGHT: | 942 case cvox.BrailleKeyCommand.PAN_RIGHT: |
| 962 this.onGotCommand('nextObject'); | 943 this.onGotCommand('nextObject'); |
| 963 break; | 944 break; |
| 964 case cvox.BrailleKeyCommand.LINE_UP: | 945 case cvox.BrailleKeyCommand.LINE_UP: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 984 } | 965 } |
| 985 return true; | 966 return true; |
| 986 }, | 967 }, |
| 987 | 968 |
| 988 /** | 969 /** |
| 989 * Returns true if the url should have Classic running. | 970 * Returns true if the url should have Classic running. |
| 990 * @return {boolean} | 971 * @return {boolean} |
| 991 * @private | 972 * @private |
| 992 */ | 973 */ |
| 993 shouldEnableClassicForUrl_: function(url) { | 974 shouldEnableClassicForUrl_: function(url) { |
| 994 return this.mode_ != ChromeVoxMode.FORCE_NEXT && | 975 return this.mode != ChromeVoxMode.FORCE_NEXT && |
| 995 !this.isBlacklistedForClassic_(url) && | 976 !this.isBlacklistedForClassic_(url) && |
| 996 !this.isWhitelistedForNext_(url); | 977 !this.isWhitelistedForNext_(url); |
| 997 }, | 978 }, |
| 998 | 979 |
| 999 /** | 980 /** |
| 981 * Compat mode is on if any of the following are true: | |
| 982 * 1. a url is blacklisted for Classic. | |
| 983 * 2. the current range is not within web content. | |
| 984 * @param {string} url | |
| 985 */ | |
| 986 isWhitelistedForCompat_: function(url) { | |
| 987 return this.isBlacklistedForClassic_(url) || (this.getCurrentRange() && | |
| 988 !this.getCurrentRange().isWebRange() && | |
| 989 this.getCurrentRange().start.node.state.focused); | |
| 990 }, | |
| 991 | |
| 992 /** | |
| 1000 * @param {string} url | 993 * @param {string} url |
| 1001 * @return {boolean} | 994 * @return {boolean} |
| 1002 * @private | 995 * @private |
| 1003 */ | 996 */ |
| 1004 isBlacklistedForClassic_: function(url) { | 997 isBlacklistedForClassic_: function(url) { |
| 1005 return this.classicBlacklistRegExp_.test(url); | 998 return this.classicBlacklistRegExp_.test(url); |
| 1006 }, | 999 }, |
| 1007 | 1000 |
| 1008 /** | 1001 /** |
| 1009 * @param {string} url | 1002 * @param {string} url |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1143 /** | 1136 /** |
| 1144 * Handles accessibility gestures from the touch screen. | 1137 * Handles accessibility gestures from the touch screen. |
| 1145 * @param {string} gesture The gesture to handle, based on the AXGesture enum | 1138 * @param {string} gesture The gesture to handle, based on the AXGesture enum |
| 1146 * defined in ui/accessibility/ax_enums.idl | 1139 * defined in ui/accessibility/ax_enums.idl |
| 1147 * @private | 1140 * @private |
| 1148 */ | 1141 */ |
| 1149 onAccessibilityGesture_: function(gesture) { | 1142 onAccessibilityGesture_: function(gesture) { |
| 1150 // If we're in classic mode, some gestures need to be handled by the | 1143 // If we're in classic mode, some gestures need to be handled by the |
| 1151 // content script. Other gestures are universal and will be handled in | 1144 // content script. Other gestures are universal and will be handled in |
| 1152 // this function. | 1145 // this function. |
| 1153 if (this.mode_ == ChromeVoxMode.CLASSIC) { | 1146 if (this.mode == ChromeVoxMode.CLASSIC) { |
| 1154 if (this.handleClassicGesture_(gesture)) | 1147 if (this.handleClassicGesture_(gesture)) |
| 1155 return; | 1148 return; |
| 1156 } | 1149 } |
| 1157 | 1150 |
| 1158 var command = Background.GESTURE_NEXT_COMMAND_MAP[gesture]; | 1151 var command = Background.GESTURE_NEXT_COMMAND_MAP[gesture]; |
| 1159 if (command) | 1152 if (command) |
| 1160 this.onGotCommand(command); | 1153 this.onGotCommand(command); |
| 1161 }, | 1154 }, |
| 1162 | 1155 |
| 1163 /** | 1156 /** |
| 1164 * Handles accessibility gestures from the touch screen when in CLASSIC | 1157 * Handles accessibility gestures from the touch screen when in CLASSIC |
| 1165 * mode, by forwarding a command to the content script. | 1158 * mode, by forwarding a command to the content script. |
| 1166 * @param {string} gesture The gesture to handle, based on the AXGesture enum | 1159 * @param {string} gesture The gesture to handle, based on the AXGesture enum |
| 1167 * defined in ui/accessibility/ax_enums.idl | 1160 * defined in ui/accessibility/ax_enums.idl |
| 1168 * @return {boolean} True if this gesture was handled. | 1161 * @return {boolean} True if this gesture was handled. |
| 1169 * @private | 1162 * @private |
| 1170 */ | 1163 */ |
| 1171 handleClassicGesture_: function(gesture) { | 1164 handleClassicGesture_: function(gesture) { |
| 1172 var command = Background.GESTURE_CLASSIC_COMMAND_MAP[gesture]; | 1165 var command = Background.GESTURE_CLASSIC_COMMAND_MAP[gesture]; |
| 1173 if (!command) | 1166 if (!command) |
| 1174 return false; | 1167 return false; |
| 1175 | 1168 |
| 1176 var msg = { | 1169 var msg = { |
| 1177 'message': 'USER_COMMAND', | 1170 'message': 'USER_COMMAND', |
| 1178 'command': command | 1171 'command': command |
| 1179 }; | 1172 }; |
| 1180 cvox.ExtensionBridge.send(msg); | 1173 cvox.ExtensionBridge.send(msg); |
| 1181 return true; | 1174 return true; |
| 1182 }, | 1175 }, |
| 1176 | |
| 1177 /** @private */ | |
| 1178 setCurrentRangeToFocus_: function() { | |
| 1179 chrome.automation.getFocus(function(focus) { | |
| 1180 if (focus) | |
| 1181 this.setCurrentRange(cursors.Range.fromNode(focus)); | |
| 1182 else | |
| 1183 this.setCurrentRange(null); | |
| 1184 }.bind(this)); | |
| 1185 }, | |
| 1183 }; | 1186 }; |
| 1184 | 1187 |
| 1185 /** | 1188 /** |
| 1186 * Converts a list of globs, as used in the extension manifest, to a regular | 1189 * Converts a list of globs, as used in the extension manifest, to a regular |
| 1187 * expression that matches if and only if any of the globs in the list matches. | 1190 * expression that matches if and only if any of the globs in the list matches. |
| 1188 * @param {!Array<string>} globs | 1191 * @param {!Array<string>} globs |
| 1189 * @return {!RegExp} | 1192 * @return {!RegExp} |
| 1190 * @private | 1193 * @private |
| 1191 */ | 1194 */ |
| 1192 Background.globsToRegExp_ = function(globs) { | 1195 Background.globsToRegExp_ = function(globs) { |
| 1193 return new RegExp('^(' + globs.map(function(glob) { | 1196 return new RegExp('^(' + globs.map(function(glob) { |
| 1194 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') | 1197 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') |
| 1195 .replace(/\*/g, '.*') | 1198 .replace(/\*/g, '.*') |
| 1196 .replace(/\?/g, '.'); | 1199 .replace(/\?/g, '.'); |
| 1197 }).join('|') + ')$'); | 1200 }).join('|') + ')$'); |
| 1198 }; | 1201 }; |
| 1199 | 1202 |
| 1200 /** @type {Background} */ | 1203 /** @type {Background} */ |
| 1201 global.backgroundObj = new Background(); | 1204 global.backgroundObj = new Background(); |
| 1202 | 1205 |
| 1203 }); // goog.scope | 1206 }); // goog.scope |
| OLD | NEW |