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