From 37ddad508d7ac506cc0299494cfb2c2731a8fa59 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Mon, 18 Apr 2011 16:39:26 -0400 Subject: [PATCH] Issue #309, more sophisticated event handling, for unbinding events in the midst of them firing. --- backbone.js | 28 +++++++++++++++------------- test/events.js | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/backbone.js b/backbone.js index be202733..b064107e 100644 --- a/backbone.js +++ b/backbone.js @@ -90,7 +90,7 @@ if (!list) return this; for (var i = 0, l = list.length; i < l; i++) { if (callback === list[i]) { - list.splice(i, 1); + list[i] = null; break; } } @@ -102,19 +102,21 @@ // Trigger an event, firing all bound callbacks. Callbacks are passed the // same arguments as `trigger` is, apart from the event name. // Listening for `"all"` passes the true event name as the first argument. - trigger : function(ev) { - var list, calls, i, l; + trigger : function(eventName) { + var list, calls, ev, callback, args, i, l; + var both = 2; if (!(calls = this._callbacks)) return this; - if (calls[ev]) { - list = calls[ev].slice(0); - for (i = 0, l = list.length; i < l; i++) { - list[i].apply(this, Array.prototype.slice.call(arguments, 1)); - } - } - if (calls['all']) { - list = calls['all'].slice(0); - for (i = 0, l = list.length; i < l; i++) { - list[i].apply(this, arguments); + while (both--) { + ev = both ? eventName : 'all'; + if (list = calls[ev]) { + for (i = 0, l = list.length; i < l; i++) { + if (!(callback = list[i])) { + list.splice(i, 1); i--; l--; + } else { + args = both ? Array.prototype.slice.call(arguments, 1) : arguments; + callback.apply(this, args); + } + } } } return this; diff --git a/test/events.js b/test/events.js index cdc8e8df..54189619 100644 --- a/test/events.js +++ b/test/events.js @@ -39,6 +39,20 @@ $(document).ready(function() { equals(obj.counterB, 2, 'counterB should have been incremented twice.'); }); + test("Events: unbind a callback in the midst of it firing", function() { + var obj = {counter: 0}; + _.extend(obj, Backbone.Events); + var callback = function() { + obj.counter += 1; + obj.unbind('event', callback); + }; + obj.bind('event', callback); + obj.trigger('event'); + obj.trigger('event'); + obj.trigger('event'); + equals(obj.counter, 1, 'the callback should have been unbound.'); + }); + test("Events: two binds that unbind themeselves", function() { var obj = { counterA: 0, counterB: 0 }; _.extend(obj,Backbone.Events);