goog.require('cvox.Focuser');
goog.require('cvox.History');
goog.require('cvox.LiveRegions');
-goog.require('cvox.LiveRegionsDeprecated');
goog.require('cvox.Memoize');
goog.require('cvox.NavigationSpeaker');
goog.require('cvox.PlatformFilter'); // TODO: Find a better place for this.
goog.require('cvox.PlatformUtil');
+goog.require('cvox.QueueMode');
goog.require('cvox.TextHandlerInterface');
goog.require('cvox.UserEventDetail');
cvox.ChromeVoxEventWatcher.WAIT_TIME_MS_ = 10;
/**
- * Amount of time in ms to wait before considering a subtree modified event to
- * be the start of a new burst of subtree modified events.
- * @const
- * @type {number}
- * @private
- */
-cvox.ChromeVoxEventWatcher.SUBTREE_MODIFIED_BURST_DURATION_ = 1000;
-
-
-/**
- * Number of subtree modified events that are part of the same burst to process
- * before we give up on processing any more events from that burst.
- * @const
- * @type {number}
- * @private
- */
-cvox.ChromeVoxEventWatcher.SUBTREE_MODIFIED_BURST_COUNT_LIMIT_ = 3;
-
-
-/**
* Maximum number of live regions that we will attempt to process.
* @const
* @type {number}
cvox.ChromeVoxEventWatcher.textMutationObserver_ = null;
cvox.ChromeVoxEventWatcher.addEventListeners_(doc);
-
- /**
- * The time when the last burst of subtree modified events started
- * @type {number}
- * @private
- */
- cvox.ChromeVoxEventWatcher.lastSubtreeModifiedEventBurstTime_ = 0;
-
- /**
- * The number of subtree modified events in the current burst.
- * @type {number}
- * @private
- */
- cvox.ChromeVoxEventWatcher.subtreeModifiedEventsCount_ = 0;
};
cvox.ChromeVoxEventWatcher.addEventListener_(doc,
'click', cvox.ChromeVoxEventWatcher.mouseClickEventWatcher, true);
- if (typeof(window.WebKitMutationObserver) != 'undefined') {
- cvox.ChromeVoxEventWatcher.mutationObserver_ =
- new window.WebKitMutationObserver(
- cvox.ChromeVoxEventWatcher.mutationHandler);
- var observerTarget = null;
- if (doc.documentElement) {
- observerTarget = doc.documentElement;
- } else if (doc.document && doc.document.documentElement) {
- observerTarget = doc.document.documentElement;
- }
- if (observerTarget) {
- cvox.ChromeVoxEventWatcher.mutationObserver_.observe(
- observerTarget,
- /** @type {!MutationObserverInit} */ ({
- childList: true,
- attributes: true,
- characterData: true,
- subtree: true,
- attributeOldValue: true,
- characterDataOldValue: true
- }));
- }
- } else {
- cvox.ChromeVoxEventWatcher.addEventListener_(doc, 'DOMSubtreeModified',
- cvox.ChromeVoxEventWatcher.subtreeModifiedEventWatcher, true);
+ cvox.ChromeVoxEventWatcher.mutationObserver_ =
+ new window.WebKitMutationObserver(
+ cvox.ChromeVoxEventWatcher.mutationHandler);
+ var observerTarget = null;
+ if (doc.documentElement) {
+ observerTarget = doc.documentElement;
+ } else if (doc.document && doc.document.documentElement) {
+ observerTarget = doc.document.documentElement;
+ }
+ if (observerTarget) {
+ cvox.ChromeVoxEventWatcher.mutationObserver_.observe(
+ observerTarget,
+ /** @type {!MutationObserverInit} */ ({
+ childList: true,
+ attributes: true,
+ characterData: true,
+ subtree: true,
+ attributeOldValue: true,
+ characterDataOldValue: true
+ }));
}
};
if (cvox.ChromeVoxEventWatcher.getInitialVisibility() ||
cvox.ChromeVoxEventWatcher.handleDialogFocus(target)) {
- queueMode = cvox.AbstractTts.QUEUE_MODE_QUEUE;
+ queueMode = cvox.QueueMode.QUEUE;
}
if (cvox.ChromeVox.navigationManager.clearPageSel(true)) {
- queueMode = cvox.AbstractTts.QUEUE_MODE_QUEUE;
+ queueMode = cvox.QueueMode.QUEUE;
}
// Navigate to this control so that it will be the same for focus as for
if (cvox.ChromeVoxEditableTextBase.eventTypingEcho && (speakChar &&
cvox.DomPredicates.editTextPredicate([document.activeElement])) &&
document.activeElement.type !== 'password') {
- cvox.ChromeVox.tts.speak(String.fromCharCode(evt.charCode), 0);
+ cvox.ChromeVox.tts.speak(String.fromCharCode(evt.charCode),
+ cvox.QueueMode.FLUSH);
}
cvox.ChromeVoxEventWatcher.addEvent(evt);
if (cvox.ChromeVoxEventWatcher.eventToEat &&
* @return {boolean} True if the default action should be performed.
*/
cvox.ChromeVoxEventWatcher.clipboardEventWatcher = function(evt) {
- cvox.ChromeVox.tts.speak(cvox.ChromeVox.msgs.getMsg(evt.type).toLowerCase());
+ cvox.ChromeVox.tts.speak(cvox.ChromeVox.msgs.getMsg(evt.type).toLowerCase(),
+ cvox.QueueMode.QUEUE);
var text = '';
switch (evt.type) {
case 'paste':
text = window.getSelection().toString();
break;
}
- cvox.ChromeVox.tts.speak(text, cvox.AbstractTts.QUEUE_MODE_QUEUE);
+ cvox.ChromeVox.tts.speak(text, cvox.QueueMode.QUEUE);
cvox.ChromeVox.navigationManager.clearPageSel();
return true;
};
};
/**
- * Watches for DOM subtree modified events.
- *
- * @param {Event} evt The event to add to the queue.
- * @return {boolean} True if the default action should be performed.
- */
-cvox.ChromeVoxEventWatcher.subtreeModifiedEventWatcher = function(evt) {
- if (!evt || !evt.target) {
- return true;
- }
- cvox.ChromeVoxEventWatcher.addEvent(evt);
- return true;
-};
-
-/**
* Listens for WebKit visibility change events.
*/
cvox.ChromeVoxEventWatcher.visibilityChangeWatcher = function() {
};
/**
- * Handles DOM subtree modified events passed to it from the events queue.
- * If the change involves an ARIA live region, then speak it.
- *
- * @param {Event} evt The event to handle.
- */
-cvox.ChromeVoxEventWatcher.subtreeModifiedHandler = function(evt) {
- // Subtree modified events can happen in bursts. If several events happen at
- // the same time, trying to process all of them will slow ChromeVox to
- // a crawl and make the page itself unresponsive (ie, Google+).
- // Before processing subtree modified events, make sure that it is not part of
- // a large burst of events.
- // TODO (clchen): Revisit this after the DOM mutation events are
- // available in Chrome.
- var currentTime = new Date().getTime();
-
- if ((cvox.ChromeVoxEventWatcher.lastSubtreeModifiedEventBurstTime_ +
- cvox.ChromeVoxEventWatcher.SUBTREE_MODIFIED_BURST_DURATION_) >
- currentTime) {
- cvox.ChromeVoxEventWatcher.subtreeModifiedEventsCount_++;
- if (cvox.ChromeVoxEventWatcher.subtreeModifiedEventsCount_ >
- cvox.ChromeVoxEventWatcher.SUBTREE_MODIFIED_BURST_COUNT_LIMIT_) {
- return;
- }
- } else {
- cvox.ChromeVoxEventWatcher.lastSubtreeModifiedEventBurstTime_ = currentTime;
- cvox.ChromeVoxEventWatcher.subtreeModifiedEventsCount_ = 1;
- }
-
- if (!evt || !evt.target) {
- return;
- }
- var target = /** @type {Element} */ (evt.target);
- var regions = cvox.AriaUtil.getLiveRegions(target);
- for (var i = 0; (i < regions.length) &&
- (i < cvox.ChromeVoxEventWatcher.MAX_LIVE_REGIONS_); i++) {
- cvox.LiveRegionsDeprecated.updateLiveRegion(
- regions[i], cvox.ChromeVoxEventWatcher.queueMode_(), false);
- }
-};
-
-/**
* Sets up the text handler.
* @return {boolean} True if an editable text control has focus.
*/
cvox.ChromeVox.navigationManager.currentDialog)) {
cvox.ChromeVox.navigationManager.currentDialog = null;
- cvox.ChromeVox.tts.speak(
+ cvox.ChromeVoxEventWatcher.speakAnnotationWithCategory_(
cvox.ChromeVox.msgs.getMsg('exiting_dialog'),
- cvox.ChromeVoxEventWatcher.queueMode_(),
- cvox.AbstractTts.PERSONALITY_ANNOTATION);
+ cvox.TtsCategory.NAV);
return true;
}
} else {
if (dialog) {
cvox.ChromeVox.navigationManager.currentDialog = dialog;
- cvox.ChromeVox.tts.speak(
+ cvox.ChromeVoxEventWatcher.speakAnnotationWithCategory_(
cvox.ChromeVox.msgs.getMsg('entering_dialog'),
- cvox.ChromeVoxEventWatcher.queueMode_(),
- cvox.AbstractTts.PERSONALITY_ANNOTATION);
+ cvox.TtsCategory.NAV);
+
if (role == 'alertdialog') {
var dialogDescArray =
cvox.DescriptionUtil.getFullDescriptionsFromChildren(null, dialog);
var descSpeaker = new cvox.NavigationSpeaker();
descSpeaker.speakDescriptionArray(dialogDescArray,
- cvox.AbstractTts.QUEUE_MODE_QUEUE,
+ cvox.QueueMode.QUEUE,
null);
}
return true;
};
/**
+ * Speak the given text with the annotation personality and the given
+ * speech queue utterance category.
+ * @param {string} text The text to speak.
+ * @param {string} category The category of text, used by the speech queue
+ * when flushing all speech from the same category while leaving other
+ * speech in the queue.
+ * @private
+ */
+cvox.ChromeVoxEventWatcher.speakAnnotationWithCategory_ = function(
+ text, category) {
+ var properties = {};
+ var src = cvox.AbstractTts.PERSONALITY_ANNOTATION;
+ for (var key in src) {
+ properties[key] = src[key];
+ }
+ properties['category'] = category;
+ cvox.ChromeVox.tts.speak(
+ text,
+ cvox.ChromeVoxEventWatcher.queueMode_(),
+ properties);
+};
+
+/**
* Returns true if we should wait to process events.
* @param {number} lastFocusTimestamp The timestamp of the last focus event.
* @param {number} firstTimestamp The timestamp of the first event.
* a result of an event or navigation. The first utterance that's spoken
* after an explicit user action like a key press will flush, and
* subsequent events will return a category flush.
- * @return {number} Either QUEUE_MODE_FLUSH or QUEUE_MODE_QUEUE.
+ * @return {cvox.QueueMode} The queue mode.
* @private
*/
cvox.ChromeVoxEventWatcher.queueMode_ = function() {
if (cvox.ChromeVoxEventWatcher.shouldFlushNextUtterance) {
cvox.ChromeVoxEventWatcher.shouldFlushNextUtterance = false;
- return cvox.AbstractTts.QUEUE_MODE_FLUSH;
+ return cvox.QueueMode.FLUSH;
}
- return cvox.AbstractTts.QUEUE_MODE_CATEGORY_FLUSH;
+ return cvox.QueueMode.CATEGORY_FLUSH;
};
cvox.ChromeVoxEventWatcher.events_ = [];
for (i = 0; evt = events[i]; i++) {
var prevEvt = events[i - 1] || {};
- if ((i >= lastFocusIndex || evt.type == 'LiveRegion' ||
- evt.type == 'DOMSubtreeModified') &&
+ if ((i >= lastFocusIndex || evt.type == 'LiveRegion') &&
(prevEvt.type != 'focus' || evt.type != 'change')) {
cvox.ChromeVoxEventWatcher.events_.push(evt);
}
if (b.type != 'LiveRegion' && a.type == 'LiveRegion') {
return 1;
}
- if (b.type != 'DOMSubtreeModified' && a.type == 'DOMSubtreeModified') {
- return 1;
- }
return -1;
});
cvox.ChromeVoxEventWatcher.speakLiveRegion_(
evt.assertive, evt.navDescriptions);
break;
- case 'DOMSubtreeModified':
- cvox.ChromeVoxEventWatcher.subtreeModifiedHandler(evt);
- break;
}
};