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 20 matching lines...) Expand all Loading... |
31 goog.require('cvox.ChromeVoxEditableTextBase'); | 31 goog.require('cvox.ChromeVoxEditableTextBase'); |
32 goog.require('cvox.ClassicEarcons'); | 32 goog.require('cvox.ClassicEarcons'); |
33 goog.require('cvox.ExtensionBridge'); | 33 goog.require('cvox.ExtensionBridge'); |
34 goog.require('cvox.NavBraille'); | 34 goog.require('cvox.NavBraille'); |
35 | 35 |
36 goog.scope(function() { | 36 goog.scope(function() { |
37 var AutomationNode = chrome.automation.AutomationNode; | 37 var AutomationNode = chrome.automation.AutomationNode; |
38 var Dir = constants.Dir; | 38 var Dir = constants.Dir; |
39 var EventType = chrome.automation.EventType; | 39 var EventType = chrome.automation.EventType; |
40 var RoleType = chrome.automation.RoleType; | 40 var RoleType = chrome.automation.RoleType; |
| 41 var StateType = chrome.automation.StateType; |
41 | 42 |
42 /** | 43 /** |
43 * ChromeVox2 background page. | 44 * ChromeVox2 background page. |
44 * @constructor | 45 * @constructor |
45 * @extends {ChromeVoxState} | 46 * @extends {ChromeVoxState} |
46 */ | 47 */ |
47 Background = function() { | 48 Background = function() { |
48 ChromeVoxState.call(this); | 49 ChromeVoxState.call(this); |
49 | 50 |
50 /** | 51 /** |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 if (!target) | 246 if (!target) |
246 return useNext ? ChromeVoxMode.FORCE_NEXT : ChromeVoxMode.CLASSIC; | 247 return useNext ? ChromeVoxMode.FORCE_NEXT : ChromeVoxMode.CLASSIC; |
247 | 248 |
248 // Closure complains, but clearly, |target| is not null. | 249 // Closure complains, but clearly, |target| is not null. |
249 var topLevelRoot = | 250 var topLevelRoot = |
250 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); | 251 AutomationUtil.getTopLevelRoot(/** @type {!AutomationNode} */(target)); |
251 if (!topLevelRoot) | 252 if (!topLevelRoot) |
252 return useNext ? ChromeVoxMode.FORCE_NEXT : | 253 return useNext ? ChromeVoxMode.FORCE_NEXT : |
253 ChromeVoxMode.CLASSIC_COMPAT; | 254 ChromeVoxMode.CLASSIC_COMPAT; |
254 | 255 |
255 var nextSite = this.isWhitelistedForNext_(topLevelRoot.docUrl); | 256 var docUrl = topLevelRoot.docUrl || ''; |
256 var nextCompat = this.nextCompatRegExp_.test(topLevelRoot.docUrl) && | 257 var nextSite = this.isWhitelistedForNext_(docUrl); |
| 258 var nextCompat = this.nextCompatRegExp_.test(docUrl) && |
257 this.chromeChannel_ != 'dev'; | 259 this.chromeChannel_ != 'dev'; |
258 var classicCompat = | 260 var classicCompat = |
259 this.isWhitelistedForClassicCompat_(topLevelRoot.docUrl); | 261 this.isWhitelistedForClassicCompat_(docUrl); |
260 if (nextCompat && useNext) | 262 if (nextCompat && useNext) |
261 return ChromeVoxMode.NEXT_COMPAT; | 263 return ChromeVoxMode.NEXT_COMPAT; |
262 else if (classicCompat && !useNext) | 264 else if (classicCompat && !useNext) |
263 return ChromeVoxMode.CLASSIC_COMPAT; | 265 return ChromeVoxMode.CLASSIC_COMPAT; |
264 else if (nextSite) | 266 else if (nextSite) |
265 return ChromeVoxMode.NEXT; | 267 return ChromeVoxMode.NEXT; |
266 else if (!useNext) | 268 else if (!useNext) |
267 return ChromeVoxMode.CLASSIC; | 269 return ChromeVoxMode.CLASSIC; |
268 else | 270 else |
269 return ChromeVoxMode.FORCE_NEXT; | 271 return ChromeVoxMode.FORCE_NEXT; |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 if (oldMode != newMode) { | 406 if (oldMode != newMode) { |
405 this.onModeChanged_(newMode, oldMode); | 407 this.onModeChanged_(newMode, oldMode); |
406 this.mode_ = newMode; | 408 this.mode_ = newMode; |
407 } | 409 } |
408 | 410 |
409 if (this.currentRange_) { | 411 if (this.currentRange_) { |
410 var start = this.currentRange_.start.node; | 412 var start = this.currentRange_.start.node; |
411 start.makeVisible(); | 413 start.makeVisible(); |
412 | 414 |
413 var root = start.root; | 415 var root = start.root; |
414 if (!root || root.role == RoleType.desktop) | 416 if (!root || root.role == RoleType.DESKTOP) |
415 return; | 417 return; |
416 | 418 |
417 var position = {}; | 419 var position = {}; |
418 var loc = start.location; | 420 var loc = start.location; |
419 position.x = loc.left + loc.width / 2; | 421 position.x = loc.left + loc.width / 2; |
420 position.y = loc.top + loc.height / 2; | 422 position.y = loc.top + loc.height / 2; |
421 var url = root.docUrl; | 423 var url = root.docUrl; |
422 url = url.substring(0, url.indexOf('#')) || url; | 424 url = url.substring(0, url.indexOf('#')) || url; |
423 cvox.ChromeVox.position[url] = position; | 425 cvox.ChromeVox.position[url] = position; |
424 } | 426 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 if (this.pageSel_) | 489 if (this.pageSel_) |
488 this.pageSel_.select(); | 490 this.pageSel_.select(); |
489 } | 491 } |
490 } else { | 492 } else { |
491 // Ensure we don't select the editable when we first encounter it. | 493 // Ensure we don't select the editable when we first encounter it. |
492 var lca = null; | 494 var lca = null; |
493 if (range.start.node && prevRange.start.node) { | 495 if (range.start.node && prevRange.start.node) { |
494 lca = AutomationUtil.getLeastCommonAncestor(prevRange.start.node, | 496 lca = AutomationUtil.getLeastCommonAncestor(prevRange.start.node, |
495 range.start.node); | 497 range.start.node); |
496 } | 498 } |
497 if (!lca || lca.state.editable || !range.start.node.state.editable) | 499 if (!lca || lca.state[StateType.EDITABLE] || |
| 500 !range.start.node.state[StateType.EDITABLE]) |
498 range.select(); | 501 range.select(); |
499 } | 502 } |
500 | 503 |
501 o.withRichSpeechAndBraille( | 504 o.withRichSpeechAndBraille( |
502 selectedRange || range, prevRange, Output.EventType.NAVIGATE) | 505 selectedRange || range, prevRange, Output.EventType.NAVIGATE) |
503 .withQueueMode(cvox.QueueMode.FLUSH); | 506 .withQueueMode(cvox.QueueMode.FLUSH); |
504 | 507 |
505 if (msg) | 508 if (msg) |
506 o.format(msg); | 509 o.format(msg); |
507 | 510 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
581 }, | 584 }, |
582 | 585 |
583 /** | 586 /** |
584 * Compat mode is on if any of the following are true: | 587 * Compat mode is on if any of the following are true: |
585 * 1. a url is blacklisted for Classic. | 588 * 1. a url is blacklisted for Classic. |
586 * 2. the current range is not within web content. | 589 * 2. the current range is not within web content. |
587 * @param {string} url | 590 * @param {string} url |
588 * @return {boolean} | 591 * @return {boolean} |
589 */ | 592 */ |
590 isWhitelistedForClassicCompat_: function(url) { | 593 isWhitelistedForClassicCompat_: function(url) { |
591 return this.isBlacklistedForClassic_(url) || (this.getCurrentRange() && | 594 return (this.isBlacklistedForClassic_(url) || (this.getCurrentRange() && |
592 !this.getCurrentRange().isWebRange() && | 595 !this.getCurrentRange().isWebRange() && |
593 this.getCurrentRange().start.node.state.focused); | 596 this.getCurrentRange().start.node.state[StateType.FOCUSED])) || false; |
594 }, | 597 }, |
595 | 598 |
596 /** | 599 /** |
597 * @param {string} url | 600 * @param {string} url |
598 * @return {boolean} | 601 * @return {boolean} |
599 * @private | 602 * @private |
600 */ | 603 */ |
601 isBlacklistedForClassic_: function(url) { | 604 isBlacklistedForClassic_: function(url) { |
602 if (this.classicBlacklistRegExp_.test(url)) | 605 if (this.classicBlacklistRegExp_.test(url)) |
603 return true; | 606 return true; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 } else if (span instanceof Output.NodeSpan) { | 663 } else if (span instanceof Output.NodeSpan) { |
661 if (!actionNodeSpan || | 664 if (!actionNodeSpan || |
662 text.getSpanLength(span) <= text.getSpanLength(actionNodeSpan)) { | 665 text.getSpanLength(span) <= text.getSpanLength(actionNodeSpan)) { |
663 actionNodeSpan = span; | 666 actionNodeSpan = span; |
664 } | 667 } |
665 } | 668 } |
666 }); | 669 }); |
667 if (!actionNodeSpan) | 670 if (!actionNodeSpan) |
668 return; | 671 return; |
669 var actionNode = actionNodeSpan.node; | 672 var actionNode = actionNodeSpan.node; |
670 if (actionNode.role === RoleType.inlineTextBox) | 673 if (actionNode.role === RoleType.INLINE_TEXT_BOX) |
671 actionNode = actionNode.parent; | 674 actionNode = actionNode.parent; |
672 actionNode.doDefault(); | 675 actionNode.doDefault(); |
673 if (selectionSpan) { | 676 if (selectionSpan) { |
674 var start = text.getSpanStart(selectionSpan); | 677 var start = text.getSpanStart(selectionSpan); |
675 var targetPosition = position - start; | 678 var targetPosition = position - start; |
676 actionNode.setSelection(targetPosition, targetPosition); | 679 actionNode.setSelection(targetPosition, targetPosition); |
677 } | 680 } |
678 }, | 681 }, |
679 | 682 |
680 /** | 683 /** |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 setFocusToRange_: function(range, prevRange) { | 783 setFocusToRange_: function(range, prevRange) { |
781 var start = range.start.node; | 784 var start = range.start.node; |
782 var end = range.end.node; | 785 var end = range.end.node; |
783 | 786 |
784 // First, see if we've crossed a root. Remove once webview handles focus | 787 // First, see if we've crossed a root. Remove once webview handles focus |
785 // correctly. | 788 // correctly. |
786 if (prevRange && prevRange.start.node && start) { | 789 if (prevRange && prevRange.start.node && start) { |
787 var entered = AutomationUtil.getUniqueAncestors( | 790 var entered = AutomationUtil.getUniqueAncestors( |
788 prevRange.start.node, start); | 791 prevRange.start.node, start); |
789 var embeddedObject = entered.find(function(f) { | 792 var embeddedObject = entered.find(function(f) { |
790 return f.role == RoleType.embeddedObject; }); | 793 return f.role == RoleType.EMBEDDED_OBJECT; }); |
791 if (embeddedObject && !embeddedObject.state.focused) | 794 if (embeddedObject && !embeddedObject.state[StateType.FOCUSED]) |
792 embeddedObject.focus(); | 795 embeddedObject.focus(); |
793 } | 796 } |
794 | 797 |
795 if (start.state.focused || end.state.focused) | 798 if (start.state[StateType.FOCUSED] || end.state[StateType.FOCUSED]) |
796 return; | 799 return; |
797 | 800 |
798 var isFocusableLinkOrControl = function(node) { | 801 var isFocusableLinkOrControl = function(node) { |
799 return node.state.focusable && | 802 return node.state[StateType.FOCUSABLE] && |
800 AutomationPredicate.linkOrControl(node); | 803 AutomationPredicate.linkOrControl(node); |
801 }; | 804 }; |
802 | 805 |
803 // Next, try to focus the start or end node. | 806 // Next, try to focus the start or end node. |
804 if (!AutomationPredicate.structuralContainer(start) && | 807 if (!AutomationPredicate.structuralContainer(start) && |
805 start.state.focusable) { | 808 start.state[StateType.FOCUSABLE]) { |
806 if (!start.state.focused) | 809 if (!start.state[StateType.FOCUSED]) |
807 start.focus(); | 810 start.focus(); |
808 return; | 811 return; |
809 } else if (!AutomationPredicate.structuralContainer(end) && | 812 } else if (!AutomationPredicate.structuralContainer(end) && |
810 end.state.focusable) { | 813 end.state[StateType.FOCUSABLE]) { |
811 if (!end.state.focused) | 814 if (!end.state[StateType.FOCUSED]) |
812 end.focus(); | 815 end.focus(); |
813 return; | 816 return; |
814 } | 817 } |
815 | 818 |
816 // If a common ancestor of |start| and |end| is a link, focus that. | 819 // If a common ancestor of |start| and |end| is a link, focus that. |
817 var ancestor = AutomationUtil.getLeastCommonAncestor(start, end); | 820 var ancestor = AutomationUtil.getLeastCommonAncestor(start, end); |
818 while (ancestor && ancestor.root == start.root) { | 821 while (ancestor && ancestor.root == start.root) { |
819 if (isFocusableLinkOrControl(ancestor)) { | 822 if (isFocusableLinkOrControl(ancestor)) { |
820 if (!ancestor.state.focused) | 823 if (!ancestor.state[StateType.FOCUSED]) |
821 ancestor.focus(); | 824 ancestor.focus(); |
822 return; | 825 return; |
823 } | 826 } |
824 ancestor = ancestor.parent; | 827 ancestor = ancestor.parent; |
825 } | 828 } |
826 | 829 |
827 // If nothing is focusable, set the sequential focus navigation starting | 830 // If nothing is focusable, set the sequential focus navigation starting |
828 // point, which ensures that the next time you press Tab, you'll reach | 831 // point, which ensures that the next time you press Tab, you'll reach |
829 // the next or previous focusable node from |start|. | 832 // the next or previous focusable node from |start|. |
830 if (!start.state.offscreen) | 833 if (!start.state[StateType.OFFSCREEN]) |
831 start.setSequentialFocusNavigationStartingPoint(); | 834 start.setSequentialFocusNavigationStartingPoint(); |
832 } | 835 } |
833 }; | 836 }; |
834 | 837 |
835 /** | 838 /** |
836 * Converts a list of globs, as used in the extension manifest, to a regular | 839 * Converts a list of globs, as used in the extension manifest, to a regular |
837 * expression that matches if and only if any of the globs in the list matches. | 840 * expression that matches if and only if any of the globs in the list matches. |
838 * @param {!Array<string>} globs | 841 * @param {!Array<string>} globs |
839 * @return {!RegExp} | 842 * @return {!RegExp} |
840 * @private | 843 * @private |
841 */ | 844 */ |
842 Background.globsToRegExp_ = function(globs) { | 845 Background.globsToRegExp_ = function(globs) { |
843 return new RegExp('^(' + globs.map(function(glob) { | 846 return new RegExp('^(' + globs.map(function(glob) { |
844 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') | 847 return glob.replace(/[.+^$(){}|[\]\\]/g, '\\$&') |
845 .replace(/\*/g, '.*') | 848 .replace(/\*/g, '.*') |
846 .replace(/\?/g, '.'); | 849 .replace(/\?/g, '.'); |
847 }).join('|') + ')$'); | 850 }).join('|') + ')$'); |
848 }; | 851 }; |
849 | 852 |
850 new Background(); | 853 new Background(); |
851 | 854 |
852 }); // goog.scope | 855 }); // goog.scope |
OLD | NEW |