Allow L.Mixin.Events.addEventListener() to accept a map in which the string keys represent one or more space-separated event types and the values represent a handler function to be called for the event(s).

Allow L.Mixin.Events.removeEventListener() to accept one or more space-separated event types. Omitting the fn parameter will remove all event handlers for the supplied event type(s).

Also allow L.Mixin.Events.removeEventListener() to accept a map where the string keys represent one or more space-separated event types and the values represent handler functions previously attached for the event(s).

Add unit tests for the above changes.
This commit is contained in:
Aaron King 2012-06-29 16:14:41 -07:00
parent 8d619899b0
commit 95ed9cdda2
2 changed files with 132 additions and 22 deletions

View File

@ -13,49 +13,89 @@ describe('Events', function() {
var obj = new Klass(),
spy = jasmine.createSpy(),
spy2 = jasmine.createSpy(),
spy3 = jasmine.createSpy();
spy3 = jasmine.createSpy(),
spy4 = jasmine.createSpy(),
spy5 = jasmine.createSpy();
spy6 = jasmine.createSpy();
obj.addEventListener('test', spy);
obj.addEventListener('test', spy2);
obj.addEventListener('other', spy3);
obj.addEventListener({ test: spy4, other: spy5 });
obj.addEventListener({'test other': spy6 })
expect(spy).not.toHaveBeenCalled();
expect(spy2).not.toHaveBeenCalled();
expect(spy3).not.toHaveBeenCalled();
expect(spy4).not.toHaveBeenCalled();
expect(spy5).not.toHaveBeenCalled();
expect(spy6).not.toHaveBeenCalled();
obj.fireEvent('test');
expect(spy).toHaveBeenCalled();
expect(spy2).toHaveBeenCalled();
expect(spy3).not.toHaveBeenCalled();
expect(spy4).toHaveBeenCalled();
expect(spy5).not.toHaveBeenCalled();
expect(spy6).toHaveBeenCalled();
expect(spy6.calls.length).toEqual(1);
});
it('should provide event object to listeners and execute them in the right context', function() {
var obj = new Klass(),
obj2 = new Klass(),
obj3 = new Klass(),
obj4 = new Klass(),
foo = {};
function listener1(e) {
expect(e.type).toEqual('test');
expect(e.target).toEqual(obj);
expect(this).toEqual(obj);
expect(e.bar).toEqual(3);
};
expect(e.baz).toEqual(1);
}
function listener2(e) {
expect(e.type).toEqual('test');
expect(e.target).toEqual(obj2);
expect(this).toEqual(foo);
};
expect(e.baz).toEqual(2);
}
function listener3(e) {
expect(e.type).toEqual('test');
expect(e.target).toEqual(obj3);
expect(this).toEqual(obj3);
expect(e.baz).toEqual(3);
}
function listener4(e) {
expect(e.type).toEqual('test');
expect(e.target).toEqual(obj4);
expect(this).toEqual(foo);
expect(e.baz).toEqual(4);
}
obj.addEventListener('test', listener1);
obj2.addEventListener('test', listener2, foo);
obj3.addEventListener({ test: listener3 });
obj4.addEventListener({ test: listener4 }, foo);
obj.fireEvent('test', {bar: 3});
obj.fireEvent('test', {baz: 1});
obj2.fireEvent('test', {baz: 2});
obj3.fireEvent('test', {baz: 3});
obj4.fireEvent('test', {baz: 4});
});
it('should not call listeners removed through #removeEventListener', function() {
var obj = new Klass(),
spy = jasmine.createSpy();
spy = jasmine.createSpy(),
spy2 = jasmine.createSpy(),
spy3 = jasmine.createSpy(),
spy4 = jasmine.createSpy(),
spy5 = jasmine.createSpy();
obj.addEventListener('test', spy);
obj.removeEventListener('test', spy);
@ -63,6 +103,28 @@ describe('Events', function() {
obj.fireEvent('test');
expect(spy).not.toHaveBeenCalled();
obj.addEventListener('test2', spy2);
obj.addEventListener('test2', spy3);
obj.removeEventListener('test2');
obj.fireEvent('test2');
expect(spy2).not.toHaveBeenCalled();
expect(spy3).not.toHaveBeenCalled();
obj.addEventListener('test3', spy4);
obj.addEventListener('test4', spy5);
obj.removeEventListener({
test3: spy4,
test4: spy5
});
obj.fireEvent('test3');
obj.fireEvent('test4');
expect(spy4).not.toHaveBeenCalled();
expect(spy5).not.toHaveBeenCalled();
});
});

View File

@ -5,13 +5,37 @@
L.Mixin = {};
L.Mixin.Events = {
addEventListener: function (/*String*/ type, /*Function*/ fn, /*(optional) Object*/ context) {
addEventListener: function (/*String or Object*/ types, /*(optional) Function or Object*/ fn, /*(optional) Object*/ context) {
var events = this._leaflet_events = this._leaflet_events || {};
events[type] = events[type] || [];
events[type].push({
// Types can be a map of types/handlers
if (typeof types === 'object') {
context = context || fn;
fn = undefined;
for (var type in types) {
if (types.hasOwnProperty(type)) {
this.addEventListener(type, types[type], context);
}
}
return this;
}
if (!fn) {
return false;
}
types = (types || '').replace(/^\s+/, '').replace(/\s+$/, '').split(' ');
for (var i = 0, ilen = types.length; i < ilen; i++) {
events[types[i]] = events[types[i]] || [];
events[types[i]].push({
action: fn,
context: context || this
});
}
return this;
},
@ -20,20 +44,44 @@ L.Mixin.Events = {
return (k in this) && (type in this[k]) && (this[k][type].length > 0);
},
removeEventListener: function (/*String*/ type, /*Function*/ fn, /*(optional) Object*/ context) {
if (!this.hasEventListeners(type)) {
removeEventListener: function (/*String or Object*/ types, /*(optional) Function*/ fn, /*(optional) Object*/ context) {
var events = this._leaflet_events;
if (typeof types === 'object') {
context = context || fn;
fn = undefined;
for (var type in types) {
if (types.hasOwnProperty(type)) {
this.off(type, types[type], context);
}
}
return this;
}
for (var i = 0, events = this._leaflet_events, len = events[type].length; i < len; i++) {
types = (types || '').replace(/^\s+/, '').replace(/\s+$/, '').split(' ');
for (var i = 0, ilen = types.length; i < ilen; i++) {
var eventType = events[types[i]] || [];
if (!this.hasEventListeners(types[i])) {
continue;
}
// Remove matching events
var j = eventType.length;
while (j--) {
if (
(events[type][i].action === fn) &&
(!context || (events[type][i].context === context))
(!fn || eventType[j].action === fn) &&
(!context || (eventType[j].context === context))
) {
events[type].splice(i, 1);
return this;
eventType.splice(j, 1);
}
}
}
return this;
},