Chromium Code Reviews| OLD | NEW |
|---|---|
| 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'); |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 /** @type {boolean} @private */ | 139 /** @type {boolean} @private */ |
| 140 this.inExcursion_ = false; | 140 this.inExcursion_ = false; |
| 141 | 141 |
| 142 if (!chrome.accessibilityPrivate.setKeyboardListener) | 142 if (!chrome.accessibilityPrivate.setKeyboardListener) |
| 143 chrome.accessibilityPrivate.setKeyboardListener = function() {}; | 143 chrome.accessibilityPrivate.setKeyboardListener = function() {}; |
| 144 | 144 |
| 145 if (cvox.ChromeVox.isChromeOS) { | 145 if (cvox.ChromeVox.isChromeOS) { |
| 146 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( | 146 chrome.accessibilityPrivate.onAccessibilityGesture.addListener( |
| 147 this.onAccessibilityGesture_); | 147 this.onAccessibilityGesture_); |
| 148 | 148 |
| 149 if (localStorage['mode']) { | |
| 150 var mode = localStorage['mode']; | |
| 151 this.setMode(mode); | |
| 152 } | |
| 153 | |
| 149 Notifications.onStartup(); | 154 Notifications.onStartup(); |
| 150 }}; | 155 }}; |
| 151 | 156 |
| 152 /** | 157 /** |
| 153 * @const {string} | 158 * @const {string} |
| 154 */ | 159 */ |
| 155 Background.ISSUE_URL = 'https://code.google.com/p/chromium/issues/entry?' + | 160 Background.ISSUE_URL = 'https://code.google.com/p/chromium/issues/entry?' + |
| 156 'labels=Type-Bug,Pri-2,cvox2,OS-Chrome&' + | 161 'labels=Type-Bug,Pri-2,cvox2,OS-Chrome&' + |
| 157 'components=UI>accessibility&' + | 162 'components=UI>accessibility&' + |
| 158 'description='; | 163 'description='; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 __proto__: ChromeVoxState.prototype, | 198 __proto__: ChromeVoxState.prototype, |
| 194 | 199 |
| 195 /** | 200 /** |
| 196 * @override | 201 * @override |
| 197 */ | 202 */ |
| 198 getMode: function() { | 203 getMode: function() { |
| 199 return this.mode_; | 204 return this.mode_; |
| 200 }, | 205 }, |
| 201 | 206 |
| 202 /** | 207 /** |
| 208 * This method sets the global mode for ChromeVox. | |
| 209 * The following transitions are supported: | |
| 210 * classic to force next | |
| 211 * compat to force next | |
| 212 * force next to classic | |
| 213 * force next to compat | |
| 203 * @override | 214 * @override |
| 204 */ | 215 */ |
| 205 setMode: function(mode, opt_injectClassic) { | 216 setMode: function(mode, opt_injectClassic) { |
| 217 var newMode = mode; | |
| 218 var oldMode = this.mode_; | |
| 219 this.mode_ = newMode; | |
| 220 localStorage['mode'] = mode; | |
|
dmazzoni
2016/06/20 19:49:03
Do you want to be setting the mode to things like
David Tseng
2016/06/20 22:31:08
Now only storing the "nextness" state.
| |
| 221 | |
| 206 // Switching key maps potentially affects the key codes that involve | 222 // Switching key maps potentially affects the key codes that involve |
| 207 // sequencing. Without resetting this list, potentially stale key codes | 223 // sequencing. Without resetting this list, potentially stale key codes |
| 208 // remain. The key codes themselves get pushed in | 224 // remain. The key codes themselves get pushed in |
| 209 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. | 225 // cvox.KeySequence.deserialize which gets called by cvox.KeyMap. |
| 210 cvox.ChromeVox.sequenceSwitchKeyCodes = []; | 226 cvox.ChromeVox.sequenceSwitchKeyCodes = []; |
| 211 if (mode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) | 227 if (window['prefs']) { |
| 212 window['prefs'].switchToKeyMap('keymap_classic'); | 228 if (newMode === ChromeVoxMode.CLASSIC || mode === ChromeVoxMode.COMPAT) |
| 213 else | 229 window['prefs'].switchToKeyMap('keymap_classic'); |
| 214 window['prefs'].switchToKeyMap('keymap_next'); | 230 else |
| 231 window['prefs'].switchToKeyMap('keymap_next'); | |
| 232 } | |
| 215 | 233 |
| 216 if (mode == ChromeVoxMode.CLASSIC) { | 234 if (newMode == ChromeVoxMode.CLASSIC) { |
| 217 if (chrome.commands && | 235 if (chrome.commands && |
| 218 chrome.commands.onCommand.hasListener(this.onGotCommand)) | 236 chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 219 chrome.commands.onCommand.removeListener(this.onGotCommand); | 237 chrome.commands.onCommand.removeListener(this.onGotCommand); |
| 220 chrome.accessibilityPrivate.setKeyboardListener(false, false); | 238 chrome.accessibilityPrivate.setKeyboardListener(false, false); |
| 221 } else { | 239 } else { |
| 222 if (chrome.commands && | 240 if (chrome.commands && |
| 223 !chrome.commands.onCommand.hasListener(this.onGotCommand)) | 241 !chrome.commands.onCommand.hasListener(this.onGotCommand)) |
| 224 chrome.commands.onCommand.addListener(this.onGotCommand); | 242 chrome.commands.onCommand.addListener(this.onGotCommand); |
| 225 chrome.accessibilityPrivate.setKeyboardListener( | 243 chrome.accessibilityPrivate.setKeyboardListener( |
| 226 true, cvox.ChromeVox.isStickyPrefOn); | 244 true, cvox.ChromeVox.isStickyPrefOn); |
| 227 } | 245 } |
| 228 | 246 |
| 229 // note that |this.currentRange_| can *change* because the request is | 247 // note that |this.currentRange_| can *change* because the request is |
| 230 // async. Save it to ensure we're looking at the currentRange at this moment | 248 // async. Save it to ensure we're looking at the currentRange at this moment |
| 231 // in time. | 249 // in time. |
| 232 var cur = this.currentRange_; | 250 var cur = this.currentRange_; |
| 233 chrome.tabs.query({active: true}, function(tabs) { | 251 chrome.tabs.query({active: true}, function(tabs) { |
| 234 if (mode === ChromeVoxMode.CLASSIC) { | 252 if (newMode === ChromeVoxMode.CLASSIC) { |
| 235 // Generally, we don't want to inject classic content scripts as it is | 253 // Generally, we don't want to inject classic content scripts as it is |
| 236 // done by the extension system at document load. The exception is when | 254 // done by the extension system at document load. The exception is when |
| 237 // we toggle classic on manually as part of a user command. | 255 // we toggle classic on manually as part of a user command. |
| 238 if (opt_injectClassic) | 256 if (opt_injectClassic) |
| 239 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); | 257 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
| 240 } else { | 258 } else { |
| 241 // When in compat mode, if the focus is within the desktop tree proper, | 259 // When in compat mode, if the focus is within the desktop tree proper, |
| 242 // then do not disable content scripts. | 260 // then do not disable content scripts. |
| 243 if (cur && !cur.isWebRange()) | 261 if (cur && !cur.isWebRange()) |
| 244 return; | 262 return; |
| 245 | 263 |
| 246 this.disableClassicChromeVox_(); | 264 this.disableClassicChromeVox_(); |
| 247 } | 265 } |
| 248 }.bind(this)); | 266 }.bind(this)); |
| 249 | 267 |
| 250 // If switching out of a ChromeVox Next mode, make sure we cancel | 268 // If switching out of a ChromeVox Next mode, make sure we cancel |
| 251 // the progress loading sound just in case. | 269 // the progress loading sound just in case. |
| 252 if ((this.mode_ === ChromeVoxMode.NEXT || | 270 if ((oldMode === ChromeVoxMode.NEXT || |
| 253 this.mode_ === ChromeVoxMode.FORCE_NEXT) && | 271 oldMode === ChromeVoxMode.FORCE_NEXT) && |
| 254 this.mode_ != mode) { | 272 oldMode != mode) { |
| 255 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); | 273 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
| 256 } | 274 } |
| 257 | 275 |
| 258 if (mode === ChromeVoxMode.NEXT || | 276 if (newMode === ChromeVoxMode.NEXT || |
| 259 mode === ChromeVoxMode.FORCE_NEXT) { | 277 newMode === ChromeVoxMode.FORCE_NEXT) { |
| 260 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); | 278 (new PanelCommand(PanelCommandType.ENABLE_MENUS)).send(); |
| 261 if (cvox.TabsApiHandler) | 279 if (cvox.TabsApiHandler) |
| 262 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; | 280 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = false; |
| 263 } else { | 281 } else { |
| 264 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); | 282 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); |
| 265 if (cvox.TabsApiHandler) | 283 if (cvox.TabsApiHandler) |
| 266 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; | 284 cvox.TabsApiHandler.shouldOutputSpeechAndBraille = true; |
| 267 } | 285 } |
| 268 | 286 |
| 269 // If switching to Classic from any automation-API-based mode, | 287 // If switching to Classic from any automation-API-based mode, |
| 270 // clear the focus ring. | 288 // clear the focus ring. |
| 271 if (mode === ChromeVoxMode.CLASSIC && mode != this.mode_) { | 289 if (newMode === ChromeVoxMode.CLASSIC && newMode != oldMode) { |
| 272 if (cvox.ChromeVox.isChromeOS) | 290 if (cvox.ChromeVox.isChromeOS) |
| 273 chrome.accessibilityPrivate.setFocusRing([]); | 291 chrome.accessibilityPrivate.setFocusRing([]); |
| 274 } | 292 } |
| 275 | 293 |
| 276 // If switching away from Classic to any automation-API-based mode, | 294 // If switching away from Classic to any automation-API-based mode, |
| 277 // update the range based on what's focused. | 295 // update the range based on what's focused. |
| 278 if (this.mode_ === ChromeVoxMode.CLASSIC && mode != this.mode_) { | 296 if (oldMode === ChromeVoxMode.CLASSIC && newMode != oldMode) { |
| 279 chrome.automation.getFocus((function(focus) { | 297 chrome.automation.getFocus((function(focus) { |
| 280 if (focus) | 298 if (focus) |
| 281 this.setCurrentRange(cursors.Range.fromNode(focus)); | 299 this.setCurrentRange(cursors.Range.fromNode(focus)); |
| 282 }).bind(this)); | 300 }).bind(this)); |
| 283 } | 301 } |
| 284 | |
| 285 this.mode_ = mode; | |
| 286 }, | 302 }, |
| 287 | 303 |
| 288 /** | 304 /** |
| 289 * Mode refreshes takes into account both |url| and the current ChromeVox | 305 * Toggles between force next and classic/compat modes. |
| 290 * range. The latter gets used to decide if the user is or isn't in web | 306 * This toggle automatically handles deciding between classic/compat based on |
| 291 * content. The focused state also needs to be set for this info to be | 307 * the start of the current range. |
| 292 * reliable. | 308 * @param {boolean=} opt_setValue Directly set to force next (true) or |
| 309 * classic/compat (false). | |
| 310 * @return {boolean} True to announce current position. | |
| 311 */ | |
| 312 toggleMode: function(opt_setValue) { | |
|
dmazzoni
2016/06/20 19:49:03
maybe this should be toggleNext since there are fo
David Tseng
2016/06/20 22:31:08
Done.
| |
| 313 var useClassicOrCompatForCurrentRange = function() { | |
| 314 var start; | |
| 315 if (this.currentRange && this.currentRange.isValid()) | |
| 316 start = this.currentRange.start.node; | |
| 317 if (!start) | |
| 318 return ChromeVoxMode.CLASSIC; | |
|
dmazzoni
2016/06/20 19:49:03
indentation
David Tseng
2016/06/20 22:31:08
Done.
| |
| 319 | |
| 320 var root = AutomationUtil.getTopLevelRoot(start); | |
| 321 if (!root) | |
| 322 return ChromeVoxMode.CLASSIC; | |
| 323 return this.isWhitelistedForCompat_(root.docUrl) ? | |
| 324 ChromeVoxMode.COMPAT : ChromeVoxMode.CLASSIC; | |
| 325 }.bind(this); | |
| 326 | |
| 327 var newMode; | |
| 328 if (opt_setValue !== undefined) { | |
| 329 if (opt_setValue) | |
| 330 newMode = ChromeVoxMode.FORCE_NEXT; | |
| 331 else | |
| 332 newMode = useClassicOrCompatForCurrentRange(); | |
| 333 } else { | |
| 334 if (this.mode_ == ChromeVoxMode.FORCE_NEXT) | |
| 335 newMode = useClassicOrCompatForCurrentRange(); | |
| 336 else | |
| 337 newMode = ChromeVoxMode.FORCE_NEXT; | |
| 338 } | |
| 339 this.setMode(newMode, true); | |
|
dmazzoni
2016/06/20 19:49:03
Can you just call refreshMode() here?
It seems li
David Tseng
2016/06/20 22:31:08
RefreshMode differs in the mode transitions it all
dmazzoni
2016/06/20 22:41:44
Why not just refreshMode to handle all of those ca
| |
| 340 | |
| 341 var isClassic = | |
| 342 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; | |
| 343 | |
| 344 var announce = Msgs.getMsg(isClassic ? | |
| 345 'switch_to_classic' : 'switch_to_next'); | |
| 346 | |
| 347 cvox.ChromeVox.tts.speak( | |
| 348 announce, cvox.QueueMode.FLUSH, {doNotInterrupt: true}); | |
| 349 | |
| 350 Notifications.onModeChange(); | |
| 351 | |
| 352 // If the new mode is Classic, return false now so we don't announce | |
| 353 // anything more. | |
| 354 return newMode != ChromeVoxMode.CLASSIC; | |
| 355 }, | |
| 356 | |
| 357 /** | |
| 358 * Refreshes ChromeVox's mode based on a node. | |
| 359 * Note that this method disallows switching from force next mode to any other | |
| 360 * mode. See toggleMode. | |
| 293 * @override | 361 * @override |
| 294 */ | 362 */ |
| 295 refreshMode: function(node) { | 363 refreshMode: function(node) { |
| 296 // Mode changes are based upon the top level web root. | 364 // Mode changes are based upon the top level web root. |
| 297 var root = node.root; | 365 var root = AutomationUtil.getTopLevelRoot(node); |
| 298 while (root && | |
| 299 root.parent && | |
| 300 root.parent.root && | |
| 301 root.parent.root.role != RoleType.desktop) { | |
| 302 root = root.parent.root; | |
| 303 } | |
| 304 | |
| 305 var url = ''; | 366 var url = ''; |
| 306 if (root && root.role == RoleType.rootWebArea) | 367 if (root) |
| 307 url = root.docUrl; | 368 url = root.docUrl; |
| 308 | 369 |
| 309 var mode = this.mode_; | 370 var mode = this.mode_; |
| 310 if (mode != ChromeVoxMode.FORCE_NEXT) { | 371 if (mode != ChromeVoxMode.FORCE_NEXT) { |
| 311 if (this.isWhitelistedForNext_(url)) { | 372 if (this.isWhitelistedForNext_(url)) { |
| 312 mode = ChromeVoxMode.NEXT; | 373 mode = ChromeVoxMode.NEXT; |
| 313 } else if (this.isBlacklistedForClassic_(url) || (this.currentRange_ && | 374 } else if (this.isWhitelistedForCompat_(url)) { |
| 314 !this.currentRange_.isWebRange() && | |
| 315 this.currentRange_.start.node.state.focused)) { | |
| 316 mode = ChromeVoxMode.COMPAT; | 375 mode = ChromeVoxMode.COMPAT; |
| 317 } else { | 376 } else { |
| 318 mode = ChromeVoxMode.CLASSIC; | 377 mode = ChromeVoxMode.CLASSIC; |
| 319 } | 378 } |
| 320 } | 379 } |
| 321 | 380 |
| 322 this.setMode(mode); | 381 this.setMode(mode); |
| 323 }, | 382 }, |
| 324 | 383 |
| 325 /** | 384 /** |
| 326 * @override | 385 * @override |
| 327 */ | 386 */ |
| 328 getCurrentRange: function() { | 387 getCurrentRange: function() { |
| 329 if (this.currentRange_ && this.currentRange_.isValid()) | 388 if (this.currentRange_ && this.currentRange_.isValid()) |
| 330 return this.currentRange_; | 389 return this.currentRange_; |
| 331 return null; | 390 return null; |
| 332 }, | 391 }, |
| 333 | 392 |
| 334 /** | 393 /** |
| 335 * @override | 394 * @override |
| 336 */ | 395 */ |
| 337 setCurrentRange: function(newRange) { | 396 setCurrentRange: function(newRange) { |
| 338 if (!newRange) | 397 if (!newRange) |
| 339 return; | 398 return; |
| 340 | 399 |
| 341 // Is the range invalid? | 400 // Is the range invalid? |
| 342 if (newRange.start.node.role === undefined || | 401 if (!newRange.isValid()) { |
| 343 newRange.end.node.role === undefined) { | |
| 344 // Restore range to the focused location. | 402 // Restore range to the focused location. |
| 345 chrome.automation.getFocus(function(f) { | 403 chrome.automation.getFocus(function(f) { |
| 346 newRange = cursors.Range.fromNode(f); | 404 newRange = cursors.Range.fromNode(f); |
| 347 }); | 405 }); |
| 348 } | 406 } |
| 349 | 407 |
| 350 if (!this.inExcursion_) | 408 if (!this.inExcursion_) |
| 351 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); | 409 this.savedRange_ = new cursors.Range(newRange.start, newRange.end); |
| 352 | 410 |
| 353 this.currentRange_ = newRange; | 411 this.currentRange_ = newRange; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 return false; | 658 return false; |
| 601 | 659 |
| 602 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; | 660 cvox.ChromeVox.isActive = !cvox.ChromeVox.isActive; |
| 603 if (!cvox.ChromeVox.isActive) { | 661 if (!cvox.ChromeVox.isActive) { |
| 604 var msg = Msgs.getMsg('chromevox_inactive'); | 662 var msg = Msgs.getMsg('chromevox_inactive'); |
| 605 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); | 663 cvox.ChromeVox.tts.speak(msg, cvox.QueueMode.FLUSH); |
| 606 return false; | 664 return false; |
| 607 } | 665 } |
| 608 break; | 666 break; |
| 609 case 'toggleChromeVoxVersion': | 667 case 'toggleChromeVoxVersion': |
| 610 var newMode; | 668 if (!this.toggleMode()) |
| 611 if (this.mode_ == ChromeVoxMode.FORCE_NEXT) { | 669 return false; |
| 612 var inWeb = current.isWebRange(); | |
| 613 newMode = inWeb ? ChromeVoxMode.CLASSIC : ChromeVoxMode.COMPAT; | |
| 614 } else { | |
| 615 newMode = ChromeVoxMode.FORCE_NEXT; | |
| 616 } | |
| 617 this.setMode(newMode, true); | |
| 618 | |
| 619 var isClassic = | |
| 620 newMode == ChromeVoxMode.CLASSIC || newMode == ChromeVoxMode.COMPAT; | |
| 621 | |
| 622 // Leaving unlocalized as 'next' isn't an official name. | |
| 623 cvox.ChromeVox.tts.speak(isClassic ? | |
| 624 'classic' : 'next', cvox.QueueMode.FLUSH, {doNotInterrupt: true}); | |
| 625 | |
| 626 // If the new mode is Classic, return now so we don't announce | |
| 627 // anything more. | |
| 628 if (newMode == ChromeVoxMode.CLASSIC) | |
| 629 return false; | |
| 630 break; | 670 break; |
| 631 case 'toggleStickyMode': | 671 case 'toggleStickyMode': |
| 632 cvox.ChromeVoxBackground.setPref('sticky', | 672 cvox.ChromeVoxBackground.setPref('sticky', |
| 633 !cvox.ChromeVox.isStickyPrefOn, | 673 !cvox.ChromeVox.isStickyPrefOn, |
| 634 true); | 674 true); |
| 635 | 675 |
| 636 if (cvox.ChromeVox.isStickyPrefOn) | 676 if (cvox.ChromeVox.isStickyPrefOn) |
| 637 chrome.accessibilityPrivate.setKeyboardListener(true, true); | 677 chrome.accessibilityPrivate.setKeyboardListener(true, true); |
| 638 else | 678 else |
| 639 chrome.accessibilityPrivate.setKeyboardListener(true, false); | 679 chrome.accessibilityPrivate.setKeyboardListener(true, false); |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 990 * @return {boolean} | 1030 * @return {boolean} |
| 991 * @private | 1031 * @private |
| 992 */ | 1032 */ |
| 993 shouldEnableClassicForUrl_: function(url) { | 1033 shouldEnableClassicForUrl_: function(url) { |
| 994 return this.mode_ != ChromeVoxMode.FORCE_NEXT && | 1034 return this.mode_ != ChromeVoxMode.FORCE_NEXT && |
| 995 !this.isBlacklistedForClassic_(url) && | 1035 !this.isBlacklistedForClassic_(url) && |
| 996 !this.isWhitelistedForNext_(url); | 1036 !this.isWhitelistedForNext_(url); |
| 997 }, | 1037 }, |
| 998 | 1038 |
| 999 /** | 1039 /** |
| 1040 * Compat mode is on if any of the following are true: | |
| 1041 * 1. a url is blacklisted for Classic. | |
| 1042 * 2. the current range is not within web content. | |
| 1043 * @param {string} url | |
| 1044 */ | |
| 1045 isWhitelistedForCompat_: function(url) { | |
| 1046 return this.isBlacklistedForClassic_(url) || (this.currentRange_ && | |
| 1047 !this.currentRange_.isWebRange() && | |
| 1048 this.currentRange_.start.node.state.focused); | |
| 1049 }, | |
| 1050 | |
| 1051 /** | |
| 1000 * @param {string} url | 1052 * @param {string} url |
| 1001 * @return {boolean} | 1053 * @return {boolean} |
| 1002 * @private | 1054 * @private |
| 1003 */ | 1055 */ |
| 1004 isBlacklistedForClassic_: function(url) { | 1056 isBlacklistedForClassic_: function(url) { |
| 1005 return this.classicBlacklistRegExp_.test(url); | 1057 return this.classicBlacklistRegExp_.test(url); |
| 1006 }, | 1058 }, |
| 1007 | 1059 |
| 1008 /** | 1060 /** |
| 1009 * @param {string} url | 1061 * @param {string} url |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1194 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') | 1246 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') |
| 1195 .replace(/\*/g, '.*') | 1247 .replace(/\*/g, '.*') |
| 1196 .replace(/\?/g, '.'); | 1248 .replace(/\?/g, '.'); |
| 1197 }).join('|') + ')$'); | 1249 }).join('|') + ')$'); |
| 1198 }; | 1250 }; |
| 1199 | 1251 |
| 1200 /** @type {Background} */ | 1252 /** @type {Background} */ |
| 1201 global.backgroundObj = new Background(); | 1253 global.backgroundObj = new Background(); |
| 1202 | 1254 |
| 1203 }); // goog.scope | 1255 }); // goog.scope |
| OLD | NEW |