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

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: 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 }
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':
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 cvox.ChromeVox.tts.increaseOrDecreaseProperty(
491 cvox.AbstractTts.RATE, false);
492 break;
David Tseng 2016/01/08 21:39:32 Needs to announce the percentage (same with all of
dmazzoni 2016/01/11 22:04:06 Done.
493 case 'increaseTtsRate':
494 cvox.ChromeVox.tts.increaseOrDecreaseProperty(
495 cvox.AbstractTts.RATE, true);
496 break;
497 case 'decreaseTtsPitch':
498 cvox.ChromeVox.tts.increaseOrDecreaseProperty(
499 cvox.AbstractTts.PITCH, false);
500 break;
501 case 'increaseTtsPitch':
502 cvox.ChromeVox.tts.increaseOrDecreaseProperty(
503 cvox.AbstractTts.PITCH, true);
504 break;
505 case 'decreaseTtsVolume':
506 cvox.ChromeVox.tts.increaseOrDecreaseProperty(
507 cvox.AbstractTts.VOLUME, false);
508 break;
509 case 'increaseTtsVolume':
510 cvox.ChromeVox.tts.increaseOrDecreaseProperty(
511 cvox.AbstractTts.VOLUME, true);
467 break; 512 break;
468 default: 513 default:
469 return true; 514 return true;
470 } 515 }
471 516
472 if (pred) { 517 if (pred) {
473 var node = AutomationUtil.findNextNode( 518 var node = AutomationUtil.findNextNode(
474 current.getBound(dir).node, dir, pred); 519 current.getBound(dir).node, dir, pred);
475 520
476 if (node) { 521 if (node) {
477 current = cursors.Range.fromNode(node); 522 current = cursors.Range.fromNode(node);
478 } else { 523 } else {
479 if (predErrorMsg) { 524 if (predErrorMsg) {
480 cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg), 525 cvox.ChromeVox.tts.speak(Msgs.getMsg(predErrorMsg),
481 cvox.QueueMode.FLUSH); 526 cvox.QueueMode.FLUSH);
482 } 527 }
483 return false; 528 return false;
484 } 529 }
485 } 530 }
486 531
487 if (current) { 532 if (current)
488 // TODO(dtseng): Figure out what it means to focus a range. 533 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 534
503 return false; 535 return false;
504 }, 536 },
505 537
506 /** 538 /**
539 * Navigate to the given range - it both sets the range and outputs it.
540 * @param {!cursors.Range} range The new range.
541 * @private
542 */
543 navigateToRange_: function(range) {
544 // TODO(dtseng): Figure out what it means to focus a range.
545 var actionNode = range.start.node;
546 if (actionNode.role == RoleType.inlineTextBox)
547 actionNode = actionNode.parent;
548 actionNode.focus();
549
550 var prevRange = this.currentRange_;
551 this.setCurrentRange(range);
552
553 new Output().withSpeechAndBraille(
554 range, prevRange, Output.EventType.NAVIGATE).go();
555 },
556
557 /**
507 * Handles key down events. 558 * Handles key down events.
508 * @param {Event} evt The key down event to process. 559 * @param {Event} evt The key down event to process.
509 * @return {boolean} True if the default action should be performed. 560 * @return {boolean} True if the default action should be performed.
510 */ 561 */
511 onKeyDown: function(evt) { 562 onKeyDown: function(evt) {
512 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive; 563 evt.stickyMode = cvox.ChromeVox.isStickyModeOn() && cvox.ChromeVox.isActive;
513 if (this.mode_ != ChromeVoxMode.CLASSIC && 564 if (this.mode_ != ChromeVoxMode.CLASSIC &&
514 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) { 565 !cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt)) {
515 evt.preventDefault(); 566 evt.preventDefault();
516 evt.stopPropagation(); 567 evt.stopPropagation();
(...skipping 15 matching lines...) Expand all
532 * @param {!cvox.BrailleKeyEvent} evt 583 * @param {!cvox.BrailleKeyEvent} evt
533 * @param {!cvox.NavBraille} content 584 * @param {!cvox.NavBraille} content
534 * @return {boolean} True if evt was processed. 585 * @return {boolean} True if evt was processed.
535 */ 586 */
536 onBrailleKeyEvent: function(evt, content) { 587 onBrailleKeyEvent: function(evt, content) {
537 if (this.mode_ === ChromeVoxMode.CLASSIC) 588 if (this.mode_ === ChromeVoxMode.CLASSIC)
538 return false; 589 return false;
539 590
540 switch (evt.command) { 591 switch (evt.command) {
541 case cvox.BrailleKeyCommand.PAN_LEFT: 592 case cvox.BrailleKeyCommand.PAN_LEFT:
542 this.onGotCommand('previousElement'); 593 this.onGotCommand('previousObject');
543 break; 594 break;
544 case cvox.BrailleKeyCommand.PAN_RIGHT: 595 case cvox.BrailleKeyCommand.PAN_RIGHT:
545 this.onGotCommand('nextElement'); 596 this.onGotCommand('nextObject');
546 break; 597 break;
547 case cvox.BrailleKeyCommand.LINE_UP: 598 case cvox.BrailleKeyCommand.LINE_UP:
548 this.onGotCommand('previousLine'); 599 this.onGotCommand('previousLine');
549 break; 600 break;
550 case cvox.BrailleKeyCommand.LINE_DOWN: 601 case cvox.BrailleKeyCommand.LINE_DOWN:
551 this.onGotCommand('nextLine'); 602 this.onGotCommand('nextLine');
552 break; 603 break;
553 case cvox.BrailleKeyCommand.TOP: 604 case cvox.BrailleKeyCommand.TOP:
554 this.onGotCommand('goToBeginning'); 605 this.onGotCommand('jumpToTop');
555 break; 606 break;
556 case cvox.BrailleKeyCommand.BOTTOM: 607 case cvox.BrailleKeyCommand.BOTTOM:
557 this.onGotCommand('goToEnd'); 608 this.onGotCommand('jumpToBottom');
558 break; 609 break;
559 case cvox.BrailleKeyCommand.ROUTING: 610 case cvox.BrailleKeyCommand.ROUTING:
560 this.brailleRoutingCommand_( 611 this.brailleRoutingCommand_(
561 content.text, 612 content.text,
562 // Cast ok since displayPosition is always defined in this case. 613 // Cast ok since displayPosition is always defined in this case.
563 /** @type {number} */ (evt.displayPosition)); 614 /** @type {number} */ (evt.displayPosition));
564 break; 615 break;
565 default: 616 default:
566 return false; 617 return false;
567 } 618 }
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 if (action == 'getIsClassicEnabled') { 704 if (action == 'getIsClassicEnabled') {
654 var url = msg['url']; 705 var url = msg['url'];
655 var isClassicEnabled = this.shouldEnableClassicForUrl_(url); 706 var isClassicEnabled = this.shouldEnableClassicForUrl_(url);
656 port.postMessage({ 707 port.postMessage({
657 target: 'next', 708 target: 'next',
658 isClassicEnabled: isClassicEnabled 709 isClassicEnabled: isClassicEnabled
659 }); 710 });
660 } 711 }
661 break; 712 break;
662 } 713 }
663 } 714 },
715
716 /**
717 *
David Tseng 2016/01/08 21:39:32 ?
dmazzoni 2016/01/11 22:04:06 Done.
718 */
719 restoreCurrentRange: function() {
720 if (this.savedRange_) {
721 var containingWindow = this.savedRange_.start.node;
David Tseng 2016/01/08 21:39:32 Rename to containingWebView?
dmazzoni 2016/01/11 22:04:06 Done.
722 while (containingWindow && containingWindow.role != RoleType.webView) {
723 containingWindow = containingWindow.parent;
724 }
725 if (containingWindow) {
David Tseng 2016/01/08 21:39:32 nit: remove braces
dmazzoni 2016/01/11 22:04:06 Done.
726 containingWindow.focus();
727 }
728
729 this.navigateToRange_(this.savedRange_);
730 this.savedRange_ = null;
731 }
732 },
664 }; 733 };
665 734
666 /** 735 /**
667 * Converts a list of globs, as used in the extension manifest, to a regular 736 * 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. 737 * expression that matches if and only if any of the globs in the list matches.
669 * @param {!Array<string>} globs 738 * @param {!Array<string>} globs
670 * @return {!RegExp} 739 * @return {!RegExp}
671 * @private 740 * @private
672 */ 741 */
673 Background.globsToRegExp_ = function(globs) { 742 Background.globsToRegExp_ = function(globs) {
674 return new RegExp('^(' + globs.map(function(glob) { 743 return new RegExp('^(' + globs.map(function(glob) {
675 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') 744 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&')
676 .replace(/\*/g, '.*') 745 .replace(/\*/g, '.*')
677 .replace(/\?/g, '.'); 746 .replace(/\?/g, '.');
678 }).join('|') + ')$'); 747 }).join('|') + ')$');
679 }; 748 };
680 749
681 /** @type {Background} */ 750 /** @type {Background} */
682 global.backgroundObj = new Background(); 751 global.backgroundObj = new Background();
683 752
684 }); // goog.scope 753 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698