Add tests and documentation of ol.events.EventTarget
This commit is contained in:
@@ -5,6 +5,25 @@ goog.require('ol.events');
|
||||
goog.require('ol.events.Event');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A simplified implementation of the W3C DOM Level 2 EventTarget interface.
|
||||
* @see {@link https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget}
|
||||
*
|
||||
* There are two important simplifications compared to the specification:
|
||||
*
|
||||
* 1. The handling of `useCapture` in `addEventListener` and
|
||||
* `removeEventListener`. There is no real capture model. Instead, when
|
||||
* adding a listener, `useCapture` means that it will be added as first
|
||||
* listener, causing it to be called before other listeners. When removing a
|
||||
* listener, the `useCapture` argument will be ignored, and the listener will
|
||||
* be removed regardless of whether it was added with `useCapture` set to
|
||||
* true or false.
|
||||
* 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.
|
||||
* There is no event target hierarchy. When a listener calls
|
||||
* `stopPropagation` or `preventDefault` on an event object, it means that no
|
||||
* more listeners after this one will be called. Same as when the listener
|
||||
* returns false.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
*/
|
||||
@@ -28,7 +47,8 @@ goog.inherits(ol.events.EventTarget, goog.Disposable);
|
||||
* @param {boolean=} opt_capture Call listener before already registered
|
||||
* listeners. Default is false.
|
||||
*/
|
||||
ol.events.EventTarget.prototype.addEventListener = function(type, listener, opt_capture) {
|
||||
ol.events.EventTarget.prototype.addEventListener = function(
|
||||
type, listener, opt_capture) {
|
||||
var listeners = this.listeners_[type];
|
||||
if (!listeners) {
|
||||
listeners = this.listeners_[type] = [];
|
||||
@@ -76,6 +96,9 @@ ol.events.EventTarget.prototype.disposeInternal = function() {
|
||||
|
||||
|
||||
/**
|
||||
* Get the listeners for a specified event type. Listeners are returned in the
|
||||
* opposite order that they will be called in.
|
||||
*
|
||||
* @param {ol.events.EventType|string} type Type.
|
||||
* @return {Array.<ol.events.ListenerFunctionType>} Listeners.
|
||||
*/
|
||||
@@ -99,10 +122,10 @@ ol.events.EventTarget.prototype.hasListener = function(opt_type) {
|
||||
/**
|
||||
* @param {ol.events.EventType|string} type Type.
|
||||
* @param {ol.events.ListenerFunctionType} listener Listener.
|
||||
* @param {boolean=} opt_capture Call listener before already registered
|
||||
* listeners. Default is false.
|
||||
* @param {boolean=} opt_capture Ignored. For W3C compatibility only.
|
||||
*/
|
||||
ol.events.EventTarget.prototype.removeEventListener = function(type, listener, opt_capture) {
|
||||
ol.events.EventTarget.prototype.removeEventListener = function(
|
||||
type, listener, opt_capture) {
|
||||
var listeners = this.listeners_[type];
|
||||
if (listeners) {
|
||||
var index = listeners.indexOf(listener);
|
||||
|
||||
158
test/spec/ol/events/eventtarget.test.js
Normal file
158
test/spec/ol/events/eventtarget.test.js
Normal file
@@ -0,0 +1,158 @@
|
||||
goog.provide('ol.test.events.EventTarget');
|
||||
|
||||
|
||||
describe('ol.events.EventTarget', function() {
|
||||
var called, events, eventTarget, spy1, spy2, spy3;
|
||||
|
||||
beforeEach(function() {
|
||||
called = [];
|
||||
events = [];
|
||||
function spy(evt) {
|
||||
called.push(this.id);
|
||||
events.push(evt);
|
||||
}
|
||||
spy1 = spy.bind({id: 1});
|
||||
spy2 = spy.bind({id: 2});
|
||||
spy3 = spy.bind({id: 3});
|
||||
eventTarget = new ol.events.EventTarget();
|
||||
});
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates an instance', function() {
|
||||
expect(eventTarget).to.be.a(ol.events.EventTarget);
|
||||
});
|
||||
it('creates an empty listeners_ object', function() {
|
||||
expect(Object.keys(eventTarget.listeners_)).to.have.length(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#hasListener', function() {
|
||||
it('reports any listeners when called without argument', function() {
|
||||
expect(eventTarget.hasListener()).to.be(false);
|
||||
eventTarget.listeners_['foo'] = [function() {}];
|
||||
expect(eventTarget.hasListener()).to.be(true);
|
||||
});
|
||||
it('reports listeners for the type passed as argument', function() {
|
||||
eventTarget.listeners_['foo'] = [function() {}];
|
||||
expect(eventTarget.hasListener('foo')).to.be(true);
|
||||
expect(eventTarget.hasListener('bar')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getListeners', function() {
|
||||
it('returns listeners for a type or undefined if none', function() {
|
||||
expect(eventTarget.getListeners('foo')).to.be(undefined);
|
||||
var listeners = [function() {}];
|
||||
eventTarget.listeners_['foo'] = listeners;
|
||||
expect(eventTarget.getListeners('foo')).to.equal(listeners);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#addEventListener()', function() {
|
||||
it('has listeners for each registered type', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('bar', spy2, false);
|
||||
expect(eventTarget.hasListener('foo')).to.be(true);
|
||||
expect(eventTarget.hasListener('bar')).to.be(true);
|
||||
});
|
||||
it('registers listeners in the order determined by useCapture', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', spy2, false);
|
||||
eventTarget.addEventListener('foo', spy3, true);
|
||||
expect(eventTarget.getListeners('foo')).to.eql([spy2, spy1, spy3]);
|
||||
});
|
||||
it('does not re-add existing listeners, ignoring useCapture', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', spy2, false);
|
||||
eventTarget.addEventListener('foo', spy3, true);
|
||||
eventTarget.addEventListener('foo', spy2);
|
||||
eventTarget.addEventListener('foo', spy1, true);
|
||||
eventTarget.addEventListener('foo', spy3, false);
|
||||
expect(eventTarget.getListeners('foo')).to.eql([spy2, spy1, spy3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeEventListener()', function() {
|
||||
it('keeps the listeners registry clean', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.removeEventListener('foo', spy1, false);
|
||||
expect(eventTarget.hasListener('foo')).to.be(false);
|
||||
});
|
||||
it('removes added listeners from the listeners registry', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', spy2, false);
|
||||
eventTarget.removeEventListener('foo', spy1, false);
|
||||
expect(eventTarget.getListeners('foo')).to.have.length(1);
|
||||
});
|
||||
it('ignores the useCapture setting when removing listeners', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', spy2, false);
|
||||
eventTarget.addEventListener('foo', spy3, true);
|
||||
eventTarget.removeEventListener('foo', spy1, true);
|
||||
eventTarget.removeEventListener('foo', spy2);
|
||||
eventTarget.removeEventListener('foo', spy3, false);
|
||||
expect(eventTarget.getListeners('foo')).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#dispatchEvent()', function() {
|
||||
it('calls listeners in the correct order', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', spy2, false);
|
||||
eventTarget.addEventListener('foo', spy3, true);
|
||||
eventTarget.dispatchEvent('foo');
|
||||
expect(called).to.eql([3, 1, 2]);
|
||||
});
|
||||
it('stops propagation when listeners return false', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', function(evt) {
|
||||
spy2();
|
||||
return false;
|
||||
}, false);
|
||||
eventTarget.addEventListener('foo', spy3, false);
|
||||
eventTarget.dispatchEvent('foo');
|
||||
expect(called).to.eql([1, 2]);
|
||||
});
|
||||
it('stops propagation when listeners call preventDefault()', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.addEventListener('foo', function(evt) {
|
||||
spy2();
|
||||
evt.preventDefault();
|
||||
}, true);
|
||||
eventTarget.addEventListener('foo', spy3, false);
|
||||
eventTarget.dispatchEvent('foo');
|
||||
expect(called).to.eql([2]);
|
||||
});
|
||||
it('passes a default ol.events.Event object to listeners', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
eventTarget.dispatchEvent('foo');
|
||||
expect(events[0]).to.be.a(ol.events.Event);
|
||||
expect(events[0].type).to.be('foo');
|
||||
expect(events[0].target).to.equal(eventTarget);
|
||||
});
|
||||
it('passes a custom event object with target to listeners', function() {
|
||||
eventTarget.addEventListener('foo', spy1, false);
|
||||
var event = {
|
||||
type: 'foo'
|
||||
};
|
||||
eventTarget.dispatchEvent(event);
|
||||
expect(events[0]).to.equal(event);
|
||||
expect(events[0].target).to.equal(eventTarget);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#dispose()', function() {
|
||||
it('cleans up foreign references', function() {
|
||||
ol.events.listen(eventTarget, 'foo', spy1, false, document);
|
||||
expect(eventTarget.hasListener('foo')).to.be(true);
|
||||
eventTarget.dispose();
|
||||
expect(eventTarget.hasListener('foo')).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
goog.require('ol.events');
|
||||
goog.require('ol.events.Event');
|
||||
goog.require('ol.events.EventTarget');
|
||||
Reference in New Issue
Block a user