Allow once listeners to dispatch events of same type

This commit is contained in:
Andreas Hocevar
2016-04-28 22:07:46 +02:00
parent 36b8f31f40
commit b2c6bb11cf
2 changed files with 32 additions and 5 deletions

View File

@@ -33,6 +33,12 @@ ol.events.EventTarget = function() {
*/ */
this.pendingRemovals_ = {}; this.pendingRemovals_ = {};
/**
* @private
* @type {!Object.<string, number>}
*/
this.dispatching_ = {};
/** /**
* @private * @private
* @type {!Object.<string, Array.<ol.events.ListenerFunctionType>>} * @type {!Object.<string, Array.<ol.events.ListenerFunctionType>>}
@@ -72,19 +78,25 @@ ol.events.EventTarget.prototype.dispatchEvent = function(event) {
var listeners = this.listeners_[type]; var listeners = this.listeners_[type];
var propagate; var propagate;
if (listeners) { if (listeners) {
if (!(type in this.pendingRemovals_)) { if (!(type in this.dispatching_)) {
this.dispatching_[type] = 0;
this.pendingRemovals_[type] = 0; this.pendingRemovals_[type] = 0;
} }
++this.dispatching_[type];
for (var i = 0, ii = listeners.length; i < ii; ++i) { for (var i = 0, ii = listeners.length; i < ii; ++i) {
if (listeners[i].call(this, evt) === false || evt.propagationStopped) { if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
propagate = false; propagate = false;
break; break;
} }
} }
var pendingRemovals = this.pendingRemovals_[type]; --this.dispatching_[type];
delete this.pendingRemovals_[type]; if (this.dispatching_[type] === 0) {
while (pendingRemovals--) { var pendingRemovals = this.pendingRemovals_[type];
this.removeEventListener(type, ol.nullFunction); delete this.pendingRemovals_[type];
while (pendingRemovals--) {
this.removeEventListener(type, ol.nullFunction);
}
delete this.dispatching_[type];
} }
return propagate; return propagate;
} }

View File

@@ -73,6 +73,21 @@ describe('ol.Observable', function() {
expect(listener.callCount).to.be(1); expect(listener.callCount).to.be(1);
}); });
it('is safe to dispatch events of same type in a once listener', function() {
var callCount = 0;
observable.once('change', function() {
observable.changed();
observable.changed();
});
observable.on('change', function() {
++callCount;
});
expect(function() {
observable.changed();
}).to.not.throwException();
expect(callCount).to.be(3);
});
it('accepts an array of event types (called once for each)', function() { it('accepts an array of event types (called once for each)', function() {
observable.once(['foo', 'bar'], listener); observable.once(['foo', 'bar'], listener);