OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 Implements support for live regions in ChromeVox Next. | 6 * @fileoverview Implements support for live regions in ChromeVox Next. |
7 */ | 7 */ |
8 | 8 |
9 goog.provide('LiveRegions'); | 9 goog.provide('LiveRegions'); |
10 | 10 |
11 goog.require('ChromeVoxState'); | 11 goog.require('ChromeVoxState'); |
12 | 12 |
13 goog.scope(function() { | 13 goog.scope(function() { |
14 var AutomationNode = chrome.automation.AutomationNode; | 14 var AutomationNode = chrome.automation.AutomationNode; |
15 var RoleType = chrome.automation.RoleType; | 15 var RoleType = chrome.automation.RoleType; |
16 var TreeChange = chrome.automation.TreeChange; | 16 var TreeChange = chrome.automation.TreeChange; |
17 var TreeChangeObserverFilter = chrome.automation.TreeChangeObserverFilter; | |
18 | 17 |
19 /** | 18 /** |
20 * ChromeVox2 live region handler. | 19 * ChromeVox2 live region handler. |
21 * @param {!ChromeVoxState} chromeVoxState The ChromeVox state object, | 20 * @param {!ChromeVoxState} chromeVoxState The ChromeVox state object, |
22 * keeping track of the current mode and current range. | 21 * keeping track of the current mode and current range. |
23 * @constructor | 22 * @constructor |
24 */ | 23 */ |
25 LiveRegions = function(chromeVoxState) { | 24 LiveRegions = function(chromeVoxState) { |
26 /** | 25 /** |
27 * @type {!ChromeVoxState} | 26 * @type {!ChromeVoxState} |
28 * @private | 27 * @private |
29 */ | 28 */ |
30 this.chromeVoxState_ = chromeVoxState; | 29 this.chromeVoxState_ = chromeVoxState; |
31 | 30 |
32 /** | 31 /** |
33 * The time the last live region event was output. | 32 * The time the last live region event was output. |
34 * @type {!Date} | 33 * @type {!Date} |
35 * @private | 34 * @private |
36 */ | 35 */ |
37 this.lastLiveRegionTime_ = new Date(0); | 36 this.lastLiveRegionTime_ = new Date(0); |
38 | 37 |
39 /** | 38 /** |
40 * Set of nodes that have been announced as part of a live region since | 39 * Set of nodes that have been announced as part of a live region since |
41 * |this.lastLiveRegionTime_|, to prevent duplicate announcements. | 40 * |this.lastLiveRegionTime_|, to prevent duplicate announcements. |
42 * @type {!WeakSet<AutomationNode>} | 41 * @type {!WeakSet<AutomationNode>} |
43 * @private | 42 * @private |
44 */ | 43 */ |
45 this.liveRegionNodeSet_ = new WeakSet(); | 44 this.liveRegionNodeSet_ = new WeakSet(); |
46 chrome.automation.addTreeChangeObserver( | 45 chrome.automation.addTreeChangeObserver( |
47 TreeChangeObserverFilter.LIVE_REGION_TREE_CHANGES, | 46 'liveRegionTreeChanges', this.onTreeChange.bind(this)); |
48 this.onTreeChange.bind(this)); | |
49 }; | 47 }; |
50 | 48 |
51 /** | 49 /** |
52 * Live region events received in fewer than this many milliseconds will | 50 * Live region events received in fewer than this many milliseconds will |
53 * queue, otherwise they'll be output with a category flush. | 51 * queue, otherwise they'll be output with a category flush. |
54 * @type {number} | 52 * @type {number} |
55 * @const | 53 * @const |
56 */ | 54 */ |
57 LiveRegions.LIVE_REGION_QUEUE_TIME_MS = 5000; | 55 LiveRegions.LIVE_REGION_QUEUE_TIME_MS = 5000; |
58 | 56 |
(...skipping 27 matching lines...) Expand all Loading... |
86 | 84 |
87 if (mode === ChromeVoxMode.CLASSIC || !cvox.ChromeVox.isActive) | 85 if (mode === ChromeVoxMode.CLASSIC || !cvox.ChromeVox.isActive) |
88 return; | 86 return; |
89 | 87 |
90 if (!currentRange) | 88 if (!currentRange) |
91 return; | 89 return; |
92 | 90 |
93 var webView = AutomationUtil.getTopLevelRoot(node); | 91 var webView = AutomationUtil.getTopLevelRoot(node); |
94 webView = webView ? webView.parent : null; | 92 webView = webView ? webView.parent : null; |
95 if (!LiveRegions.announceLiveRegionsFromBackgroundTabs_ && | 93 if (!LiveRegions.announceLiveRegionsFromBackgroundTabs_ && |
96 currentRange.start.node.role != RoleType.DESKTOP && | 94 currentRange.start.node.role != RoleType.desktop && |
97 (!webView || !webView.state.focused)) { | 95 (!webView || !webView.state.focused)) { |
98 return; | 96 return; |
99 } | 97 } |
100 | 98 |
101 var type = treeChange.type; | 99 var type = treeChange.type; |
102 var relevant = node.containerLiveRelevant; | 100 var relevant = node.containerLiveRelevant; |
103 var additions = relevant.indexOf('additions') >= 0; | 101 var additions = relevant.indexOf('additions') >= 0; |
104 var text = relevant.indexOf('text') >= 0; | 102 var text = relevant.indexOf('text') >= 0; |
105 var removals = relevant.indexOf('removals') >= 0; | 103 var removals = relevant.indexOf('removals') >= 0; |
106 var all = relevant.indexOf('all') >= 0; | 104 var all = relevant.indexOf('all') >= 0; |
(...skipping 23 matching lines...) Expand all Loading... |
130 if (node.containerLiveBusy) | 128 if (node.containerLiveBusy) |
131 return; | 129 return; |
132 | 130 |
133 if (node.containerLiveAtomic && !node.liveAtomic) { | 131 if (node.containerLiveAtomic && !node.liveAtomic) { |
134 if (node.parent) | 132 if (node.parent) |
135 this.outputLiveRegionChange_(node.parent, opt_prependFormatStr); | 133 this.outputLiveRegionChange_(node.parent, opt_prependFormatStr); |
136 return; | 134 return; |
137 } | 135 } |
138 | 136 |
139 // Alerts should be announced as a result of focus. | 137 // Alerts should be announced as a result of focus. |
140 if (node.role == RoleType.ALERT) | 138 if (node.role == RoleType.alert) |
141 return; | 139 return; |
142 | 140 |
143 var range = cursors.Range.fromNode(node); | 141 var range = cursors.Range.fromNode(node); |
144 var output = new Output(); | 142 var output = new Output(); |
145 if (opt_prependFormatStr) | 143 if (opt_prependFormatStr) |
146 output.format(opt_prependFormatStr); | 144 output.format(opt_prependFormatStr); |
147 output.withSpeech(range, range, Output.EventType.NAVIGATE); | 145 output.withSpeech(range, range, Output.EventType.NAVIGATE); |
148 | 146 |
149 if (!output.hasSpeech && node.liveAtomic) | 147 if (!output.hasSpeech && node.liveAtomic) |
150 output.format('$joinedDescendants', node); | 148 output.format('$joinedDescendants', node); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 parent = parent.parent; | 180 parent = parent.parent; |
183 } | 181 } |
184 | 182 |
185 this.liveRegionNodeSet_.add(node); | 183 this.liveRegionNodeSet_.add(node); |
186 output.go(); | 184 output.go(); |
187 this.lastLiveRegionTime_ = currentTime; | 185 this.lastLiveRegionTime_ = currentTime; |
188 }, | 186 }, |
189 }; | 187 }; |
190 | 188 |
191 }); // goog.scope | 189 }); // goog.scope |
OLD | NEW |