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

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

Issue 1942683005: Refactor event handler classes to make it easier to add new event type listeners. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months 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('AutomationObjectConstructorInstaller');
11 goog.require('BaseAutomationHandler'); 12 goog.require('BaseAutomationHandler');
12 goog.require('ChromeVoxState'); 13 goog.require('ChromeVoxState');
13 goog.require('editing.TextEditHandler'); 14 goog.require('editing.TextEditHandler');
14 15
15 goog.scope(function() { 16 goog.scope(function() {
16 var AutomationEvent = chrome.automation.AutomationEvent; 17 var AutomationEvent = chrome.automation.AutomationEvent;
17 var AutomationNode = chrome.automation.AutomationNode; 18 var AutomationNode = chrome.automation.AutomationNode;
18 var Dir = constants.Dir; 19 var Dir = constants.Dir;
20 var EventType = chrome.automation.EventType;
19 var RoleType = chrome.automation.RoleType; 21 var RoleType = chrome.automation.RoleType;
20 22
21 /** 23 /**
22 * @param {!AutomationNode} node 24 * @param {!AutomationNode} node
23 * @constructor 25 * @constructor
24 * @extends {BaseAutomationHandler} 26 * @extends {BaseAutomationHandler}
25 */ 27 */
26 DesktopAutomationHandler = function(node) { 28 DesktopAutomationHandler = function(node) {
27 BaseAutomationHandler.call(this, node); 29 BaseAutomationHandler.call(this, node);
28 30
29 /** 31 /**
30 * The object that speaks changes to an editable text field. 32 * The object that speaks changes to an editable text field.
31 * @type {editing.TextEditHandler} 33 * @type {editing.TextEditHandler}
32 */ 34 */
33 this.textEditHandler_ = null; 35 this.textEditHandler_ = null;
34 36
35 /** 37 /**
36 * The last time we handled a value changed event. 38 * The last time we handled a value changed event.
37 * @type {!Date} 39 * @type {!Date}
38 * @private 40 * @private
39 */ 41 */
40 this.lastValueChanged_ = new Date(0); 42 this.lastValueChanged_ = new Date(0);
41 43
42 // The focused state gets set on the containing webView node. 44 var e = EventType;
43 var webView = node.find({role: RoleType.webView, state: {focused: true}}); 45 this.addListener_(e.activedescendantchanged, this.onActiveDescendantChanged);
44 if (webView) { 46 this.addListener_(e.alert, this.onAlert);
45 var root = webView.find({role: RoleType.rootWebArea}); 47 this.addListener_(e.ariaAttributeChanged, this.onEventIfInRange);
46 if (root) { 48 this.addListener_(e.checkedStateChanged, this.onEventIfInRange);
47 this.onLoadComplete( 49 this.addListener_(e.focus, this.onFocus);
48 {target: root, 50 this.addListener_(e.hover, this.onEventWithFlushedOutput);
49 type: chrome.automation.EventType.loadComplete}); 51 this.addListener_(e.loadComplete, this.onLoadComplete);
50 } 52 this.addListener_(e.menuEnd, this.onMenuEnd);
51 } 53 this.addListener_(e.menuListItemSelected, this.onEventDefault);
54 this.addListener_(e.menuStart, this.onMenuStart);
55 this.addListener_(e.scrollPositionChanged, this.onScrollPositionChanged);
56 this.addListener_(e.selection, this.onEventWithFlushedOutput);
57 this.addListener_(e.textChanged, this.onTextChanged);
58 this.addListener_(e.textSelectionChanged, this.onTextSelectionChanged);
59 this.addListener_(e.valueChanged, this.onValueChanged);
52 60
53 chrome.automation.getFocus((function(focus) { 61 AutomationObjectConstructorInstaller.init(node, function() {
54 if (focus) 62 chrome.automation.getFocus((function(focus) {
55 this.onFocus({target: focus, type: 'focus'}); 63 if (ChromeVoxState.instance.mode != ChromeVoxMode.FORCE_NEXT)
56 }).bind(this)); 64 return;
65
66 if (focus) {
67 this.onFocus(
68 new chrome.automation.AutomationEvent(EventType.focus, focus));
69 }
70 }).bind(this));
71 }.bind(this));
57 }; 72 };
58 73
59 /** 74 /**
60 * Time to wait until processing more value changed events. 75 * Time to wait until processing more value changed events.
61 * @const {number} 76 * @const {number}
62 */ 77 */
63 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500; 78 DesktopAutomationHandler.VMIN_VALUE_CHANGE_DELAY_MS = 500;
64 79
65 DesktopAutomationHandler.prototype = { 80 DesktopAutomationHandler.prototype = {
66 __proto__: BaseAutomationHandler.prototype, 81 __proto__: BaseAutomationHandler.prototype,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 output.withBraille( 126 output.withBraille(
112 ChromeVoxState.instance.currentRange, prevRange, evt.type); 127 ChromeVoxState.instance.currentRange, prevRange, evt.type);
113 } else { 128 } else {
114 // Delegate event handling to the text edit handler for braille. 129 // Delegate event handling to the text edit handler for braille.
115 this.textEditHandler_.onEvent(evt); 130 this.textEditHandler_.onEvent(evt);
116 } 131 }
117 output.go(); 132 output.go();
118 }, 133 },
119 134
120 /** 135 /**
136 * @param {!AutomationEvent} evt
137 */
138 onEventIfInRange: function(evt) {
139 // TODO(dtseng): Consider the end of the current range as well.
140 if (AutomationUtil.isDescendantOf(
141 global.backgroundObj.currentRange.start.node, evt.target) ||
142 evt.target.state.focused)
143 this.onEventDefault(evt);
144 },
145
146 /**
147 * @param {!AutomationEvent} evt
148 */
149 onEventWithFlushedOutput: function(evt) {
150 Output.flushNextSpeechUtterance();
151 this.onEventDefault(evt);
152 },
153
154 /**
121 * Makes an announcement without changing focus. 155 * Makes an announcement without changing focus.
122 * @param {Object} evt 156 * @param {!AutomationEvent} evt
157 */
158 onActiveDescendantChanged: function(evt) {
159 if (!evt.target.activeDescendant)
160 return;
161 this.onEventDefault(new chrome.automation.AutomationEvent(
162 EventType.focus, evt.target.activeDescendant));
163 },
164
165 /**
166 * Makes an announcement without changing focus.
167 * @param {!AutomationEvent} evt
123 */ 168 */
124 onAlert: function(evt) { 169 onAlert: function(evt) {
125 var node = evt.target; 170 var node = evt.target;
126 if (!node) 171 if (!node)
127 return; 172 return;
128 173
129 // Don't process nodes inside of web content if ChromeVox Next is inactive. 174 // Don't process nodes inside of web content if ChromeVox Next is inactive.
130 if (node.root.role != RoleType.desktop && 175 if (node.root.role != RoleType.desktop &&
131 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC) { 176 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC) {
132 return; 177 return;
133 } 178 }
134 179
135 var range = cursors.Range.fromNode(node); 180 var range = cursors.Range.fromNode(node);
136 181
137 new Output().withSpeechAndBraille(range, null, evt.type).go(); 182 new Output().withSpeechAndBraille(range, null, evt.type).go();
138 }, 183 },
139 184
140 /** 185 /**
141 * Provides all feedback once a focus event fires. 186 * Provides all feedback once a focus event fires.
142 * @param {Object} evt 187 * @param {!AutomationEvent} evt
143 */ 188 */
144 onFocus: function(evt) { 189 onFocus: function(evt) {
145 // Invalidate any previous editable text handler state. 190 // Invalidate any previous editable text handler state.
146 this.textEditHandler_ = null; 191 this.textEditHandler_ = null;
147 192
148 var node = evt.target; 193 var node = evt.target;
149 194
150 // Discard focus events on embeddedObject and client nodes. 195 // Discard focus events on embeddedObject and client nodes.
151 if (node.role == RoleType.embeddedObject || node.role == RoleType.client) 196 if (node.role == RoleType.embeddedObject || node.role == RoleType.client)
152 return; 197 return;
153 198
154 this.createTextEditHandlerIfNeeded_(evt.target); 199 this.createTextEditHandlerIfNeeded_(evt.target);
155 200
156 // Since we queue output mostly for live regions support and there isn't a 201 // Since we queue output mostly for live regions support and there isn't a
157 // reliable way to know if this focus event resulted from a user's explicit 202 // reliable way to know if this focus event resulted from a user's explicit
158 // action, only flush when the focused node is not web content. 203 // action, only flush when the focused node is not web content.
159 if (node.root.role == RoleType.desktop) 204 if (node.root.role == RoleType.desktop)
160 Output.flushNextSpeechUtterance(); 205 Output.flushNextSpeechUtterance();
161 206
162 this.onEventDefault( 207 this.onEventDefault(
163 /** @type {!AutomationEvent} */ 208 new chrome.automation.AutomationEvent(EventType.focus, node));
164 ({target: node, type: chrome.automation.EventType.focus}));
165 }, 209 },
166 210
167 /** 211 /**
168 * Provides all feedback once a load complete event fires. 212 * Provides all feedback once a load complete event fires.
169 * @param {Object} evt 213 * @param {!AutomationEvent} evt
170 */ 214 */
171 onLoadComplete: function(evt) { 215 onLoadComplete: function(evt) {
172 ChromeVoxState.instance.refreshMode(evt.target.docUrl); 216 ChromeVoxState.instance.refreshMode(evt.target.docUrl);
173 217
174 // Don't process nodes inside of web content if ChromeVox Next is inactive. 218 // Don't process nodes inside of web content if ChromeVox Next is inactive.
175 if (evt.target.root.role != RoleType.desktop && 219 if (evt.target.root.role != RoleType.desktop &&
176 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC) 220 ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC)
177 return; 221 return;
178 222
179 chrome.automation.getFocus((function(focus) { 223 chrome.automation.getFocus((function(focus) {
180 if (!focus) 224 if (!focus)
181 return; 225 return;
182 226
183 // If initial focus was already placed on this page (e.g. if a user starts 227 // If initial focus was already placed on this page (e.g. if a user starts
184 // tabbing before load complete), then don't move ChromeVox's position on 228 // tabbing before load complete), then don't move ChromeVox's position on
185 // the page. 229 // the page.
186 if (ChromeVoxState.instance.currentRange && 230 if (ChromeVoxState.instance.currentRange &&
187 ChromeVoxState.instance.currentRange.start.node.root == focus.root) 231 ChromeVoxState.instance.currentRange.start.node.root == focus.root)
188 return; 232 return;
189 233
190 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(focus)); 234 ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(focus));
191 new Output().withRichSpeechAndBraille( 235 new Output().withRichSpeechAndBraille(
192 ChromeVoxState.instance.currentRange, null, evt.type).go(); 236 ChromeVoxState.instance.currentRange, null, evt.type).go();
193 }).bind(this)); 237 }).bind(this));
194 }, 238 },
195 239
196 /** @override */ 240
241 /**
242 * Provides all feedback once a text changed event fires.
243 * @param {!AutomationEvent} evt
244 */
197 onTextChanged: function(evt) { 245 onTextChanged: function(evt) {
198 if (evt.target.state.editable) 246 if (evt.target.state.editable)
199 this.onEditableChanged_(evt); 247 this.onEditableChanged_(evt);
200 }, 248 },
201 249
202 /** @override */ 250 /**
251 * Provides all feedback once a text selection changed event fires.
252 * @param {!AutomationEvent} evt
253 */
203 onTextSelectionChanged: function(evt) { 254 onTextSelectionChanged: function(evt) {
204 if (evt.target.state.editable) 255 if (evt.target.state.editable)
205 this.onEditableChanged_(evt); 256 this.onEditableChanged_(evt);
206 }, 257 },
207 258
208 /** 259 /**
209 * Provides all feedback once a change event in a text field fires. 260 * Provides all feedback once a change event in a text field fires.
210 * @param {!AutomationEvent} evt 261 * @param {!AutomationEvent} evt
211 * @private 262 * @private
212 */ 263 */
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 310
260 this.lastValueChanged_ = new Date(); 311 this.lastValueChanged_ = new Date();
261 312
262 new Output().format('$value', evt.target) 313 new Output().format('$value', evt.target)
263 .go(); 314 .go();
264 } 315 }
265 }, 316 },
266 317
267 /** 318 /**
268 * Handle updating the active indicator when the document scrolls. 319 * Handle updating the active indicator when the document scrolls.
269 * @override 320 * @param {!AutomationEvent} evt
270 */ 321 */
271 onScrollPositionChanged: function(evt) { 322 onScrollPositionChanged: function(evt) {
272 if (ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC) 323 if (ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC)
273 return; 324 return;
274 325
275 var currentRange = ChromeVoxState.instance.currentRange; 326 var currentRange = ChromeVoxState.instance.currentRange;
276 if (currentRange) 327 if (currentRange)
277 new Output().withLocation(currentRange, null, evt.type).go(); 328 new Output().withLocation(currentRange, null, evt.type).go();
278 }, 329 },
279 330
280 /** @override */ 331 /**
332 * Provides all feedback once a menu start event fires.
333 * @param {!AutomationEvent} evt
334 */
281 onMenuStart: function(evt) { 335 onMenuStart: function(evt) {
282 global.backgroundObj.startExcursion(); 336 global.backgroundObj.startExcursion();
283 this.onEventDefault(evt); 337 this.onEventDefault(evt);
284 }, 338 },
285 339
286 /** @override */ 340 /**
341 * Provides all feedback once a menu end event fires.
342 * @param {!AutomationEvent} evt
343 */
287 onMenuEnd: function(evt) { 344 onMenuEnd: function(evt) {
288 this.onEventDefault(evt); 345 this.onEventDefault(evt);
289 global.backgroundObj.endExcursion(); 346 global.backgroundObj.endExcursion();
290 }, 347 },
291 348
292 /** 349 /**
293 * Create an editable text handler for the given node if needed. 350 * Create an editable text handler for the given node if needed.
294 * @param {!AutomationNode} node 351 * @param {!AutomationNode} node
295 */ 352 */
296 createTextEditHandlerIfNeeded_: function(node) { 353 createTextEditHandlerIfNeeded_: function(node) {
(...skipping 12 matching lines...) Expand all
309 if (cvox.ChromeVox.isMac) 366 if (cvox.ChromeVox.isMac)
310 return; 367 return;
311 chrome.automation.getDesktop(function(desktop) { 368 chrome.automation.getDesktop(function(desktop) {
312 global.desktopAutomationHandler = new DesktopAutomationHandler(desktop); 369 global.desktopAutomationHandler = new DesktopAutomationHandler(desktop);
313 }); 370 });
314 }; 371 };
315 372
316 DesktopAutomationHandler.init_(); 373 DesktopAutomationHandler.init_();
317 374
318 }); // goog.scope 375 }); // goog.scope
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698