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

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

Issue 1696443002: Re-land: Implement ChromeVox Next menus. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 }.bind(this)); 194 }.bind(this));
188 195
189 // If switching out of a ChromeVox Next mode, make sure we cancel 196 // If switching out of a ChromeVox Next mode, make sure we cancel
190 // the progress loading sound just in case. 197 // the progress loading sound just in case.
191 if ((this.mode_ === ChromeVoxMode.NEXT || 198 if ((this.mode_ === ChromeVoxMode.NEXT ||
192 this.mode_ === ChromeVoxMode.FORCE_NEXT) && 199 this.mode_ === ChromeVoxMode.FORCE_NEXT) &&
193 this.mode_ != mode) { 200 this.mode_ != mode) {
194 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); 201 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING);
195 } 202 }
196 203
204 if (mode === ChromeVoxMode.NEXT ||
205 mode === ChromeVoxMode.FORCE_NEXT) {
206 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send();
207 } else {
208 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send();
209 }
210
197 this.mode_ = mode; 211 this.mode_ = mode;
198 }, 212 },
199 213
200 /** 214 /**
201 * Mode refreshes takes into account both |url| and the current ChromeVox 215 * Mode refreshes takes into account both |url| and the current ChromeVox
202 * range. The latter gets used to decide if the user is or isn't in web 216 * range. The latter gets used to decide if the user is or isn't in web
203 * content. The focused state also needs to be set for this info to be 217 * content. The focused state also needs to be set for this info to be
204 * reliable. 218 * reliable.
205 * @override 219 * @override
206 */ 220 */
(...skipping 21 matching lines...) Expand all
228 return this.currentRange_; 242 return this.currentRange_;
229 }, 243 },
230 244
231 /** 245 /**
232 * @override 246 * @override
233 */ 247 */
234 setCurrentRange: function(newRange) { 248 setCurrentRange: function(newRange) {
235 if (!newRange) 249 if (!newRange)
236 return; 250 return;
237 251
252 var panelUrl = chrome.extension.getURL('cvox2/background/panel.html');
253 if (newRange.start.node.root.docUrl.indexOf(panelUrl) != 0)
254 this.savedRange_ = new cursors.Range(newRange.start, newRange.end);
255
238 this.currentRange_ = newRange; 256 this.currentRange_ = newRange;
239 257
240 if (this.currentRange_) 258 if (this.currentRange_)
241 this.currentRange_.start.node.makeVisible(); 259 this.currentRange_.start.node.makeVisible();
242 }, 260 },
243 261
244 /** Forces ChromeVox Next to be active for all tabs. */ 262 /** Forces ChromeVox Next to be active for all tabs. */
245 forceChromeVoxNextActive: function() { 263 forceChromeVoxNextActive: function() {
246 this.setMode(ChromeVoxMode.FORCE_NEXT); 264 this.setMode(ChromeVoxMode.FORCE_NEXT);
247 }, 265 },
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 case 'nextButton': 306 case 'nextButton':
289 dir = Dir.FORWARD; 307 dir = Dir.FORWARD;
290 pred = AutomationPredicate.button; 308 pred = AutomationPredicate.button;
291 predErrorMsg = 'no_next_button'; 309 predErrorMsg = 'no_next_button';
292 break; 310 break;
293 case 'previousButton': 311 case 'previousButton':
294 dir = Dir.BACKWARD; 312 dir = Dir.BACKWARD;
295 pred = AutomationPredicate.button; 313 pred = AutomationPredicate.button;
296 predErrorMsg = 'no_previous_button'; 314 predErrorMsg = 'no_previous_button';
297 break; 315 break;
298 case 'nextCheckBox': 316 case 'nextCheckbox':
299 dir = Dir.FORWARD; 317 dir = Dir.FORWARD;
300 pred = AutomationPredicate.checkBox; 318 pred = AutomationPredicate.checkBox;
301 predErrorMsg = 'no_next_checkbox'; 319 predErrorMsg = 'no_next_checkbox';
302 break; 320 break;
303 case 'previousCheckBox': 321 case 'previousCheckbox':
304 dir = Dir.BACKWARD; 322 dir = Dir.BACKWARD;
305 pred = AutomationPredicate.checkBox; 323 pred = AutomationPredicate.checkBox;
306 predErrorMsg = 'no_previous_checkbox'; 324 predErrorMsg = 'no_previous_checkbox';
307 break; 325 break;
308 case 'nextComboBox': 326 case 'nextComboBox':
309 dir = Dir.FORWARD; 327 dir = Dir.FORWARD;
310 pred = AutomationPredicate.comboBox; 328 pred = AutomationPredicate.comboBox;
311 predErrorMsg = 'no_next_combo_box'; 329 predErrorMsg = 'no_next_combo_box';
312 break; 330 break;
313 case 'previousComboBox': 331 case 'previousComboBox':
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 dir = Dir.FORWARD; 387 dir = Dir.FORWARD;
370 pred = AutomationPredicate.visitedLink; 388 pred = AutomationPredicate.visitedLink;
371 predErrorMsg = 'no_next_visited_link'; 389 predErrorMsg = 'no_next_visited_link';
372 break; 390 break;
373 case 'previousVisitedLink': 391 case 'previousVisitedLink':
374 dir = Dir.BACKWARD; 392 dir = Dir.BACKWARD;
375 pred = AutomationPredicate.visitedLink; 393 pred = AutomationPredicate.visitedLink;
376 predErrorMsg = 'no_previous_visited_link'; 394 predErrorMsg = 'no_previous_visited_link';
377 break; 395 break;
378 case 'right': 396 case 'right':
379 case 'nextElement': 397 case 'nextObject':
380 current = current.move(cursors.Unit.DOM_NODE, Dir.FORWARD); 398 current = current.move(cursors.Unit.DOM_NODE, Dir.FORWARD);
381 break; 399 break;
382 case 'left': 400 case 'left':
383 case 'previousElement': 401 case 'previousObject':
384 current = current.move(cursors.Unit.DOM_NODE, Dir.BACKWARD); 402 current = current.move(cursors.Unit.DOM_NODE, Dir.BACKWARD);
385 break; 403 break;
386 case 'goToBeginning': 404 case 'jumpToTop':
387 var node = 405 var node =
388 AutomationUtil.findNodePost(current.start.node.root, 406 AutomationUtil.findNodePost(current.start.node.root,
389 Dir.FORWARD, 407 Dir.FORWARD,
390 AutomationPredicate.leaf); 408 AutomationPredicate.leaf);
391 if (node) 409 if (node)
392 current = cursors.Range.fromNode(node); 410 current = cursors.Range.fromNode(node);
393 break; 411 break;
394 case 'goToEnd': 412 case 'jumpToBottom':
395 var node = 413 var node =
396 AutomationUtil.findNodePost(current.start.node.root, 414 AutomationUtil.findNodePost(current.start.node.root,
397 Dir.BACKWARD, 415 Dir.BACKWARD,
398 AutomationPredicate.leaf); 416 AutomationPredicate.leaf);
399 if (node) 417 if (node)
400 current = cursors.Range.fromNode(node); 418 current = cursors.Range.fromNode(node);
401 break; 419 break;
402 case 'forceClickOnCurrentItem': 420 case 'forceClickOnCurrentItem':
403 case 'doDefault': 421 case 'performDefaultAction':
404 if (this.currentRange_) { 422 if (this.currentRange_) {
405 var actionNode = this.currentRange_.start.node; 423 var actionNode = this.currentRange_.start.node;
406 if (actionNode.role == RoleType.inlineTextBox) 424 if (actionNode.role == RoleType.inlineTextBox)
407 actionNode = actionNode.parent; 425 actionNode = actionNode.parent;
408 actionNode.doDefault(); 426 actionNode.doDefault();
409 } 427 }
410 // Skip all other processing; if focus changes, we should get an event 428 // Skip all other processing; if focus changes, we should get an event
411 // for that. 429 // for that.
412 return false; 430 return false;
413 case 'continuousRead': 431 case 'readFromHere':
414 global.isReadingContinuously = true; 432 global.isReadingContinuously = true;
415 var continueReading = function() { 433 var continueReading = function() {
416 if (!global.isReadingContinuously || !this.currentRange_) 434 if (!global.isReadingContinuously || !this.currentRange_)
417 return; 435 return;
418 436
419 var prevRange = this.currentRange_; 437 var prevRange = this.currentRange_;
420 var newRange = 438 var newRange =
421 this.currentRange_.move(cursors.Unit.DOM_NODE, Dir.FORWARD); 439 this.currentRange_.move(cursors.Unit.DOM_NODE, Dir.FORWARD);
422 440
423 // Stop if we've wrapped back to the document. 441 // Stop if we've wrapped back to the document.
(...skipping 11 matching lines...) Expand all
435 .onSpeechEnd(continueReading) 453 .onSpeechEnd(continueReading)
436 .go(); 454 .go();
437 }.bind(this); 455 }.bind(this);
438 456
439 new Output().withSpeechAndBraille( 457 new Output().withSpeechAndBraille(
440 this.currentRange_, null, Output.EventType.NAVIGATE) 458 this.currentRange_, null, Output.EventType.NAVIGATE)
441 .onSpeechEnd(continueReading) 459 .onSpeechEnd(continueReading)
442 .go(); 460 .go();
443 461
444 return false; 462 return false;
445 case 'showContextMenu': 463 case 'contextMenu':
446 if (this.currentRange_) { 464 if (this.currentRange_) {
447 var actionNode = this.currentRange_.start.node; 465 var actionNode = this.currentRange_.start.node;
448 if (actionNode.role == RoleType.inlineTextBox) 466 if (actionNode.role == RoleType.inlineTextBox)
449 actionNode = actionNode.parent; 467 actionNode = actionNode.parent;
450 actionNode.showContextMenu(); 468 actionNode.showContextMenu();
451 return false; 469 return false;
452 } 470 }
453 break; 471 break;
454 case 'showOptionsPage': 472 case 'showOptionsPage':
455 chrome.runtime.openOptionsPage(); 473 chrome.runtime.openOptionsPage();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 if (cvox.ChromeVox.isStickyPrefOn) 508 if (cvox.ChromeVox.isStickyPrefOn)
491 chrome.accessibilityPrivate.setKeyboardListener(true, true); 509 chrome.accessibilityPrivate.setKeyboardListener(true, true);
492 else 510 else
493 chrome.accessibilityPrivate.setKeyboardListener(true, false); 511 chrome.accessibilityPrivate.setKeyboardListener(true, false);
494 return false; 512 return false;
495 case 'passThroughMode': 513 case 'passThroughMode':
496 cvox.ChromeVox.passThroughMode = true; 514 cvox.ChromeVox.passThroughMode = true;
497 cvox.ChromeVox.tts.speak( 515 cvox.ChromeVox.tts.speak(
498 Msgs.getMsg('pass_through_key'), cvox.QueueMode.QUEUE); 516 Msgs.getMsg('pass_through_key'), cvox.QueueMode.QUEUE);
499 return true; 517 return true;
518 case 'openChromeVoxMenus':
519 (new PanelCommand(PanelCommandType.OPEN_MENUS)).send();
520 break;
521 case 'decreaseTtsRate':
522 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, false);
523 break;
524 case 'increaseTtsRate':
525 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.RATE, true);
526 break;
527 case 'decreaseTtsPitch':
528 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, false);
529 break;
530 case 'increaseTtsPitch':
531 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.PITCH, true);
532 break;
533 case 'decreaseTtsVolume':
534 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, false);
535 break;
536 case 'increaseTtsVolume':
537 this.increaseOrDecreaseSpeechProperty_(cvox.AbstractTts.VOLUME, true);
538 break;
500 default: 539 default:
501 return true; 540 return true;
502 } 541 }
503 542
504 if (pred) { 543 if (pred) {
505 var node = AutomationUtil.findNextNode( 544 var node = AutomationUtil.findNextNode(
506 current.getBound(dir).node, dir, pred); 545 current.getBound(dir).node, dir, pred);
507 546
508 if (node) { 547 if (node) {
509 current = cursors.Range.fromNode(node); 548 current = cursors.Range.fromNode(node);
510 } else { 549 } else {
511 if (predErrorMsg) { 550 if (predErrorMsg) {
512 cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg), 551 cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg),
513 cvox.QueueMode.FLUSH); 552 cvox.QueueMode.FLUSH);
514 } 553 }
515 return false; 554 return false;
516 } 555 }
517 } 556 }
518 557
519 if (current) { 558 if (current)
520 // TODO(dtseng): Figure out what it means to focus a range. 559 this.navigateToRange_(current);
521 var actionNode = current.start.node;
522 if (actionNode.role == RoleType.inlineTextBox)
523 actionNode = actionNode.parent;
524
525 // Iframes, when focused, causes the child webArea to fire focus event.
526 // This can result in getting stuck when navigating backward.
527 if (actionNode.role != RoleType.iframe && !actionNode.state.focused)
528 actionNode.focus();
529
530 var prevRange = this.currentRange_;
531 this.setCurrentRange(current);
532
533 new Output().withSpeechAndBraille(
534 this.currentRange_, prevRange, Output.EventType.NAVIGATE)
535 .withQueueMode(cvox.QueueMode.FLUSH)
536 .go();
537 }
538 560
539 return false; 561 return false;
540 }, 562 },
541 563
542 /** 564 /**
565 * Increase or decrease a speech property and make an announcement.
566 * @param {string} propertyName The name of the property to change.
567 * @param {boolean} increase If true, increases the property value by one
568 * step size, otherwise decreases.
569 */
570 increaseOrDecreaseSpeechProperty_: function(propertyName, increase) {
571 cvox.ChromeVox.tts.increaseOrDecreaseProperty(propertyName, increase);
572 var announcement;
573 var valueAsPercent = Math.round(
574 cvox.ChromeVox.tts.propertyToPercentage(propertyName) * 100);
575 switch (propertyName) {
576 case cvox.AbstractTts.RATE:
577 announcement = Msgs.getMsg('announce_rate', [valueAsPercent]);
578 break;
579 case cvox.AbstractTts.PITCH:
580 announcement = Msgs.getMsg('announce_pitch', [valueAsPercent]);
581 break;
582 case cvox.AbstractTts.VOLUME:
583 announcement = Msgs.getMsg('announce_volume', [valueAsPercent]);
584 break;
585 }
586 if (announcement) {
587 cvox.ChromeVox.tts.speak(
588 announcement, cvox.QueueMode.FLUSH,
589 cvox.AbstractTts.PERSONALITY_ANNOTATION);
590 }
591 },
592
593 /**
594 * Navigate to the given range - it both sets the range and outputs it.
595 * @param {!cursors.Range} range The new range.
596 * @private
597 */
598 navigateToRange_: function(range) {
599 // TODO(dtseng): Figure out what it means to focus a range.
600 var actionNode = range.start.node;
601 if (actionNode.role == RoleType.inlineTextBox)
602 actionNode = actionNode.parent;
603
604 // Iframes, when focused, causes the child webArea to fire focus event.
605 // This can result in getting stuck when navigating backward.
606 if (actionNode.role != RoleType.iframe && !actionNode.state.focused)
607 actionNode.focus();
608
609 var prevRange = this.currentRange_;
610 this.setCurrentRange(range);
611
612 new Output().withSpeechAndBraille(
613 range, prevRange, Output.EventType.NAVIGATE)
614 .withQueueMode(cvox.QueueMode.FLUSH)
615 .go();
616 },
617
618 /**
543 * Handles key down events. 619 * Handles key down events.
544 * @param {Event} evt The key down event to process. 620 * @param {Event} evt The key down event to process.
545 * @return {boolean} True if the default action should be performed. 621 * @return {boolean} True if the default action should be performed.
546 */ 622 */
547 onKeyDown: function(evt) { 623 onKeyDown: function(evt) {
548 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; 624 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive;
549 if (cvox.ChromeVox.passThroughMode) 625 if (cvox.ChromeVox.passThroughMode)
550 return false; 626 return false;
551 627
552 if (this.mode_ != ChromeVoxMode.CLASSIC && 628 if (this.mode_ != ChromeVoxMode.CLASSIC &&
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 * @param {!cvox.BrailleKeyEvent} evt 666 * @param {!cvox.BrailleKeyEvent} evt
591 * @param {!cvox.NavBraille} content 667 * @param {!cvox.NavBraille} content
592 * @return {boolean} True if evt was processed. 668 * @return {boolean} True if evt was processed.
593 */ 669 */
594 onBrailleKeyEvent: function(evt, content) { 670 onBrailleKeyEvent: function(evt, content) {
595 if (this.mode_ === ChromeVoxMode.CLASSIC) 671 if (this.mode_ === ChromeVoxMode.CLASSIC)
596 return false; 672 return false;
597 673
598 switch (evt.command) { 674 switch (evt.command) {
599 case cvox.BrailleKeyCommand.PAN_LEFT: 675 case cvox.BrailleKeyCommand.PAN_LEFT:
600 this.onGotCommand('previousElement'); 676 this.onGotCommand('previousObject');
601 break; 677 break;
602 case cvox.BrailleKeyCommand.PAN_RIGHT: 678 case cvox.BrailleKeyCommand.PAN_RIGHT:
603 this.onGotCommand('nextElement'); 679 this.onGotCommand('nextObject');
604 break; 680 break;
605 case cvox.BrailleKeyCommand.LINE_UP: 681 case cvox.BrailleKeyCommand.LINE_UP:
606 this.onGotCommand('previousLine'); 682 this.onGotCommand('previousLine');
607 break; 683 break;
608 case cvox.BrailleKeyCommand.LINE_DOWN: 684 case cvox.BrailleKeyCommand.LINE_DOWN:
609 this.onGotCommand('nextLine'); 685 this.onGotCommand('nextLine');
610 break; 686 break;
611 case cvox.BrailleKeyCommand.TOP: 687 case cvox.BrailleKeyCommand.TOP:
612 this.onGotCommand('goToBeginning'); 688 this.onGotCommand('jumpToTop');
613 break; 689 break;
614 case cvox.BrailleKeyCommand.BOTTOM: 690 case cvox.BrailleKeyCommand.BOTTOM:
615 this.onGotCommand('goToEnd'); 691 this.onGotCommand('jumpToBottom');
616 break; 692 break;
617 case cvox.BrailleKeyCommand.ROUTING: 693 case cvox.BrailleKeyCommand.ROUTING:
618 this.brailleRoutingCommand_( 694 this.brailleRoutingCommand_(
619 content.text, 695 content.text,
620 // Cast ok since displayPosition is always defined in this case. 696 // Cast ok since displayPosition is always defined in this case.
621 /** @type {number} */ (evt.displayPosition)); 697 /** @type {number} */ (evt.displayPosition));
622 break; 698 break;
623 default: 699 default:
624 return false; 700 return false;
625 } 701 }
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 target: 'next', 792 target: 'next',
717 isClassicEnabled: isClassicEnabled 793 isClassicEnabled: isClassicEnabled
718 }); 794 });
719 } else if (action == 'onCommand') { 795 } else if (action == 'onCommand') {
720 this.onGotCommand(msg['command']); 796 this.onGotCommand(msg['command']);
721 } else if (action == 'flushNextUtterance') { 797 } else if (action == 'flushNextUtterance') {
722 Output.flushNextSpeechUtterance(); 798 Output.flushNextSpeechUtterance();
723 } 799 }
724 break; 800 break;
725 } 801 }
726 } 802 },
803
804 /**
805 * Restore the range to the last range that was *not* in the ChromeVox
806 * panel. This is used when the ChromeVox Panel closes.
807 */
808 restoreCurrentRange: function() {
809 if (this.savedRange_) {
810 var containingWebView = this.savedRange_.start.node;
811 while (containingWebView && containingWebView.role != RoleType.webView)
812 containingWebView = containingWebView.parent;
813 if (containingWebView)
814 containingWebView.focus();
815
816 this.navigateToRange_(this.savedRange_);
817 this.savedRange_ = null;
818 }
819 },
727 }; 820 };
728 821
729 /** 822 /**
730 * Converts a list of globs, as used in the extension manifest, to a regular 823 * Converts a list of globs, as used in the extension manifest, to a regular
731 * expression that matches if and only if any of the globs in the list matches. 824 * expression that matches if and only if any of the globs in the list matches.
732 * @param {!Array<string>} globs 825 * @param {!Array<string>} globs
733 * @return {!RegExp} 826 * @return {!RegExp}
734 * @private 827 * @private
735 */ 828 */
736 Background.globsToRegExp_ = function(globs) { 829 Background.globsToRegExp_ = function(globs) {
737 return new RegExp('^(' + globs.map(function(glob) { 830 return new RegExp('^(' + globs.map(function(glob) {
738 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') 831 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&')
739 .replace(/\*/g, '.*') 832 .replace(/\*/g, '.*')
740 .replace(/\?/g, '.'); 833 .replace(/\?/g, '.');
741 }).join('|') + ')$'); 834 }).join('|') + ')$');
742 }; 835 };
743 836
744 /** @type {Background} */ 837 /** @type {Background} */
745 global.backgroundObj = new Background(); 838 global.backgroundObj = new Background();
746 839
747 }); // goog.scope 840 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698