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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/access_chromevox/chromevox/injected/event_watcher.js
===================================================================
--- chrome/browser/resources/access_chromevox/chromevox/injected/event_watcher.js (revision 0)
+++ chrome/browser/resources/access_chromevox/chromevox/injected/event_watcher.js (revision 0)
@@ -0,0 +1,447 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Watches for events in the browser such as focus changes.
+ */
+
+goog.provide('cvox.ChromeVoxEventWatcher');
+
+goog.require('cvox.ChromeVox');
+goog.require('cvox.ChromeVoxEditableTextBase');
+goog.require('cvox.ChromeVoxKbHandler');
+goog.require('cvox.ChromeVoxUserCommands');
+goog.require('cvox.DomUtil');
+
+/**
+ * @constructor
+ */
+cvox.ChromeVoxEventWatcher = function() {
+};
+
+/**
+ * @type {Object}
+ */
+cvox.ChromeVoxEventWatcher.lastFocusedNode = null;
+
+/**
+ * @type {string?}
+ */
+cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = null;
+
+/**
+ * @type {Object}
+ */
+cvox.ChromeVoxEventWatcher.eventToEat = null;
+
+/**
+ * @type {Element}
+ */
+cvox.ChromeVoxEventWatcher.currentTextControl = null;
+
+/**
+ * @type {cvox.ChromeVoxEditableTextBase}
+ */
+cvox.ChromeVoxEventWatcher.currentTextHandler = null;
+
+/**
+ * @type {Object}
+ */
+cvox.ChromeVoxEventWatcher.previousTextHandlerState = null;
+
+/**
+ * The last timestamp for the last keypress; that helps us separate
+ * user-triggered events from other events.
+ * @type {number}
+ */
+cvox.ChromeVoxEventWatcher.lastKeypressTime = 0;
+
+/**
+ * The delay before the timer function is first called to check on a
+ * focused text control, to see if it's been modified without an event
+ * being generated.
+ * @const
+ * @type {number}
+ */
+cvox.ChromeVoxEventWatcher.TEXT_TIMER_INITIAL_DELAY_MS = 10;
+
+/**
+ * The delay between subsequent calls to the timer function to check
+ * focused text controls.
+ * @const
+ * @type {number}
+ */
+cvox.ChromeVoxEventWatcher.TEXT_TIMER_DELAY_MS = 250;
+
+/**
+ * Add all of our event listeners to the document.
+ */
+cvox.ChromeVoxEventWatcher.addEventListeners = function() {
+ document.addEventListener(
+ 'keypress', cvox.ChromeVoxEventWatcher.keyPressEventWatcher, true);
+ document.addEventListener(
+ 'keydown', cvox.ChromeVoxEventWatcher.keyDownEventWatcher, true);
+ document.addEventListener(
+ 'keyup', cvox.ChromeVoxEventWatcher.keyUpEventWatcher, true);
+ document.addEventListener(
+ 'focus', cvox.ChromeVoxEventWatcher.focusEventWatcher, true);
+ document.addEventListener(
+ 'blur', cvox.ChromeVoxEventWatcher.blurEventWatcher, true);
+ document.addEventListener(
+ 'change', cvox.ChromeVoxEventWatcher.changeEventWatcher, true);
+ document.addEventListener(
+ 'select', cvox.ChromeVoxEventWatcher.selectEventWatcher, true);
+};
+
+/**
+ * Return the last focused node.
+ * @return {Object} The last node that was focused.
+ */
+cvox.ChromeVoxEventWatcher.getLastFocusedNode = function() {
+ return cvox.ChromeVoxEventWatcher.lastFocusedNode;
+};
+
+/**
+ * Handles focus events.
+ *
+ * @param {Event} evt The focus event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.focusEventWatcher = function(evt) {
+ cvox.ChromeVoxEventWatcher.lastFocusedNode = evt.target;
+ if (evt.target) {
+ if (cvox.DomUtil.isControl(evt.target)) {
+ cvox.ChromeVoxEventWatcher.lastFocusedNodeValue =
+ cvox.ChromeVoxEventWatcher.getControlValueAndStateString(
+ /** @type {Element} */(evt.target));
+ cvox.ChromeVox.tts.speak(cvox.ChromeVoxEventWatcher.lastFocusedNodeValue,
+ 0, null);
+ }
+ if (evt.target.tagName == 'A' &&
+ cvox.ChromeVoxUserCommands.silenceLevel == 0) {
+ cvox.ChromeVox.tts.speak(cvox.DomUtil.getText(evt.target), 0, null);
+ }
+ cvox.ChromeVox.navigationManager.syncToNode(evt.target);
+ } else {
+ cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = null;
+ }
+ cvox.ChromeVoxEventWatcher.handleTextChanged(false);
+ return true;
+};
+
+/**
+ * Handles blur events.
+ *
+ * @param {Object} evt The blur event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.blurEventWatcher = function(evt) {
+ cvox.ChromeVoxEventWatcher.lastFocusedNode = null;
+ cvox.ChromeVoxEventWatcher.handleTextChanged(false);
+ return true;
+};
+
+/**
+ * Handles key down events.
+ *
+ * @param {Object} evt The event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.keyDownEventWatcher = function(evt) {
+ if (cvox.ChromeVoxEventWatcher.currentTextHandler) {
+ cvox.ChromeVoxEventWatcher.previousTextHandlerState =
+ cvox.ChromeVoxEventWatcher.currentTextHandler.saveState();
+ }
+ cvox.ChromeVoxEventWatcher.lastKeypressTime = new Date().getTime();
+
+ cvox.ChromeVoxEventWatcher.eventToEat = null;
+ if (!cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt) ||
+ cvox.ChromeVoxEventWatcher.handleControlAction(evt)) {
+ // Swallow the event immediately to prevent the arrow keys
+ // from driving controls on the web page.
+ evt.preventDefault();
+ evt.stopPropagation();
+ // Also mark this as something to be swallowed when the followup
+ // keypress/keyup counterparts to this event show up later.
+ cvox.ChromeVoxEventWatcher.eventToEat = evt;
+ return false;
+ }
+ cvox.ChromeVoxEventWatcher.handleTextChanged(true);
+ setTimeout(function() {
+ cvox.ChromeVoxEventWatcher.handleControlChanged(evt.target);
+ }, 0);
+ return true;
+};
+
+/**
+ * Handles key press events.
+ *
+ * @param {Object} evt The event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.keyPressEventWatcher = function(evt) {
+ cvox.ChromeVoxEventWatcher.handleTextChanged(false);
+
+ if (cvox.ChromeVoxEventWatcher.eventToEat &&
+ evt.keyCode == cvox.ChromeVoxEventWatcher.eventToEat.keyCode) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Handles key up events.
+ *
+ * @param {Object} evt The event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.keyUpEventWatcher = function(evt) {
+ if (cvox.ChromeVoxEventWatcher.eventToEat &&
+ evt.keyCode == cvox.ChromeVoxEventWatcher.eventToEat.keyCode) {
+ evt.stopPropagation();
+ evt.preventDefault();
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Handles change events.
+ *
+ * @param {Object} evt The event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.changeEventWatcher = function(evt) {
+ if (cvox.ChromeVoxEventWatcher.handleTextChanged(false)) {
+ return true;
+ }
+ return true;
+};
+
+/**
+ * Handles select events.
+ *
+ * @param {Object} evt The event to process.
+ * @return {boolean} True if the default action should be performed.
+ */
+cvox.ChromeVoxEventWatcher.selectEventWatcher = function(evt) {
+ if (cvox.ChromeVoxEventWatcher.handleTextChanged(false)) {
+ return true;
+ }
+ return true;
+};
+
+/**
+ * Speaks updates to editable text controls as needed.
+ * @param {boolean} isKeypress Was this change triggered by a keypress?
+ * @return {boolean} True if an editable text control has focus.
+ */
+cvox.ChromeVoxEventWatcher.handleTextChanged = function(isKeypress) {
+ var currentFocus = document.activeElement;
+
+ if (currentFocus != cvox.ChromeVoxEventWatcher.currentTextControl) {
+ if (cvox.ChromeVoxEventWatcher.currentTextControl) {
+ cvox.ChromeVoxEventWatcher.currentTextControl.removeEventListener(
+ 'input', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
+ cvox.ChromeVoxEventWatcher.currentTextControl.removeEventListener(
+ 'click', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
+ }
+ cvox.ChromeVoxEventWatcher.currentTextControl = null;
+ cvox.ChromeVoxEventWatcher.currentTextHandler = null;
+ cvox.ChromeVoxEventWatcher.previousTextHandlerState = null;
+
+ if (currentFocus == null) {
+ return false;
+ }
+
+ if (currentFocus.constructor == HTMLInputElement &&
+ cvox.DomUtil.isInputTypeText(currentFocus)) {
+ cvox.ChromeVoxEventWatcher.currentTextControl = currentFocus;
+ cvox.ChromeVoxEventWatcher.currentTextHandler =
+ new cvox.ChromeVoxEditableHTMLInput(currentFocus, cvox.ChromeVox.tts);
+ } else if (currentFocus.constructor == HTMLTextAreaElement) {
+ cvox.ChromeVoxEventWatcher.currentTextControl = currentFocus;
+ cvox.ChromeVoxEventWatcher.currentTextHandler =
+ new cvox.ChromeVoxEditableTextArea(currentFocus, cvox.ChromeVox.tts);
+ }
+
+ if (cvox.ChromeVoxEventWatcher.currentTextControl) {
+ cvox.ChromeVoxEventWatcher.currentTextControl.addEventListener(
+ 'input', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
+ cvox.ChromeVoxEventWatcher.currentTextControl.addEventListener(
+ 'click', cvox.ChromeVoxEventWatcher.changeEventWatcher, false);
+ cvox.ChromeVoxEventWatcher.currentTextHandler.describe();
+ window.setTimeout(cvox.ChromeVoxEventWatcher.textTimer,
+ cvox.ChromeVoxEventWatcher.TEXT_TIMER_INITIAL_DELAY_MS);
+ cvox.ChromeVox.navigationManager.syncToNode(
+ cvox.ChromeVoxEventWatcher.currentTextControl);
+ }
+
+ return (null != cvox.ChromeVoxEventWatcher.currentTextHandler);
+ }
+
+ if (cvox.ChromeVoxEventWatcher.currentTextHandler) {
+ var handler = cvox.ChromeVoxEventWatcher.currentTextHandler;
+ window.setTimeout(function() {
+ // If this update was not triggered by an explicit user keypress,
+ // and we already started speaking an update to this text control
+ // very recently (less than 50 ms ago), restore the control to its
+ // previous state and then speak the new update (interrupting any
+ // ongoing speech). That way, if the user presses a key and the
+ // page's javascript causes a few more characters to be inserted,
+ // we'll speak it as one big update.
+ var now = new Date().getTime();
+ if (!isKeypress &&
+ handler.needsUpdate() &&
+ cvox.ChromeVoxEventWatcher.previousTextHandlerState &&
+ now - cvox.ChromeVoxEventWatcher.lastKeypressTime < 50) {
+ handler.restoreState(
+ cvox.ChromeVoxEventWatcher.previousTextHandlerState);
+ }
+
+ handler.update();
+ }, 0);
+ return true;
+ } else {
+ }
+
+ return false;
+};
+
+/**
+ * Called repeatedly while a text box has focus, because many changes
+ * to a text box don't ever generate events - e.g. if the page's javascript
+ * changes the contents of the text box after some delay.
+ */
+cvox.ChromeVoxEventWatcher.textTimer = function() {
+ if (cvox.ChromeVoxEventWatcher.currentTextHandler &&
+ cvox.ChromeVoxEventWatcher.currentTextHandler.needsUpdate()) {
+ cvox.ChromeVoxEventWatcher.handleTextChanged(false);
+ }
+
+ if (cvox.ChromeVoxEventWatcher.currentTextControl) {
+ window.setTimeout(cvox.ChromeVoxEventWatcher.textTimer,
+ cvox.ChromeVoxEventWatcher.TEXT_TIMER_DELAY_MS);
+ }
+};
+
+/**
+ * Speaks updates to other form controls as needed.
+ * @param {Element} control The target control.
+ */
+cvox.ChromeVoxEventWatcher.handleControlChanged = function(control) {
+ var newValue = cvox.ChromeVoxEventWatcher.getControlValueAndStateString(
+ control);
+
+ if (control != cvox.ChromeVoxEventWatcher.lastFocusedNode) {
+ cvox.ChromeVoxEventWatcher.lastFocusedNode = control;
+ cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = newValue;
+ return;
+ }
+
+ if (newValue == cvox.ChromeVoxEventWatcher.lastFocusedNodeValue) {
+ return;
+ }
+
+ cvox.ChromeVoxEventWatcher.lastFocusedNodeValue = newValue;
+
+ var announceChange = false;
+
+ if (control.tagName == 'SELECT') {
+ announceChange = true;
+ }
+
+ if (control.tagName == 'INPUT') {
+ switch (control.type) {
+ case 'checkbox':
+ case 'color':
+ case 'datetime':
+ case 'datetime-local':
+ case 'date':
+ case 'month':
+ case 'radio':
+ case 'range':
+ case 'week':
+ announceChange = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (announceChange && cvox.ChromeVoxUserCommands.silenceLevel == 0) {
+ cvox.ChromeVox.tts.speak(newValue, 0, null);
+ }
+};
+
+/**
+ * Handle actions on form controls triggered by key presses.
+ * @param {Object} evt The event.
+ * @return {boolean} True if this key event was handled.
+ */
+cvox.ChromeVoxEventWatcher.handleControlAction = function(evt) {
+ var control = evt.target;
+
+ if (control.tagName == 'SELECT' &&
+ (evt.keyCode == 13 || evt.keyCode == 32)) { // Enter or Space
+ evt.preventDefault();
+ evt.stopPropagation();
+ // Do nothing, but eat this keystroke
+ return true;
+ }
+
+ if (control.tagName == 'INPUT' && control.type == 'range') {
+ var value = parseFloat(control.value);
+ var step;
+ if (control.step && control.step > 0.0) {
+ step = control.step;
+ } else if (control.min && control.max) {
+ var range = (control.max - control.min);
+ if (range > 2 && range < 31) {
+ step = 1;
+ } else {
+ step = (control.max - control.min) / 10;
+ }
+ } else {
+ step = 1;
+ }
+
+ if (evt.keyCode == 37 || evt.keyCode == 38) { // left or up
+ value -= step;
+ } else if (evt.keyCode == 39 || evt.keyCode == 40) { // right or down
+ value += step;
+ }
+
+ if (control.max && value > control.max) {
+ value = control.max;
+ }
+ if (control.min && value < control.min) {
+ value = control.min;
+ }
+
+ control.value = value;
+ }
+
+ return false;
+};
+
+/**
+ * Get a string representing a control's value and state.
+ * @param {Element} control A control.
+ * @return {string} A string representing a control's value and state.
+ */
+cvox.ChromeVoxEventWatcher.getControlValueAndStateString = function(
+ control) {
+ var controlValue = cvox.DomUtil.getValue(control);
+ var controlState = cvox.DomUtil.getBasicNodeState(control);
+ var controlTitle = cvox.DomUtil.getTitle(control);
+ var controlLabel = cvox.DomUtil.getLabel(control, false);
+ if ((controlTitle.length < 1) && (controlLabel.length < 1)) {
+ controlLabel = cvox.DomUtil.getLabel(control, true);
+ }
+ return controlLabel + ' ' + controlTitle + ' ' + controlValue + ' ' +
+ controlState;
+};
Property changes on: chrome/browser/resources/access_chromevox/chromevox/injected/event_watcher.js
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698