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

Side by Side Diff: chrome/browser/resources/access_chromevox/chromevox/injected/event_watcher.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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 | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview Watches for events in the browser such as focus changes.
7 */
8
9 goog.provide('cvox.ChromeVoxEventWatcher');
10
11 goog.require('cvox.ChromeVox');
12 goog.require('cvox.ChromeVoxEditableTextBase');
13 goog.require('cvox.ChromeVoxKbHandler');
14 goog.require('cvox.ChromeVoxUserCommands');
15 goog.require('cvox.DomUtil');
16
17 /**
18 * @constructor
19 */
20 cvox.ChromeVoxEventWatcher = function() {
21 };
22
23 /**
24 * @type {Object}
25 */
26 cvox.ChromeVoxEventWatcher.lastFocusedNode = null;
27
28 /**
29 * @type {string?}
30 */
31 cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = null;
32
33 /**
34 * @type {Object}
35 */
36 cvox.ChromeVoxEventWatcher.eventToEat = null;
37
38 /**
39 * @type {Element}
40 */
41 cvox.ChromeVoxEventWatcher.currentTextControl = null;
42
43 /**
44 * @type {cvox.ChromeVoxEditableTextBase}
45 */
46 cvox.ChromeVoxEventWatcher.currentTextHandler = null;
47
48 /**
49 * @type {Object}
50 */
51 cvox.ChromeVoxEventWatcher.previousTextHandlerState = null;
52
53 /**
54 * The last timestamp for the last keypress; that helps us separate
55 * user-triggered events from other events.
56 * @type {number}
57 */
58 cvox.ChromeVoxEventWatcher.lastKeypressTime = 0;
59
60 /**
61 * The delay before the timer function is first called to check on a
62 * focused text control, to see if it's been modified without an event
63 * being generated.
64 * @const
65 * @type {number}
66 */
67 cvox.ChromeVoxEventWatcher.TEXT_TIMER_INITIAL_DELAY_MS = 10;
68
69 /**
70 * The delay between subsequent calls to the timer function to check
71 * focused text controls.
72 * @const
73 * @type {number}
74 */
75 cvox.ChromeVoxEventWatcher.TEXT_TIMER_DELAY_MS = 250;
76
77 /**
78 * Add all of our event listeners to the document.
79 */
80 cvox.ChromeVoxEventWatcher.addEventListeners = function() {
81 document.addEventListener(
82 'keypress', cvox.ChromeVoxEventWatcher.keyPressEventWatcher, true);
83 document.addEventListener(
84 'keydown', cvox.ChromeVoxEventWatcher.keyDownEventWatcher, true);
85 document.addEventListener(
86 'keyup', cvox.ChromeVoxEventWatcher.keyUpEventWatcher, true);
87 document.addEventListener(
88 'focus', cvox.ChromeVoxEventWatcher.focusEventWatcher, true);
89 document.addEventListener(
90 'blur', cvox.ChromeVoxEventWatcher.blurEventWatcher, true);
91 document.addEventListener(
92 'change', cvox.ChromeVoxEventWatcher.changeEventWatcher, true);
93 document.addEventListener(
94 'select', cvox.ChromeVoxEventWatcher.selectEventWatcher, true);
95 };
96
97 /**
98 * Return the last focused node.
99 * @return {Object} The last node that was focused.
100 */
101 cvox.ChromeVoxEventWatcher.getLastFocusedNode = function() {
102 return cvox.ChromeVoxEventWatcher.lastFocusedNode;
103 };
104
105 /**
106 * Handles focus events.
107 *
108 * @param {Event} evt The focus event to process.
109 * @return {boolean} True if the default action should be performed.
110 */
111 cvox.ChromeVoxEventWatcher.focusEventWatcher = function(evt) {
112 cvox.ChromeVoxEventWatcher.lastFocusedNode = evt.target;
113 if (evt.target) {
114 if (cvox.DomUtil.isControl(evt.target)) {
115 cvox.ChromeVoxEventWatcher.lastFocusedNodeValue =
116 cvox.ChromeVoxEventWatcher.getControlValueAndStateString(
117 /** @type {Element} */(evt.target));
118 cvox.ChromeVox.tts.speak(cvox.ChromeVoxEventWatcher.lastFocusedNodeValue,
119 0, null);
120 }
121 if (evt.target.tagName == 'A' &&
122 cvox.ChromeVoxUserCommands.silenceLevel == 0) {
123 cvox.ChromeVox.tts.speak(cvox.DomUtil.getText(evt.target), 0, null);
124 }
125 cvox.ChromeVox.navigationManager.syncToNode(evt.target);
126 } else {
127 cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = null;
128 }
129 cvox.ChromeVoxEventWatcher.handleTextChanged(false);
130 return true;
131 };
132
133 /**
134 * Handles blur events.
135 *
136 * @param {Object} evt The blur event to process.
137 * @return {boolean} True if the default action should be performed.
138 */
139 cvox.ChromeVoxEventWatcher.blurEventWatcher = function(evt) {
140 cvox.ChromeVoxEventWatcher.lastFocusedNode = null;
141 cvox.ChromeVoxEventWatcher.handleTextChanged(false);
142 return true;
143 };
144
145 /**
146 * Handles key down events.
147 *
148 * @param {Object} evt The event to process.
149 * @return {boolean} True if the default action should be performed.
150 */
151 cvox.ChromeVoxEventWatcher.keyDownEventWatcher = function(evt) {
152 if (cvox.ChromeVoxEventWatcher.currentTextHandler) {
153 cvox.ChromeVoxEventWatcher.previousTextHandlerState =
154 cvox.ChromeVoxEventWatcher.currentTextHandler.saveState();
155 }
156 cvox.ChromeVoxEventWatcher.lastKeypressTime = new Date().getTime();
157
158 cvox.ChromeVoxEventWatcher.eventToEat = null;
159 if (!cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt) ||
160 cvox.ChromeVoxEventWatcher.handleControlAction(evt)) {
161 // Swallow the event immediately to prevent the arrow keys
162 // from driving controls on the web page.
163 evt.preventDefault();
164 evt.stopPropagation();
165 // Also mark this as something to be swallowed when the followup
166 // keypress/keyup counterparts to this event show up later.
167 cvox.ChromeVoxEventWatcher.eventToEat = evt;
168 return false;
169 }
170 cvox.ChromeVoxEventWatcher.handleTextChanged(true);
171 setTimeout(function() {
172 cvox.ChromeVoxEventWatcher.handleControlChanged(evt.target);
173 }, 0);
174 return true;
175 };
176
177 /**
178 * Handles key press events.
179 *
180 * @param {Object} evt The event to process.
181 * @return {boolean} True if the default action should be performed.
182 */
183 cvox.ChromeVoxEventWatcher.keyPressEventWatcher = function(evt) {
184 cvox.ChromeVoxEventWatcher.handleTextChanged(false);
185
186 if (cvox.ChromeVoxEventWatcher.eventToEat &&
187 evt.keyCode == cvox.ChromeVoxEventWatcher.eventToEat.keyCode) {
188 evt.preventDefault();
189 evt.stopPropagation();
190 return false;
191 }
192 return true;
193 };
194
195 /**
196 * Handles key up events.
197 *
198 * @param {Object} evt The event to process.
199 * @return {boolean} True if the default action should be performed.
200 */
201 cvox.ChromeVoxEventWatcher.keyUpEventWatcher = function(evt) {
202 if (cvox.ChromeVoxEventWatcher.eventToEat &&
203 evt.keyCode == cvox.ChromeVoxEventWatcher.eventToEat.keyCode) {
204 evt.stopPropagation();
205 evt.preventDefault();
206 return false;
207 }
208 return true;
209 };
210
211 /**
212 * Handles change events.
213 *
214 * @param {Object} evt The event to process.
215 * @return {boolean} True if the default action should be performed.
216 */
217 cvox.ChromeVoxEventWatcher.changeEventWatcher = function(evt) {
218 if (cvox.ChromeVoxEventWatcher.handleTextChanged(false)) {
219 return true;
220 }
221 return true;
222 };
223
224 /**
225 * Handles select events.
226 *
227 * @param {Object} evt The event to process.
228 * @return {boolean} True if the default action should be performed.
229 */
230 cvox.ChromeVoxEventWatcher.selectEventWatcher = function(evt) {
231 if (cvox.ChromeVoxEventWatcher.handleTextChanged(false)) {
232 return true;
233 }
234 return true;
235 };
236
237 /**
238 * Speaks updates to editable text controls as needed.
239 * @param {boolean} isKeypress Was this change triggered by a keypress?
240 * @return {boolean} True if an editable text control has focus.
241 */
242 cvox.ChromeVoxEventWatcher.handleTextChanged = function(isKeypress) {
243 var currentFocus = document.activeElement;
244
245 if (currentFocus != cvox.ChromeVoxEventWatcher.currentTextControl) {
246 if (cvox.ChromeVoxEventWatcher.currentTextControl) {
247 cvox.ChromeVoxEventWatcher.currentTextControl.removeEventListener(
248 'input', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
249 cvox.ChromeVoxEventWatcher.currentTextControl.removeEventListener(
250 'click', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
251 }
252 cvox.ChromeVoxEventWatcher.currentTextControl = null;
253 cvox.ChromeVoxEventWatcher.currentTextHandler = null;
254 cvox.ChromeVoxEventWatcher.previousTextHandlerState = null;
255
256 if (currentFocus == null) {
257 return false;
258 }
259
260 if (currentFocus.constructor == HTMLInputElement &&
261 cvox.DomUtil.isInputTypeText(currentFocus)) {
262 cvox.ChromeVoxEventWatcher.currentTextControl = currentFocus;
263 cvox.ChromeVoxEventWatcher.currentTextHandler =
264 new cvox.ChromeVoxEditableHTMLInput(currentFocus, cvox.ChromeVox.tts);
265 } else if (currentFocus.constructor == HTMLTextAreaElement) {
266 cvox.ChromeVoxEventWatcher.currentTextControl = currentFocus;
267 cvox.ChromeVoxEventWatcher.currentTextHandler =
268 new cvox.ChromeVoxEditableTextArea(currentFocus, cvox.ChromeVox.tts);
269 }
270
271 if (cvox.ChromeVoxEventWatcher.currentTextControl) {
272 cvox.ChromeVoxEventWatcher.currentTextControl.addEventListener(
273 'input', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
274 cvox.ChromeVoxEventWatcher.currentTextControl.addEventListener(
275 'click', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
276 cvox.ChromeVoxEventWatcher.currentTextHandler.describe();
277 window.setTimeout(cvox.ChromeVoxEventWatcher.textTimer,
278 cvox.ChromeVoxEventWatcher.TEXT_TIMER_INITIAL_DELAY_MS);
279 cvox.ChromeVox.navigationManager.syncToNode(
280 cvox.ChromeVoxEventWatcher.currentTextControl);
281 }
282
283 return (null != cvox.ChromeVoxEventWatcher.currentTextHandler);
284 }
285
286 if (cvox.ChromeVoxEventWatcher.currentTextHandler) {
287 var handler = cvox.ChromeVoxEventWatcher.currentTextHandler;
288 window.setTimeout(function() {
289 // If this update was not triggered by an explicit user keypress,
290 // and we already started speaking an update to this text control
291 // very recently (less than 50 ms ago), restore the control to its
292 // previous state and then speak the new update (interrupting any
293 // ongoing speech). That way, if the user presses a key and the
294 // page's javascript causes a few more characters to be inserted,
295 // we'll speak it as one big update.
296 var now = new Date().getTime();
297 if (!isKeypress &&
298 handler.needsUpdate() &&
299 cvox.ChromeVoxEventWatcher.previousTextHandlerState &&
300 now - cvox.ChromeVoxEventWatcher.lastKeypressTime < 50) {
301 handler.restoreState(
302 cvox.ChromeVoxEventWatcher.previousTextHandlerState);
303 }
304
305 handler.update();
306 }, 0);
307 return true;
308 } else {
309 }
310
311 return false;
312 };
313
314 /**
315 * Called repeatedly while a text box has focus, because many changes
316 * to a text box don't ever generate events - e.g. if the page's javascript
317 * changes the contents of the text box after some delay.
318 */
319 cvox.ChromeVoxEventWatcher.textTimer = function() {
320 if (cvox.ChromeVoxEventWatcher.currentTextHandler &&
321 cvox.ChromeVoxEventWatcher.currentTextHandler.needsUpdate()) {
322 cvox.ChromeVoxEventWatcher.handleTextChanged(false);
323 }
324
325 if (cvox.ChromeVoxEventWatcher.currentTextControl) {
326 window.setTimeout(cvox.ChromeVoxEventWatcher.textTimer,
327 cvox.ChromeVoxEventWatcher.TEXT_TIMER_DELAY_MS);
328 }
329 };
330
331 /**
332 * Speaks updates to other form controls as needed.
333 * @param {Element} control The target control.
334 */
335 cvox.ChromeVoxEventWatcher.handleControlChanged = function(control) {
336 var newValue = cvox.ChromeVoxEventWatcher.getControlValueAndStateString(
337 control);
338
339 if (control != cvox.ChromeVoxEventWatcher.lastFocusedNode) {
340 cvox.ChromeVoxEventWatcher.lastFocusedNode = control;
341 cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = newValue;
342 return;
343 }
344
345 if (newValue == cvox.ChromeVoxEventWatcher.lastFocusedNodeValue) {
346 return;
347 }
348
349 cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = newValue;
350
351 var announceChange = false;
352
353 if (control.tagName == 'SELECT') {
354 announceChange = true;
355 }
356
357 if (control.tagName == 'INPUT') {
358 switch (control.type) {
359 case 'checkbox':
360 case 'color':
361 case 'datetime':
362 case 'datetime-local':
363 case 'date':
364 case 'month':
365 case 'radio':
366 case 'range':
367 case 'week':
368 announceChange = true;
369 break;
370 default:
371 break;
372 }
373 }
374
375 if (announceChange && cvox.ChromeVoxUserCommands.silenceLevel == 0) {
376 cvox.ChromeVox.tts.speak(newValue, 0, null);
377 }
378 };
379
380 /**
381 * Handle actions on form controls triggered by key presses.
382 * @param {Object} evt The event.
383 * @return {boolean} True if this key event was handled.
384 */
385 cvox.ChromeVoxEventWatcher.handleControlAction = function(evt) {
386 var control = evt.target;
387
388 if (control.tagName == 'SELECT' &&
389 (evt.keyCode == 13 || evt.keyCode == 32)) { // Enter or Space
390 evt.preventDefault();
391 evt.stopPropagation();
392 // Do nothing, but eat this keystroke
393 return true;
394 }
395
396 if (control.tagName == 'INPUT' && control.type == 'range') {
397 var value = parseFloat(control.value);
398 var step;
399 if (control.step && control.step > 0.0) {
400 step = control.step;
401 } else if (control.min && control.max) {
402 var range = (control.max - control.min);
403 if (range > 2 && range < 31) {
404 step = 1;
405 } else {
406 step = (control.max - control.min) / 10;
407 }
408 } else {
409 step = 1;
410 }
411
412 if (evt.keyCode == 37 || evt.keyCode == 38) { // left or up
413 value -= step;
414 } else if (evt.keyCode == 39 || evt.keyCode == 40) { // right or down
415 value += step;
416 }
417
418 if (control.max && value > control.max) {
419 value = control.max;
420 }
421 if (control.min && value < control.min) {
422 value = control.min;
423 }
424
425 control.value = value;
426 }
427
428 return false;
429 };
430
431 /**
432 * Get a string representing a control's value and state.
433 * @param {Element} control A control.
434 * @return {string} A string representing a control's value and state.
435 */
436 cvox.ChromeVoxEventWatcher.getControlValueAndStateString = function(
437 control) {
438 var controlValue = cvox.DomUtil.getValue(control);
439 var controlState = cvox.DomUtil.getBasicNodeState(control);
440 var controlTitle = cvox.DomUtil.getTitle(control);
441 var controlLabel = cvox.DomUtil.getLabel(control, false);
442 if ((controlTitle.length < 1) && (controlLabel.length < 1)) {
443 controlLabel = cvox.DomUtil.getLabel(control, true);
444 }
445 return controlLabel + ' ' + controlTitle + ' ' + controlValue + ' ' +
446 controlState;
447 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698