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

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

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

Powered by Google App Engine
This is Rietveld 408576698