Chromium Code Reviews| Index: chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js |
| diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js |
| index 6abdb980da3fb97047fd01d0c1fa8e98aa49325b..0c552d39b1d90fae1c76746e1204bfc5dfd2a04f 100644 |
| --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js |
| +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js |
| @@ -65,6 +65,23 @@ Background = function() { |
| /** @type {!ClassicCompatibility} @private */ |
| this.compat_ = new ClassicCompatibility(); |
| + /** @type {Array<Object>} A queue of incoming events. @private */ |
| + this.eventQueue_ = []; |
|
Peter Lundblad
2015/08/20 08:30:05
I suggest putting the event queue into its own cla
|
| + |
| + /** |
| + * @type {?number} |
| + * The window.setTimeout timer ID of the event queue timer. |
| + * @private |
| + */ |
| + this.eventQueueTimerId_ = null; |
|
Peter Lundblad
2015/08/20 08:30:05
Since your code already relies on timer ids being
|
| + |
| + /** |
| + * @type {number} |
| + * How long to hold events in the event queue before executing them. |
| + * @const |
| + */ |
| + this.EVENT_QUEUE_DELAY_MS = 10; |
|
David Tseng
2015/08/19 17:19:25
nit: make private.
Peter Lundblad
2015/08/20 08:30:05
Put constants outside of the constructor, directly
|
| + |
| // Manually bind all functions to |this|. |
| for (var func in this) { |
| if (typeof(this[func]) == 'function') |
| @@ -88,6 +105,12 @@ Background = function() { |
| valueChanged: this.onValueChanged |
| }; |
| + /** |
| + * The object that speaks changes to an editable text field. |
| + * @type {?cvox.ChromeVoxEditableTextBase} |
|
Peter Lundblad
2015/08/20 08:30:05
Document when this is null.
|
| + */ |
| + this.editableTextHandler_ = null; |
| + |
| chrome.automation.getDesktop(this.onGotDesktop); |
| // Handle messages directed to the Next background page. |
| @@ -123,7 +146,7 @@ Background.prototype = { |
| onGotDesktop: function(desktop) { |
| // Register all automation event listeners. |
| for (var eventType in this.listeners_) |
| - desktop.addEventListener(eventType, this.listeners_[eventType], true); |
| + desktop.addEventListener(eventType, this.addToEventQueue_, true); |
| // Register a tree change observer. |
| chrome.automation.addTreeChangeObserver(this.onTreeChange); |
| @@ -401,6 +424,59 @@ Background.prototype = { |
| }, |
| /** |
| + * Add an event to the event queue so that we can avoid ignore |
|
David Tseng
2015/08/19 17:19:25
avoid or ignore
|
| + * transient states - for example if focus moves to one node and |
| + * then immediately another, or if a node gains focus and |
| + * immediately changes its selection. |
| + * |
| + * @param {Object} evt |
| + */ |
|
David Tseng
2015/08/19 17:19:25
nit: @private
|
| + addToEventQueue_: function(evt) { |
| + evt.enqueueTime = new Date(); |
|
Peter Lundblad
2015/08/20 08:30:05
Should we extend the automation api with a time fi
|
| + this.eventQueue_.push(evt); |
| + if (!this.eventQueueTimerId_) { |
| + this.eventQueueTimerId_ = window.setTimeout( |
| + this.executeNextEventFromQueue_, this.EVENT_QUEUE_DELAY_MS); |
| + } |
| + }, |
| + |
| + /** |
| + * Filter duplicates from the event queue, then pop the first item |
| + * off and if it's time to execute it, do so, otherwise set the timer |
| + * to wake up again. |
|
David Tseng
2015/08/19 17:19:25
nit: @private
|
| + */ |
| + executeNextEventFromQueue_: function() { |
|
Peter Lundblad
2015/08/20 08:30:05
nit: s/execute/handle/ ?
|
| + this.eventQueueTimerId_ = null; |
| + |
| + if (this.eventQueue_.length == 0) { |
| + return; |
| + } |
|
David Tseng
2015/08/19 17:19:25
nit: remove braces.
|
| + |
| + // Assuming the queue is in increasing order of enqueue time, remove all except the |
| + // last item of each type. |
| + var lastTimeForEventType = {}; |
|
Peter Lundblad
2015/08/20 08:30:05
Why not just store the object reference instead of
|
| + this.eventQueue_.forEach(function(evt) { |
| + lastTimeForEventType[evt.type] = evt.enqueueTime; |
| + }); |
| + this.eventQueue_ = this.eventQueue_.filter(function(evt) { |
| + return evt.enqueueTime == lastTimeForEventType[evt.type]; |
|
David Tseng
2015/08/19 17:19:25
Any issues doing this generically? For example, do
|
| + }); |
| + |
| + while (this.eventQueue_.length) { |
| + var now = new Date(); |
| + var delta = now - this.eventQueue_[0].enqueueTime; |
| + if (delta < this.EVENT_QUEUE_DELAY_MS) { |
| + this.eventQueueTimerId_ = window.setTimeout( |
| + this.executeNextEventFromQueue_, this.EVENT_QUEUE_DELAY_MS - delta); |
| + return; |
| + } |
| + |
| + var evt = this.eventQueue_.shift(); |
| + this.listeners_[evt.type](evt); |
| + } |
| + }, |
| + |
| + /** |
| * Provides all feedback once ChromeVox's focus changes. |
| * @param {Object} evt |
| */ |
| @@ -454,6 +530,11 @@ Background.prototype = { |
| Dir.FORWARD, |
| AutomationPredicate.focused) || node; |
| } |
| + |
| + if (evt.target.role == 'textField' || evt.target.role == 'textBox') { |
|
David Tseng
2015/08/19 17:19:25
nit: please use RoleType.textField and RoleType.te
|
| + this.createEditableTextHandlerIfNeeded_(evt.target); |
| + } |
| + |
| this.onEventDefault({target: node, type: 'focus'}); |
| }, |
| @@ -511,23 +592,14 @@ Background.prototype = { |
| this.currentRange_ = cursors.Range.fromNode(evt.target); |
| } |
| + this.createEditableTextHandlerIfNeeded_(evt.target); |
| var textChangeEvent = new cvox.TextChangeEvent( |
| evt.target.value, |
| evt.target.textSelStart, |
| evt.target.textSelEnd, |
| true); // triggered by user |
| - if (!this.editableTextHandler || |
| - evt.target != this.currentRange_.start.node) { |
| - this.editableTextHandler = |
| - new cvox.ChromeVoxEditableTextBase( |
| - textChangeEvent.value, |
| - textChangeEvent.start, |
| - textChangeEvent.end, |
| - evt.target.state['protected'], |
| - cvox.ChromeVox.tts); |
| - } |
| + this.editableTextHandler_.changed(textChangeEvent); |
| - this.editableTextHandler.changed(textChangeEvent); |
| new Output().withBraille( |
| this.currentRange_, null, evt.type) |
| .go(); |
| @@ -689,7 +761,23 @@ Background.prototype = { |
| }.bind(this)); |
| this.mode_ = mode; |
| - } |
| + }, |
| + |
| + /** |
| + * Create an editable text handler for the given node if needed. |
| + * @param {Object} node |
|
David Tseng
2015/08/19 17:19:25
s/Object/AutomationNode
|
| + */ |
|
David Tseng
2015/08/19 17:19:25
@private
|
| + createEditableTextHandlerIfNeeded_: function(node) { |
| + if (!this.editableTextHandler_ || node != this.currentRange_.start.node) { |
| + this.editableTextHandler_ = |
| + new cvox.ChromeVoxEditableTextBase( |
| + node.value, |
| + node.textSelStart, |
| + node.textSelEnd, |
| + node.state['protected'], |
| + cvox.ChromeVox.tts); |
| + } |
| + }, |
| }; |
| /** @type {Background} */ |