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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 | 66 |
67 /** | 67 /** |
68 * Regular expression for blacklisting classic. | 68 * Regular expression for blacklisting classic. |
69 * @type {RegExp} | 69 * @type {RegExp} |
70 * @private | 70 * @private |
71 */ | 71 */ |
72 this.classicBlacklistRegExp_ = Background.globsToRegExp_( | 72 this.classicBlacklistRegExp_ = Background.globsToRegExp_( |
73 chrome.runtime.getManifest()['content_scripts'][0]['exclude_globs']); | 73 chrome.runtime.getManifest()['content_scripts'][0]['exclude_globs']); |
74 | 74 |
75 /** | 75 /** |
76 * Regular expression for whitelisting Next compat. | |
77 * @type {RegExp} | |
78 * @private | |
79 */ | |
80 this.nextCompatRegExp_ = Background.globsToRegExp_([ | |
81 '*docs.google.com/document/*', | |
82 '*docs.google.com/spreadsheets/*', | |
83 '*docs.google.com/presentation/*' | |
84 ]); | |
85 | |
86 /** | |
87 * @type {cursors.Range} | 76 * @type {cursors.Range} |
88 * @private | 77 * @private |
89 */ | 78 */ |
90 this.currentRange_ = null; | 79 this.currentRange_ = null; |
91 | 80 |
92 // Manually bind all functions to |this|. | 81 // Manually bind all functions to |this|. |
93 for (var func in this) { | 82 for (var func in this) { |
94 if (typeof(this[func]) == 'function') | 83 if (typeof(this[func]) == 'function') |
95 this[func] = this[func].bind(this); | 84 this[func] = this[func].bind(this); |
96 } | 85 } |
97 | 86 |
98 /** @type {!cvox.AbstractEarcons} @private */ | 87 /** @type {!cvox.AbstractEarcons} @private */ |
99 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); | 88 this.classicEarcons_ = cvox.ChromeVox.earcons || new cvox.ClassicEarcons(); |
100 | 89 |
101 /** @type {!cvox.AbstractEarcons} @private */ | 90 /** @type {!cvox.AbstractEarcons} @private */ |
102 this.nextEarcons_ = new NextEarcons(); | 91 this.nextEarcons_ = new NextEarcons(); |
103 | 92 |
104 // Turn cvox.ChromeVox.earcons into a getter that returns either the | 93 // Turn cvox.ChromeVox.earcons into a getter that returns either the |
105 // Next earcons or the Classic earcons depending on the current mode. | 94 // Next earcons or the Classic earcons depending on the current mode. |
106 Object.defineProperty(cvox.ChromeVox, 'earcons', { | 95 Object.defineProperty(cvox.ChromeVox, 'earcons', { |
107 get: (function() { | 96 get: (function() { |
108 if (this.mode === ChromeVoxMode.FORCE_NEXT || | 97 if (this.mode === ChromeVoxMode.FORCE_NEXT || |
109 this.mode === ChromeVoxMode.NEXT || | 98 this.mode === ChromeVoxMode.NEXT) { |
110 this.mode === ChromeVoxMode.NEXT_COMPAT) { | |
111 return this.nextEarcons_; | 99 return this.nextEarcons_; |
112 } else { | 100 } else { |
113 return this.classicEarcons_; | 101 return this.classicEarcons_; |
114 } | 102 } |
115 }).bind(this) | 103 }).bind(this) |
116 }); | 104 }); |
117 | 105 |
118 if (cvox.ChromeVox.isChromeOS) { | 106 if (cvox.ChromeVox.isChromeOS) { |
119 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { | 107 Object.defineProperty(cvox.ChromeVox, 'modKeyStr', { |
120 get: function() { | 108 get: function() { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 | 236 |
249 // Closure complains, but clearly, |target| is not null. | 237 // Closure complains, but clearly, |target| is not null. |
250 var topLevelRoot = | 238 var topLevelRoot = |
251 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); | 239 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); |
252 if (!topLevelRoot) | 240 if (!topLevelRoot) |
253 return useNext ? ChromeVoxMode.FORCE_NEXT : | 241 return useNext ? ChromeVoxMode.FORCE_NEXT : |
254 ChromeVoxMode.CLASSIC_COMPAT; | 242 ChromeVoxMode.CLASSIC_COMPAT; |
255 | 243 |
256 var docUrl = topLevelRoot.docUrl || ''; | 244 var docUrl = topLevelRoot.docUrl || ''; |
257 var nextSite = this.isWhitelistedForNext_(docUrl); | 245 var nextSite = this.isWhitelistedForNext_(docUrl); |
258 var nextCompat = this.nextCompatRegExp_.test(docUrl) && | |
259 this.chromeChannel_ != 'dev'; | |
260 var classicCompat = | 246 var classicCompat = |
261 this.isWhitelistedForClassicCompat_(docUrl); | 247 this.isWhitelistedForClassicCompat_(docUrl); |
262 if (nextCompat && useNext) | 248 if (classicCompat && !useNext) |
263 return ChromeVoxMode.NEXT_COMPAT; | |
264 else if (classicCompat && !useNext) | |
265 return ChromeVoxMode.CLASSIC_COMPAT; | 249 return ChromeVoxMode.CLASSIC_COMPAT; |
266 else if (nextSite) | 250 else if (nextSite) |
267 return ChromeVoxMode.NEXT; | 251 return ChromeVoxMode.NEXT; |
268 else if (!useNext) | 252 else if (!useNext) |
269 return ChromeVoxMode.CLASSIC; | 253 return ChromeVoxMode.CLASSIC; |
270 else | 254 else |
271 return ChromeVoxMode.FORCE_NEXT; | 255 return ChromeVoxMode.FORCE_NEXT; |
272 }, | 256 }, |
273 | 257 |
274 /** | 258 /** |
275 * Handles a mode change. | 259 * Handles a mode change. |
276 * @param {ChromeVoxMode} newMode | 260 * @param {ChromeVoxMode} newMode |
277 * @param {?ChromeVoxMode} oldMode Can be null at startup when no range was | 261 * @param {?ChromeVoxMode} oldMode Can be null at startup when no range was |
278 * previously set. | 262 * previously set. |
279 * @private | 263 * @private |
280 */ | 264 */ |
281 onModeChanged_: function(newMode, oldMode) { | 265 onModeChanged_: function(newMode, oldMode) { |
282 this.keyboardHandler_.onModeChanged(newMode, oldMode); | 266 this.keyboardHandler_.onModeChanged(newMode, oldMode); |
283 CommandHandler.onModeChanged(newMode, oldMode); | 267 CommandHandler.onModeChanged(newMode, oldMode); |
284 FindHandler.onModeChanged(newMode, oldMode); | 268 FindHandler.onModeChanged(newMode, oldMode); |
285 Notifications.onModeChange(newMode, oldMode); | 269 Notifications.onModeChange(newMode, oldMode); |
286 | 270 |
287 // The below logic handles transition between the classic engine | 271 // The below logic handles transition between the classic engine |
288 // (content script) and next engine (no content script) as well as | 272 // (content script) and next engine (no content script) as well as |
289 // misc states that are not handled above. | 273 // misc states that are not handled above. |
290 | 274 |
291 // Classic modes do not use the new focus highlight. | 275 // Classic modes do not use the new focus highlight. |
292 if (newMode == ChromeVoxMode.CLASSIC || | 276 if (newMode == ChromeVoxMode.CLASSIC) |
293 newMode == ChromeVoxMode.NEXT_COMPAT) | |
294 chrome.accessibilityPrivate.setFocusRing([]); | 277 chrome.accessibilityPrivate.setFocusRing([]); |
295 | 278 |
296 // Switch on/off content scripts. | 279 // Switch on/off content scripts. |
297 // note that |this.currentRange_| can *change* because the request is | 280 // note that |this.currentRange_| can *change* because the request is |
298 // async. Save it to ensure we're looking at the currentRange at this moment | 281 // async. Save it to ensure we're looking at the currentRange at this moment |
299 // in time. | 282 // in time. |
300 var cur = this.currentRange_; | 283 var cur = this.currentRange_; |
301 chrome.tabs.query({active: true, | 284 chrome.tabs.query({active: true, |
302 lastFocusedWindow: true}, function(tabs) { | 285 lastFocusedWindow: true}, function(tabs) { |
303 if (newMode == ChromeVoxMode.CLASSIC) { | 286 if (newMode == ChromeVoxMode.CLASSIC) { |
304 // Generally, we don't want to inject classic content scripts as it is | 287 // Generally, we don't want to inject classic content scripts as it is |
305 // done by the extension system at document load. The exception is when | 288 // done by the extension system at document load. The exception is when |
306 // we toggle classic on manually as part of a user command. | 289 // we toggle classic on manually as part of a user command. |
307 // Note that classic -> next_compat is ignored here because classic | |
308 // should have already enabled content scripts. | |
309 if (oldMode == ChromeVoxMode.FORCE_NEXT) { | 290 if (oldMode == ChromeVoxMode.FORCE_NEXT) { |
310 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); | 291 cvox.ChromeVox.injectChromeVoxIntoTabs(tabs); |
311 } | 292 } |
312 } else if (newMode === ChromeVoxMode.FORCE_NEXT) { | 293 } else if (newMode === ChromeVoxMode.FORCE_NEXT) { |
313 // Disable ChromeVox everywhere except for things whitelisted | 294 this.disableClassicChromeVox_(); |
314 // for next compat. | 295 } else { |
315 this.disableClassicChromeVox_({forNextCompat: true}); | |
316 } else if (newMode != ChromeVoxMode.NEXT_COMPAT) { | |
317 // If we're focused in the desktop tree, do nothing. | 296 // If we're focused in the desktop tree, do nothing. |
318 if (cur && !cur.isWebRange()) | 297 if (cur && !cur.isWebRange()) |
319 return; | 298 return; |
320 | 299 |
321 // If we're entering classic compat mode or next mode for just one tab, | 300 // If we're entering classic compat mode or next mode for just one tab, |
322 // disable Classic for that tab only. | 301 // disable Classic for that tab only. |
323 this.disableClassicChromeVox_({tabs: tabs}); | 302 this.disableClassicChromeVox_(tabs); |
324 } | 303 } |
325 }.bind(this)); | 304 }.bind(this)); |
326 | 305 |
327 // Switching into either compat or classic. | 306 // Switching into either compat or classic. |
328 if (oldMode === ChromeVoxMode.NEXT || | 307 if (oldMode === ChromeVoxMode.NEXT || |
329 oldMode === ChromeVoxMode.FORCE_NEXT) { | 308 oldMode === ChromeVoxMode.FORCE_NEXT) { |
330 // Make sure we cancel the progress loading sound just in case. | 309 // Make sure we cancel the progress loading sound just in case. |
331 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); | 310 cvox.ChromeVox.earcons.cancelEarcon(cvox.Earcon.PAGE_START_LOADING); |
332 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); | 311 (new PanelCommand(PanelCommandType.DISABLE_MENUS)).send(); |
333 } | 312 } |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 } | 553 } |
575 return true; | 554 return true; |
576 }, | 555 }, |
577 | 556 |
578 /** | 557 /** |
579 * Returns true if the url should have Classic running. | 558 * Returns true if the url should have Classic running. |
580 * @return {boolean} | 559 * @return {boolean} |
581 * @private | 560 * @private |
582 */ | 561 */ |
583 shouldEnableClassicForUrl_: function(url) { | 562 shouldEnableClassicForUrl_: function(url) { |
584 return (this.nextCompatRegExp_.test(url) &&this.chromeChannel_ != 'dev') || | 563 return this.mode != ChromeVoxMode.FORCE_NEXT && |
585 (this.mode != ChromeVoxMode.FORCE_NEXT && | |
586 !this.isBlacklistedForClassic_(url) && | 564 !this.isBlacklistedForClassic_(url) && |
587 !this.isWhitelistedForNext_(url)); | 565 !this.isWhitelistedForNext_(url); |
588 }, | 566 }, |
589 | 567 |
590 /** | 568 /** |
591 * Compat mode is on if any of the following are true: | 569 * Compat mode is on if any of the following are true: |
592 * 1. a url is blacklisted for Classic. | 570 * 1. a url is blacklisted for Classic. |
593 * 2. the current range is not within web content. | 571 * 2. the current range is not within web content. |
594 * @param {string} url | 572 * @param {string} url |
595 * @return {boolean} | 573 * @return {boolean} |
596 */ | 574 */ |
597 isWhitelistedForClassicCompat_: function(url) { | 575 isWhitelistedForClassicCompat_: function(url) { |
(...skipping 20 matching lines...) Expand all Loading... |
618 * @private | 596 * @private |
619 */ | 597 */ |
620 isWhitelistedForNext_: function(url) { | 598 isWhitelistedForNext_: function(url) { |
621 return this.whitelist_.some(function(item) { | 599 return this.whitelist_.some(function(item) { |
622 return url.indexOf(item) != -1; | 600 return url.indexOf(item) != -1; |
623 }); | 601 }); |
624 }, | 602 }, |
625 | 603 |
626 /** | 604 /** |
627 * Disables classic ChromeVox in current web content. | 605 * Disables classic ChromeVox in current web content. |
628 * @param {{tabs: (Array<Tab>|undefined), | 606 * @param {Array<Tab>=} opt_tabs The tabs where ChromeVox scripts should be |
629 * forNextCompat: (boolean|undefined)}} params | 607 * disabled. If null, will disable ChromeVox everywhere. |
630 * tabs: The tabs where ChromeVox scripts should be disabled. If null, will | |
631 * disable ChromeVox everywhere. | |
632 * forNextCompat: filters out tabs that have been listed for next compat (i.e. | |
633 * should retain content script). | |
634 */ | 608 */ |
635 disableClassicChromeVox_: function(params) { | 609 disableClassicChromeVox_: function(opt_tabs) { |
636 var disableChromeVoxCommand = { | 610 var disableChromeVoxCommand = { |
637 message: 'SYSTEM_COMMAND', | 611 message: 'SYSTEM_COMMAND', |
638 command: 'killChromeVox' | 612 command: 'killChromeVox' |
639 }; | 613 }; |
640 | 614 |
641 if (params.forNextCompat) { | 615 if (opt_tabs) { |
642 var reStr = this.nextCompatRegExp_.toString(); | 616 for (var i = 0, tab; tab = opt_tabs[i]; i++) |
643 disableChromeVoxCommand['excludeUrlRegExp'] = | |
644 reStr.substring(1, reStr.length - 1); | |
645 } | |
646 | |
647 if (params.tabs) { | |
648 for (var i = 0, tab; tab = params.tabs[i]; i++) | |
649 chrome.tabs.sendMessage(tab.id, disableChromeVoxCommand); | 617 chrome.tabs.sendMessage(tab.id, disableChromeVoxCommand); |
650 } else { | 618 } else { |
651 // Send to all ChromeVox clients. | 619 // Send to all ChromeVox clients. |
652 cvox.ExtensionBridge.send(disableChromeVoxCommand); | 620 cvox.ExtensionBridge.send(disableChromeVoxCommand); |
653 } | 621 } |
654 }, | 622 }, |
655 | 623 |
656 /** | 624 /** |
657 * @param {!Spannable} text | 625 * @param {!Spannable} text |
658 * @param {number} position | 626 * @param {number} position |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 return new RegExp('^(' + globs.map(function(glob) { | 818 return new RegExp('^(' + globs.map(function(glob) { |
851 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') | 819 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') |
852 .replace(/\*/g, '.*') | 820 .replace(/\*/g, '.*') |
853 .replace(/\?/g, '.'); | 821 .replace(/\?/g, '.'); |
854 }).join('|') + ')$'); | 822 }).join('|') + ')$'); |
855 }; | 823 }; |
856 | 824 |
857 new Background(); | 825 new Background(); |
858 | 826 |
859 }); // goog.scope | 827 }); // goog.scope |
OLD | NEW |