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

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

Issue 1561773002: Implement ChromeVox Next menus. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@panel_view_type
Patch Set: Address feedback Created 4 years, 11 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 goog.provide('global');
12 12
13 goog.require('AutomationPredicate'); 13 goog.require('AutomationPredicate');
14 goog.require('AutomationUtil'); 14 goog.require('AutomationUtil');
15 goog.require('ChromeVoxState'); 15 goog.require('ChromeVoxState');
16 goog.require('LiveRegions'); 16 goog.require('LiveRegions');
17 goog.require('NextEarcons'); 17 goog.require('NextEarcons');
18 goog.require('Output'); 18 goog.require('Output');
19 goog.require('Output.EventType'); 19 goog.require('Output.EventType');
20 goog.require('PanelCommand');
20 goog.require('constants'); 21 goog.require('constants');
21 goog.require('cursors.Cursor'); 22 goog.require('cursors.Cursor');
22 goog.require('cvox.BrailleKeyCommand'); 23 goog.require('cvox.BrailleKeyCommand');
23 goog.require('cvox.ChromeVoxEditableTextBase'); 24 goog.require('cvox.ChromeVoxEditableTextBase');
24 goog.require('cvox.ChromeVoxKbHandler'); 25 goog.require('cvox.ChromeVoxKbHandler');
25 goog.require('cvox.ClassicEarcons'); 26 goog.require('cvox.ClassicEarcons');
26 goog.require('cvox.ExtensionBridge'); 27 goog.require('cvox.ExtensionBridge');
27 goog.require('cvox.NavBraille'); 28 goog.require('cvox.NavBraille');
28 29
29 goog.scope(function() { 30 goog.scope(function() {
(...skipping 26 matching lines...) Expand all
56 this.classicBlacklistRegExp_ = Background.globsToRegExp_( 57 this.classicBlacklistRegExp_ = Background.globsToRegExp_(
57 chrome.runtime.getManifest()['content_scripts'][0]['exclude_globs']); 58 chrome.runtime.getManifest()['content_scripts'][0]['exclude_globs']);
58 59
59 /** 60 /**
60 * @type {cursors.Range} 61 * @type {cursors.Range}
61 * @private 62 * @private
62 */ 63 */
63 this.currentRange_ = null; 64 this.currentRange_ = null;
64 65
65 /** 66 /**
67 * @type {cursors.Range}
68 * @private
69 */
70 this.savedRange_ = null;
71
72 /**
66 * Which variant of ChromeVox is active. 73 * Which variant of ChromeVox is active.
67 * @type {ChromeVoxMode} 74 * @type {ChromeVoxMode}
68 * @private 75 * @private
69 */ 76 */
70 this.mode_ = ChromeVoxMode.COMPAT; 77 this.mode_ = ChromeVoxMode.COMPAT;
71 78
72 // Manually bind all functions to |this|. 79 // Manually bind all functions to |this|.
73 for (var func in this) { 80 for (var func in this) {
74 if (typeof(this[func]) == 'function') 81 if (typeof(this[func]) == 'function')
75 this[func] = this[func].bind(this); 82 this[func] = this[func].bind(this);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 }.bind(this)); 184 }.bind(this));
178 185
179 // If switching out of a ChromeVox Next mode, make sure we cancel 186 // If switching out of a ChromeVox Next mode, make sure we cancel
180 // the progress loading sound just in case. 187 // the progress loading sound just in case.
181 if ((this.mode_ === ChromeVoxMode.NEXT || 188 if ((this.mode_ === ChromeVoxMode.NEXT ||
182 this.mode_ === ChromeVoxMode.FORCE_NEXT) && 189 this.mode_ === ChromeVoxMode.FORCE_NEXT) &&
183 this.mode_ != mode) { 190 this.mode_ != mode) {
184 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); 191 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING);
185 } 192 }
186 193
194 if (mode === ChromeVoxMode.NEXT ||
195 mode === ChromeVoxMode.FORCE_NEXT) {
196 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send();
197 } else {
198 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send();
199 }
200
187 this.mode_ = mode; 201 this.mode_ = mode;
188 }, 202 },
189 203
190 /** 204 /**
191 * Mode refreshes takes into account both |url| and the current ChromeVox 205 * Mode refreshes takes into account both |url| and the current ChromeVox
192 * range. The latter gets used to decide if the user is or isn't in web 206 * range. The latter gets used to decide if the user is or isn't in web
193 * content. The focused state also needs to be set for this info to be 207 * content. The focused state also needs to be set for this info to be
194 * reliable. 208 * reliable.
195 * @override 209 * @override
196 */ 210 */
(...skipping 21 matching lines...) Expand all
218 return this.currentRange_; 232 return this.currentRange_;
219 }, 233 },
220 234
221 /** 235 /**
222 * @override 236 * @override
223 */ 237 */
224 setCurrentRange: function(newRange) { 238 setCurrentRange: function(newRange) {
225 if (!newRange) 239 if (!newRange)
226 return; 240 return;
227 241
242 var panelUrl = chrome.extension.getURL('cvox2/background/panel.html');
243 if (newRange.start.node.root.docUrl.indexOf(panelUrl) != 0) {
244 this.savedRange_ = new cursors.Range(newRange.start, newRange.end);
245 }
David Tseng 2016/01/12 20:10:57 nit: remove braces
dmazzoni 2016/01/13 23:26:39 Done.
246
228 this.currentRange_ = newRange; 247 this.currentRange_ = newRange;
229 248
230 if (this.currentRange_) 249 if (this.currentRange_)
231 this.currentRange_.start.node.makeVisible(); 250 this.currentRange_.start.node.makeVisible();
232 }, 251 },
233 252
234 /** Forces ChromeVox Next to be active for all tabs. */ 253 /** Forces ChromeVox Next to be active for all tabs. */
235 forceChromeVoxNextActive: function() { 254 forceChromeVoxNextActive: function() {
236 this.setMode(ChromeVoxMode.FORCE_NEXT); 255 this.setMode(ChromeVoxMode.FORCE_NEXT);
237 }, 256 },
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 case 'nextButton': 297 case 'nextButton':
279 dir = Dir.FORWARD; 298 dir = Dir.FORWARD;
280 pred = AutomationPredicate.button; 299 pred = AutomationPredicate.button;
281 predErrorMsg = 'no_next_button'; 300 predErrorMsg = 'no_next_button';
282 break; 301 break;
283 case 'previousButton': 302 case 'previousButton':
284 dir = Dir.BACKWARD; 303 dir = Dir.BACKWARD;
285 pred = AutomationPredicate.button; 304 pred = AutomationPredicate.button;
286 predErrorMsg = 'no_previous_button'; 305 predErrorMsg = 'no_previous_button';
287 break; 306 break;
288 case 'nextCheckBox': 307 case 'nextCheckbox':
289 dir = Dir.FORWARD; 308 dir = Dir.FORWARD;
290 pred = AutomationPredicate.checkBox; 309 pred = AutomationPredicate.checkBox;
291 predErrorMsg = 'no_next_checkbox'; 310 predErrorMsg = 'no_next_checkbox';
292 break; 311 break;
293 case 'previousCheckBox': 312 case 'previousCheckbox':
294 dir = Dir.BACKWARD; 313 dir = Dir.BACKWARD;
295 pred = AutomationPredicate.checkBox; 314 pred = AutomationPredicate.checkBox;
296 predErrorMsg = 'no_previous_checkbox'; 315 predErrorMsg = 'no_previous_checkbox';
297 break; 316 break;
298 case 'nextComboBox': 317 case 'nextComboBox':
299 dir = Dir.FORWARD; 318 dir = Dir.FORWARD;
300 pred = AutomationPredicate.comboBox; 319 pred = AutomationPredicate.comboBox;
301 predErrorMsg = 'no_next_combo_box'; 320 predErrorMsg = 'no_next_combo_box';
302 break; 321 break;
303 case 'previousComboBox': 322 case 'previousComboBox':
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 dir = Dir.FORWARD; 378 dir = Dir.FORWARD;
360 pred = AutomationPredicate.visitedLink; 379 pred = AutomationPredicate.visitedLink;
361 predErrorMsg = 'no_next_visited_link'; 380 predErrorMsg = 'no_next_visited_link';
362 break; 381 break;
363 case 'previousVisitedLink': 382 case 'previousVisitedLink':
364 dir = Dir.BACKWARD; 383 dir = Dir.BACKWARD;
365 pred = AutomationPredicate.visitedLink; 384 pred = AutomationPredicate.visitedLink;
366 predErrorMsg = 'no_previous_visited_link'; 385 predErrorMsg = 'no_previous_visited_link';
367 break; 386 break;
368 case 'right': 387 case 'right':
369 case 'nextElement': 388 case 'nextObject':
370 current = current.move(cursors.Unit.DOM_NODE, Dir.FORWARD); 389 current = current.move(cursors.Unit.DOM_NODE, Dir.FORWARD);
371 break; 390 break;
372 case 'left': 391 case 'left':
373 case 'previousElement': 392 case 'previousObject':
374 current = current.move(cursors.Unit.DOM_NODE, Dir.BACKWARD); 393 current = current.move(cursors.Unit.DOM_NODE, Dir.BACKWARD);
375 break; 394 break;
376 case 'goToBeginning': 395 case 'jumpToTop':
David Tseng 2016/01/12 19:24:42 goToEnd/jumpToBottom as well?
dmazzoni 2016/01/13 23:26:39 Done.
377 var node = 396 var node =
378 AutomationUtil.findNodePost(current.start.node.root, 397 AutomationUtil.findNodePost(current.start.node.root,
379 Dir.FORWARD, 398 Dir.FORWARD,
380 AutomationPredicate.leaf); 399 AutomationPredicate.leaf);
381 if (node) 400 if (node)
382 current = cursors.Range.fromNode(node); 401 current = cursors.Range.fromNode(node);
383 break; 402 break;
384 case 'goToEnd': 403 case 'goToEnd':
385 var node = 404 var node =
386 AutomationUtil.findNodePost(current.start.node.root, 405 AutomationUtil.findNodePost(current.start.node.root,
387 Dir.BACKWARD, 406 Dir.BACKWARD,
388 AutomationPredicate.leaf); 407 AutomationPredicate.leaf);
389 if (node) 408 if (node)
390 current = cursors.Range.fromNode(node); 409 current = cursors.Range.fromNode(node);
391 break; 410 break;
392 case 'forceClickOnCurrentItem': 411 case 'forceClickOnCurrentItem':
393 case 'doDefault': 412 case 'performDefaultAction':
394 if (this.currentRange_) { 413 if (this.currentRange_) {
395 var actionNode = this.currentRange_.start.node; 414 var actionNode = this.currentRange_.start.node;
396 if (actionNode.role == RoleType.inlineTextBox) 415 if (actionNode.role == RoleType.inlineTextBox)
397 actionNode = actionNode.parent; 416 actionNode = actionNode.parent;
398 actionNode.doDefault(); 417 actionNode.doDefault();
399 } 418 }
400 // Skip all other processing; if focus changes, we should get an event 419 // Skip all other processing; if focus changes, we should get an event
401 // for that. 420 // for that.
402 return false; 421 return false;
403 case 'continuousRead': 422 case 'readFromHere':
404 global.isReadingContinuously = true; 423 global.isReadingContinuously = true;
405 var continueReading = function(prevRange) { 424 var continueReading = function(prevRange) {
406 if (!global.isReadingContinuously || !this.currentRange_) 425 if (!global.isReadingContinuously || !this.currentRange_)
407 return; 426 return;
408 427
409 new Output().withSpeechAndBraille( 428 new Output().withSpeechAndBraille(
410 this.currentRange_, prevRange, Output.EventType.NAVIGATE) 429 this.currentRange_, prevRange, Output.EventType.NAVIGATE)
411 .onSpeechEnd(function() { continueReading(prevRange); }) 430 .onSpeechEnd(function() { continueReading(prevRange); })
412 .go(); 431 .go();
413 prevRange = this.currentRange_; 432 prevRange = this.currentRange_;
414 this.setCurrentRange( 433 this.setCurrentRange(
415 this.currentRange_.move(cursors.Unit.NODE, Dir.FORWARD)); 434 this.currentRange_.move(cursors.Unit.NODE, Dir.FORWARD));
416 435
417 if (!this.currentRange_ || this.currentRange_.equals(prevRange)) 436 if (!this.currentRange_ || this.currentRange_.equals(prevRange))
418 global.isReadingContinuously = false; 437 global.isReadingContinuously = false;
419 }.bind(this); 438 }.bind(this);
420 439
421 continueReading(null); 440 continueReading(null);
422 return false; 441 return false;
423 case 'showContextMenu': 442 case 'contextMenu':
424 if (this.currentRange_) { 443 if (this.currentRange_) {
425 var actionNode = this.currentRange_.start.node; 444 var actionNode = this.currentRange_.start.node;
426 if (actionNode.role == RoleType.inlineTextBox) 445 if (actionNode.role == RoleType.inlineTextBox)
427 actionNode = actionNode.parent; 446 actionNode = actionNode.parent;
428 actionNode.showContextMenu(); 447 actionNode.showContextMenu();
429 return false; 448 return false;
430 } 449 }
431 break; 450 break;
432 case 'showOptionsPage': 451 case 'showOptionsPage':
433 chrome.runtime.openOptionsPage(); 452 chrome.runtime.openOptionsPage();
(...skipping 23 matching lines...) Expand all
457 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; 476 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT;
458 477
459 // Leaving unlocalized as 'next' isn't an official name. 478 // Leaving unlocalized as 'next' isn't an official name.
460 cvox.ChromeVox.tts.speak(isClassic ? 479 cvox.ChromeVox.tts.speak(isClassic ?
461 'classic' : 'next', cvox.QueueMode.FLUSH, {doNotInterrupt: true}); 480 'classic' : 'next', cvox.QueueMode.FLUSH, {doNotInterrupt: true});
462 break; 481 break;
463 case 'toggleStickyMode': 482 case 'toggleStickyMode':
464 cvox.ChromeVoxBackground.setPref('sticky', 483 cvox.ChromeVoxBackground.setPref('sticky',
465 !cvox.ChromeVox.isStickyPrefOn, 484 !cvox.ChromeVox.isStickyPrefOn,
466 true); 485 true);
486 case 'openChromeVoxMenus':
487 (new PanelCommand(PanelCommandType.OPEN_MENUS)).send();
488 break;
489 case 'decreaseTtsRate':
490 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, false);
491 break;
492 case 'increaseTtsRate':
493 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, true);
494 break;
495 case 'decreaseTtsPitch':
496 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, false);
497 break;
498 case 'increaseTtsPitch':
499 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, true);
500 break;
501 case 'decreaseTtsVolume':
502 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, false);
503 break;
504 case 'increaseTtsVolume':
505 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, true);
467 break; 506 break;
468 default: 507 default:
469 return true; 508 return true;
470 } 509 }
471 510
472 if (pred) { 511 if (pred) {
473 var node = AutomationUtil.findNextNode( 512 var node = AutomationUtil.findNextNode(
474 current.getBound(dir).node, dir, pred); 513 current.getBound(dir).node, dir, pred);
475 514
476 if (node) { 515 if (node) {
477 current = cursors.Range.fromNode(node); 516 current = cursors.Range.fromNode(node);
478 } else { 517 } else {
479 if (predErrorMsg) { 518 if (predErrorMsg) {
480 cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg), 519 cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg),
481 cvox.QueueMode.FLUSH); 520 cvox.QueueMode.FLUSH);
482 } 521 }
483 return false; 522 return false;
484 } 523 }
485 } 524 }
486 525
487 if (current) { 526 if (current)
488 // TODO(dtseng): Figure out what it means to focus a range. 527 this.navigateToRange_(current);
489 var actionNode = current.start.node;
490 if (actionNode.role == RoleType.inlineTextBox)
491 actionNode = actionNode.parent;
492 actionNode.focus();
493
494 var prevRange = this.currentRange_;
495 this.setCurrentRange(current);
496
497 new Output().withSpeechAndBraille(
498 this.currentRange_, prevRange, Output.EventType.NAVIGATE)
499 .withQueueMode(cvox.QueueMode.FLUSH)
500 .go();
501 }
502 528
503 return false; 529 return false;
504 }, 530 },
505 531
506 /** 532 /**
533 * Increase or decrease a speech property and make an announcement.
534 * @param {string} propertyName The name of the property to change.
535 * @param {boolean} increase If true, increases the property value by one
536 * step size, otherwise decreases.
537 */
538 increaseOrDecreaseSpeechProperty_: function(propertyName, increase) {
539 cvox.ChromeVox.tts.increaseOrDecreaseProperty(propertyName, increase);
540 var announcement;
541 var valueAsPercent = Math.round(
542 cvox.ChromeVox.tts.propertyToPercentage(propertyName) * 100);
543 switch (propertyName) {
544 case cvox.AbstractTts.RATE:
545 announcement = Msgs.getMsg('announce_rate', [valueAsPercent]);
546 break;
547 case cvox.AbstractTts.PITCH:
548 announcement = Msgs.getMsg('announce_pitch', [valueAsPercent]);
549 break;
550 case cvox.AbstractTts.VOLUME:
551 announcement = Msgs.getMsg('announce_volume', [valueAsPercent]);
552 break;
553 }
554 if (announcement) {
555 cvox.ChromeVox.tts.speak(
556 announcement, cvox.QueueMode.FLUSH,
557 cvox.AbstractTts.PERSONALITY_ANNOTATION);
558 }
559 },
560
561 /**
562 * Navigate to the given range - it both sets the range and outputs it.
563 * @param {!cursors.Range} range The new range.
564 * @private
565 */
566 navigateToRange_: function(range) {
567 // TODO(dtseng): Figure out what it means to focus a range.
568 var actionNode = range.start.node;
569 if (actionNode.role == RoleType.inlineTextBox)
570 actionNode = actionNode.parent;
571 actionNode.focus();
572
573 var prevRange = this.currentRange_;
574 this.setCurrentRange(range);
575
576 new Output().withSpeechAndBraille(
577 range, prevRange, Output.EventType.NAVIGATE).go();
578 },
579
580 /**
507 * Handles key down events. 581 * Handles key down events.
508 * @param {Event} evt The key down event to process. 582 * @param {Event} evt The key down event to process.
509 * @return {boolean} True if the default action should be performed. 583 * @return {boolean} True if the default action should be performed.
510 */ 584 */
511 onKeyDown: function(evt) { 585 onKeyDown: function(evt) {
512 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; 586 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive;
513 if (this.mode_ != ChromeVoxMode.CLASSIC && 587 if (this.mode_ != ChromeVoxMode.CLASSIC &&
514 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { 588 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) {
515 evt.preventDefault(); 589 evt.preventDefault();
516 evt.stopPropagation(); 590 evt.stopPropagation();
(...skipping 15 matching lines...) Expand all
532 * @param {!cvox.BrailleKeyEvent} evt 606 * @param {!cvox.BrailleKeyEvent} evt
533 * @param {!cvox.NavBraille} content 607 * @param {!cvox.NavBraille} content
534 * @return {boolean} True if evt was processed. 608 * @return {boolean} True if evt was processed.
535 */ 609 */
536 onBrailleKeyEvent: function(evt, content) { 610 onBrailleKeyEvent: function(evt, content) {
537 if (this.mode_ === ChromeVoxMode.CLASSIC) 611 if (this.mode_ === ChromeVoxMode.CLASSIC)
538 return false; 612 return false;
539 613
540 switch (evt.command) { 614 switch (evt.command) {
541 case cvox.BrailleKeyCommand.PAN_LEFT: 615 case cvox.BrailleKeyCommand.PAN_LEFT:
542 this.onGotCommand('previousElement'); 616 this.onGotCommand('previousObject');
543 break; 617 break;
544 case cvox.BrailleKeyCommand.PAN_RIGHT: 618 case cvox.BrailleKeyCommand.PAN_RIGHT:
545 this.onGotCommand('nextElement'); 619 this.onGotCommand('nextObject');
546 break; 620 break;
547 case cvox.BrailleKeyCommand.LINE_UP: 621 case cvox.BrailleKeyCommand.LINE_UP:
548 this.onGotCommand('previousLine'); 622 this.onGotCommand('previousLine');
549 break; 623 break;
550 case cvox.BrailleKeyCommand.LINE_DOWN: 624 case cvox.BrailleKeyCommand.LINE_DOWN:
551 this.onGotCommand('nextLine'); 625 this.onGotCommand('nextLine');
552 break; 626 break;
553 case cvox.BrailleKeyCommand.TOP: 627 case cvox.BrailleKeyCommand.TOP:
554 this.onGotCommand('goToBeginning'); 628 this.onGotCommand('jumpToTop');
555 break; 629 break;
556 case cvox.BrailleKeyCommand.BOTTOM: 630 case cvox.BrailleKeyCommand.BOTTOM:
557 this.onGotCommand('goToEnd'); 631 this.onGotCommand('jumpToBottom');
558 break; 632 break;
559 case cvox.BrailleKeyCommand.ROUTING: 633 case cvox.BrailleKeyCommand.ROUTING:
560 this.brailleRoutingCommand_( 634 this.brailleRoutingCommand_(
561 content.text, 635 content.text,
562 // Cast ok since displayPosition is always defined in this case. 636 // Cast ok since displayPosition is always defined in this case.
563 /** @type {number} */ (evt.displayPosition)); 637 /** @type {number} */ (evt.displayPosition));
564 break; 638 break;
565 default: 639 default:
566 return false; 640 return false;
567 } 641 }
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 if (action == 'getIsClassicEnabled') { 727 if (action == 'getIsClassicEnabled') {
654 var url = msg['url']; 728 var url = msg['url'];
655 var isClassicEnabled = this.shouldEnableClassicForUrl_(url); 729 var isClassicEnabled = this.shouldEnableClassicForUrl_(url);
656 port.postMessage({ 730 port.postMessage({
657 target: 'next', 731 target: 'next',
658 isClassicEnabled: isClassicEnabled 732 isClassicEnabled: isClassicEnabled
659 }); 733 });
660 } 734 }
661 break; 735 break;
662 } 736 }
663 } 737 },
738
739 /**
740 * Restore the range to the last range that was *not* in the ChromeVox
741 * panel. This is used when the ChromeVox Panel closes.
742 */
743 restoreCurrentRange: function() {
744 if (this.savedRange_) {
745 var containingWebView = this.savedRange_.start.node;
746 while (containingWebView && containingWebView.role != RoleType.webView) {
747 containingWebView = containingWebView.parent;
748 }
David Tseng 2016/01/12 20:10:57 nit: remove braces
dmazzoni 2016/01/13 23:26:39 Done.
749 if (containingWebView)
750 containingWebView.focus();
David Tseng 2016/01/12 20:10:57 Does this restore focus properly? What if savedRan
dmazzoni 2016/01/13 23:26:39 It's okay to call focus() on a dead node, it's a n
751
752 this.navigateToRange_(this.savedRange_);
753 this.savedRange_ = null;
754 }
755 },
664 }; 756 };
665 757
666 /** 758 /**
667 * Converts a list of globs, as used in the extension manifest, to a regular 759 * Converts a list of globs, as used in the extension manifest, to a regular
668 * expression that matches if and only if any of the globs in the list matches. 760 * expression that matches if and only if any of the globs in the list matches.
669 * @param {!Array<string>} globs 761 * @param {!Array<string>} globs
670 * @return {!RegExp} 762 * @return {!RegExp}
671 * @private 763 * @private
672 */ 764 */
673 Background.globsToRegExp_ = function(globs) { 765 Background.globsToRegExp_ = function(globs) {
674 return new RegExp('^(' + globs.map(function(glob) { 766 return new RegExp('^(' + globs.map(function(glob) {
675 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') 767 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&')
676 .replace(/\*/g, '.*') 768 .replace(/\*/g, '.*')
677 .replace(/\?/g, '.'); 769 .replace(/\?/g, '.');
678 }).join('|') + ')$'); 770 }).join('|') + ')$');
679 }; 771 };
680 772
681 /** @type {Background} */ 773 /** @type {Background} */
682 global.backgroundObj = new Background(); 774 global.backgroundObj = new Background();
683 775
684 }); // goog.scope 776 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698