Skip to content

Commit

Permalink
Allow L.Mixin.Events.addEventListener() to accept a map in which the …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Guiswa committed Jun 29, 2012
1 parent 8d61989 commit 95ed9cd
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 22 deletions.
74 changes: 68 additions & 6 deletions spec/suites/core/EventsSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,56 +13,118 @@ 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);

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();
});
});

Expand Down
80 changes: 64 additions & 16 deletions src/core/Events.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
action: fn,
context: context || this
});

// 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;
},

Expand All @@ -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++) {
if (
(events[type][i].action === fn) &&
(!context || (events[type][i].context === context))
) {
events[type].splice(i, 1);
return this;

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 (
(!fn || eventType[j].action === fn) &&
(!context || (eventType[j].context === context))
) {
eventType.splice(j, 1);
}
}
}

return this;
},

Expand Down

0 comments on commit 95ed9cd

Please sign in to comment.