Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(448)

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js

Issue 2079073002: Make ChromeVox Next a setting in options page. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: m Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698