Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js

Issue 1457683009: Complete live region support in ChromeVox Next. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed last feedback Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 Handles automation from a desktop automation node. 6 * @fileoverview Handles automation from a desktop automation node.
7 */ 7 */
8 8
9 goog.provide('DesktopAutomationHandler'); 9 goog.provide('DesktopAutomationHandler');
10 10
11 goog.require('Background');
12 goog.require('BaseAutomationHandler'); 11 goog.require('BaseAutomationHandler');
12 goog.require('ChromeVoxState');
13 13
14 goog.scope(function() { 14 goog.scope(function() {
15 var AutomationEvent = chrome.automation.AutomationEvent; 15 var AutomationEvent = chrome.automation.AutomationEvent;
16 var AutomationNode = chrome.automation.AutomationNode; 16 var AutomationNode = chrome.automation.AutomationNode;
17 var Dir = AutomationUtil.Dir; 17 var Dir = AutomationUtil.Dir;
18 var RoleType = chrome.automation.RoleType; 18 var RoleType = chrome.automation.RoleType;
19 19
20 /** 20 /**
21 * @param {!AutomationNode} node 21 * @param {!AutomationNode} node
22 * @constructor 22 * @constructor
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 /** 54 /**
55 * Provides all feedback once ChromeVox's focus changes. 55 * Provides all feedback once ChromeVox's focus changes.
56 * @param {Object} evt 56 * @param {Object} evt
57 */ 57 */
58 onEventDefault: function(evt) { 58 onEventDefault: function(evt) {
59 var node = evt.target; 59 var node = evt.target;
60 60
61 if (!node) 61 if (!node)
62 return; 62 return;
63 63
64 var prevRange = global.backgroundObj.currentRange; 64 var prevRange = ChromeVoxState.instance.currentRange;
65 65
66 global.backgroundObj.currentRange = cursors.Range.fromNode(node); 66 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(node));
67 67
68 // Check to see if we've crossed roots. Continue if we've crossed roots or 68 // Check to see if we've crossed roots. Continue if we've crossed roots or
69 // are not within web content. 69 // are not within web content.
70 if (node.root.role == RoleType.desktop || 70 if (node.root.role == RoleType.desktop ||
71 !prevRange || 71 !prevRange ||
72 prevRange.start.node.root != node.root) 72 prevRange.start.node.root != node.root)
73 global.backgroundObj.refreshMode(node.root.docUrl || ''); 73 ChromeVoxState.instance.refreshMode(node.root.docUrl || '');
74 74
75 // Don't process nodes inside of web content if ChromeVox Next is inactive. 75 // Don't process nodes inside of web content if ChromeVox Next is inactive.
76 if (node.root.role != RoleType.desktop && 76 if (node.root.role != RoleType.desktop &&
77 global.backgroundObj.mode === ChromeVoxMode.CLASSIC) { 77 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC) {
78 if (cvox.ChromeVox.isChromeOS) 78 if (cvox.ChromeVox.isChromeOS)
79 chrome.accessibilityPrivate.setFocusRing([]); 79 chrome.accessibilityPrivate.setFocusRing([]);
80 return; 80 return;
81 } 81 }
82 82
83 // Don't output if focused node hasn't changed. 83 // Don't output if focused node hasn't changed.
84 if (prevRange && 84 if (prevRange &&
85 evt.type == 'focus' && 85 evt.type == 'focus' &&
86 global.backgroundObj.currentRange.equals(prevRange)) 86 ChromeVoxState.instance.currentRange.equals(prevRange))
87 return; 87 return;
88 88
89 new Output().withSpeechAndBraille( 89 new Output().withSpeechAndBraille(
90 global.backgroundObj.currentRange, prevRange, evt.type) 90 ChromeVoxState.instance.currentRange, prevRange, evt.type)
91 .go(); 91 .go();
92 }, 92 },
93 93
94 /** 94 /**
95 * Makes an announcement without changing focus. 95 * Makes an announcement without changing focus.
96 * @param {Object} evt 96 * @param {Object} evt
97 */ 97 */
98 onAlert: function(evt) { 98 onAlert: function(evt) {
99 var node = evt.target; 99 var node = evt.target;
100 if (!node) 100 if (!node)
101 return; 101 return;
102 102
103 // Don't process nodes inside of web content if ChromeVox Next is inactive. 103 // Don't process nodes inside of web content if ChromeVox Next is inactive.
104 if (node.root.role != RoleType.desktop && 104 if (node.root.role != RoleType.desktop &&
105 global.backgroundObj.mode === ChromeVoxMode.CLASSIC) { 105 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC) {
106 return; 106 return;
107 } 107 }
108 108
109 var range = cursors.Range.fromNode(node); 109 var range = cursors.Range.fromNode(node);
110 110
111 new Output().withSpeechAndBraille(range, null, evt.type).go(); 111 new Output().withSpeechAndBraille(range, null, evt.type).go();
112 }, 112 },
113 113
114 /** 114 /**
115 * Provides all feedback once a focus event fires. 115 * Provides all feedback once a focus event fires.
116 * @param {Object} evt 116 * @param {Object} evt
117 */ 117 */
118 onFocus: function(evt) { 118 onFocus: function(evt) {
119 // Invalidate any previous editable text handler state. 119 // Invalidate any previous editable text handler state.
120 this.editableTextHandler_ = null; 120 this.editableTextHandler_ = null;
121 121
122 var node = evt.target; 122 var node = evt.target;
123 123
124 // Discard focus events on embeddedObject nodes. 124 // Discard focus events on embeddedObject nodes.
125 if (node.role == RoleType.embeddedObject) 125 if (node.role == RoleType.embeddedObject)
126 return; 126 return;
127 127
128 // It almost never makes sense to place focus directly on a rootWebArea. 128 // It almost never makes sense to place focus directly on a rootWebArea.
129 if (node.role == RoleType.rootWebArea) { 129 if (node.role == RoleType.rootWebArea) {
130 // Discard focus events for root web areas when focus was previously 130 // Discard focus events for root web areas when focus was previously
131 // placed on a descendant. 131 // placed on a descendant.
132 var currentRange = global.backgroundObj.currentRange; 132 var currentRange = ChromeVoxState.instance.currentRange;
133 if (currentRange && currentRange.start.node.root == node) 133 if (currentRange && currentRange.start.node.root == node)
134 return; 134 return;
135 135
136 // Discard focused root nodes without focused state set. 136 // Discard focused root nodes without focused state set.
137 if (!node.state.focused) 137 if (!node.state.focused)
138 return; 138 return;
139 139
140 // Try to find a focusable descendant. 140 // Try to find a focusable descendant.
141 node = node.find({state: {focused: true}}) || node; 141 node = node.find({state: {focused: true}}) || node;
142 } 142 }
143 143
144 if (this.isEditable_(evt.target)) 144 if (this.isEditable_(evt.target))
145 this.createEditableTextHandlerIfNeeded_(evt.target); 145 this.createEditableTextHandlerIfNeeded_(evt.target);
146 146
147 this.onEventDefault({target: node, type: 'focus'}); 147 this.onEventDefault({target: node, type: 'focus'});
148 }, 148 },
149 149
150 /** 150 /**
151 * Provides all feedback once a load complete event fires. 151 * Provides all feedback once a load complete event fires.
152 * @param {Object} evt 152 * @param {Object} evt
153 */ 153 */
154 onLoadComplete: function(evt) { 154 onLoadComplete: function(evt) {
155 global.backgroundObj.refreshMode(evt.target.docUrl); 155 ChromeVoxState.instance.refreshMode(evt.target.docUrl);
156 156
157 // Don't process nodes inside of web content if ChromeVox Next is inactive. 157 // Don't process nodes inside of web content if ChromeVox Next is inactive.
158 if (evt.target.root.role != RoleType.desktop && 158 if (evt.target.root.role != RoleType.desktop &&
159 global.backgroundObj.mode === ChromeVoxMode.CLASSIC) 159 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC)
160 return; 160 return;
161 161
162 // If initial focus was already placed on this page (e.g. if a user starts 162 // If initial focus was already placed on this page (e.g. if a user starts
163 // tabbing before load complete), then don't move ChromeVox's position on 163 // tabbing before load complete), then don't move ChromeVox's position on
164 // the page. 164 // the page.
165 if (global.backgroundObj.currentRange && 165 if (ChromeVoxState.instance.currentRange &&
166 global.backgroundObj.currentRange.start.node.role != 166 ChromeVoxState.instance.currentRange.start.node.role !=
167 RoleType.rootWebArea && 167 RoleType.rootWebArea &&
168 global.backgroundObj.currentRange.start.node.root.docUrl == 168 ChromeVoxState.instance.currentRange.start.node.root.docUrl ==
169 evt.target.docUrl) 169 evt.target.docUrl)
170 return; 170 return;
171 171
172 var root = evt.target; 172 var root = evt.target;
173 var webView = root; 173 var webView = root;
174 while (webView && webView.role != RoleType.webView) 174 while (webView && webView.role != RoleType.webView)
175 webView = webView.parent; 175 webView = webView.parent;
176 176
177 if (!webView || !webView.state.focused) 177 if (!webView || !webView.state.focused)
178 return; 178 return;
179 179
180 var node = AutomationUtil.findNodePost(root, 180 var node = AutomationUtil.findNodePost(root,
181 Dir.FORWARD, 181 Dir.FORWARD,
182 AutomationPredicate.leaf); 182 AutomationPredicate.leaf);
183 183
184 if (node) 184 if (node)
185 global.backgroundObj.currentRange = cursors.Range.fromNode(node); 185 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(node));
186 186
187 if (global.backgroundObj.currentRange) 187 if (ChromeVoxState.instance.currentRange)
188 new Output().withSpeechAndBraille( 188 new Output().withSpeechAndBraille(
189 global.backgroundObj.currentRange, null, evt.type) 189 ChromeVoxState.instance.currentRange, null, evt.type)
190 .go(); 190 .go();
191 }, 191 },
192 192
193 /** 193 /**
194 * Provides all feedback once a text selection change event fires. 194 * Provides all feedback once a text selection change event fires.
195 * @param {Object} evt 195 * @param {Object} evt
196 */ 196 */
197 onTextOrTextSelectionChanged: function(evt) { 197 onTextOrTextSelectionChanged: function(evt) {
198 if (!this.isEditable_(evt.target)) 198 if (!this.isEditable_(evt.target))
199 return; 199 return;
200 200
201 // Don't process nodes inside of web content if ChromeVox Next is inactive. 201 // Don't process nodes inside of web content if ChromeVox Next is inactive.
202 if (evt.target.root.role != RoleType.desktop && 202 if (evt.target.root.role != RoleType.desktop &&
203 global.backgroundObj.mode === ChromeVoxMode.CLASSIC) 203 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC)
204 return; 204 return;
205 205
206 if (!evt.target.state.focused) 206 if (!evt.target.state.focused)
207 return; 207 return;
208 208
209 if (!global.backgroundObj.currentRange) { 209 if (!ChromeVoxState.instance.currentRange) {
210 this.onEventDefault(evt); 210 this.onEventDefault(evt);
211 global.backgroundObj.currentRange = cursors.Range.fromNode(evt.target); 211 ChromeVoxState.instance.setCurrentRange(
212 cursors.Range.fromNode(evt.target));
212 } 213 }
213 214
214 this.createEditableTextHandlerIfNeeded_(evt.target); 215 this.createEditableTextHandlerIfNeeded_(evt.target);
215 216
216 var textChangeEvent = new cvox.TextChangeEvent( 217 var textChangeEvent = new cvox.TextChangeEvent(
217 evt.target.value, 218 evt.target.value,
218 evt.target.textSelStart, 219 evt.target.textSelStart,
219 evt.target.textSelEnd, 220 evt.target.textSelEnd,
220 true); // triggered by user 221 true); // triggered by user
221 222
222 this.editableTextHandler_.changed(textChangeEvent); 223 this.editableTextHandler_.changed(textChangeEvent);
223 224
224 new Output().withBraille( 225 new Output().withBraille(
225 global.backgroundObj.currentRange, null, evt.type) 226 ChromeVoxState.instance.currentRange, null, evt.type)
226 .go(); 227 .go();
227 }, 228 },
228 229
229 /** 230 /**
230 * Provides all feedback once a value changed event fires. 231 * Provides all feedback once a value changed event fires.
231 * @param {Object} evt 232 * @param {Object} evt
232 */ 233 */
233 onValueChanged: function(evt) { 234 onValueChanged: function(evt) {
234 // Don't process nodes inside of web content if ChromeVox Next is inactive. 235 // Don't process nodes inside of web content if ChromeVox Next is inactive.
235 if (evt.target.root.role != RoleType.desktop && 236 if (evt.target.root.role != RoleType.desktop &&
236 global.backgroundObj.mode === ChromeVoxMode.CLASSIC) 237 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC)
237 return; 238 return;
238 239
239 if (!evt.target.state.focused) 240 if (!evt.target.state.focused)
240 return; 241 return;
241 242
242 // Value change events fire on web editables when typing. Suppress them. 243 // Value change events fire on web editables when typing. Suppress them.
243 if (!global.backgroundObj.currentRange || !this.isEditable_(evt.target)) { 244 if (!ChromeVoxState.instance.currentRange ||
245 !this.isEditable_(evt.target)) {
244 this.onEventDefault(evt); 246 this.onEventDefault(evt);
245 global.backgroundObj.currentRange = cursors.Range.fromNode(evt.target); 247 ChromeVoxState.instance.setCurrentRange(
248 cursors.Range.fromNode(evt.target));
246 } 249 }
247 }, 250 },
248 251
249 /** 252 /**
250 * Handle updating the active indicator when the document scrolls. 253 * Handle updating the active indicator when the document scrolls.
251 * @override 254 * @override
252 */ 255 */
253 onScrollPositionChanged: function(evt) { 256 onScrollPositionChanged: function(evt) {
254 var currentRange = global.backgroundObj.currentRange; 257 var currentRange = ChromeVoxState.instance.currentRange;
255 if (currentRange) 258 if (currentRange)
256 new Output().withLocation(currentRange, null, evt.type).go(); 259 new Output().withLocation(currentRange, null, evt.type).go();
257 }, 260 },
258 261
259 /** 262 /**
260 * Create an editable text handler for the given node if needed. 263 * Create an editable text handler for the given node if needed.
261 * @param {Object} node 264 * @param {Object} node
262 */ 265 */
263 createEditableTextHandlerIfNeeded_: function(node) { 266 createEditableTextHandlerIfNeeded_: function(node) {
264 if (!this.editableTextHandler_ || 267 if (!this.editableTextHandler_ ||
265 node != global.backgroundObj.currentRange.start.node) { 268 node != ChromeVoxState.instance.currentRange.start.node) {
266 var start = node.textSelStart; 269 var start = node.textSelStart;
267 var end = node.textSelEnd; 270 var end = node.textSelEnd;
268 if (start > end) { 271 if (start > end) {
269 var tempOffset = end; 272 var tempOffset = end;
270 end = start; 273 end = start;
271 start = tempOffset; 274 start = tempOffset;
272 } 275 }
273 276
274 this.editableTextHandler_ = 277 this.editableTextHandler_ =
275 new cvox.ChromeVoxEditableTextBase( 278 new cvox.ChromeVoxEditableTextBase(
(...skipping 26 matching lines...) Expand all
302 if (cvox.ChromeVox.isMac) 305 if (cvox.ChromeVox.isMac)
303 return; 306 return;
304 chrome.automation.getDesktop(function(desktop) { 307 chrome.automation.getDesktop(function(desktop) {
305 global.desktopAutomationHandler = new DesktopAutomationHandler(desktop); 308 global.desktopAutomationHandler = new DesktopAutomationHandler(desktop);
306 }); 309 });
307 }; 310 };
308 311
309 DesktopAutomationHandler.init_(); 312 DesktopAutomationHandler.init_();
310 313
311 }); // goog.scope 314 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698