Skip to content

Commit

Permalink
Include _.Events module.
Browse files Browse the repository at this point in the history
  • Loading branch information
michael committed Apr 16, 2012
1 parent 658e12f commit 3bfd19c
Showing 1 changed file with 117 additions and 1 deletion.
118 changes: 117 additions & 1 deletion data.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -82,6 +82,122 @@
}; };





// _.Events
// -----------------

// Regular expression used to split event strings
var eventSplitter = /\s+/;

// A module that can be mixed in to *any object* in order to provide it with
// custom events. You may bind with `on` or remove with `off` callback functions
// to an event; trigger`-ing an event fires all callbacks in succession.
//
// var object = {};
// _.extend(object, Backbone.Events);
// object.on('expand', function(){ alert('expanded'); });
// object.trigger('expand');
//
_.Events = {

// Bind one or more space separated events, `events`, to a `callback`
// function. Passing `"all"` will bind the callback to all events fired.
on: function(events, callback, context) {

var calls, event, node, tail, list;
if (!callback) return this;
events = events.split(eventSplitter);
calls = this._callbacks || (this._callbacks = {});

// Create an immutable callback list, allowing traversal during
// modification. The tail is an empty object that will always be used
// as the next node.
while (event = events.shift()) {
list = calls[event];
node = list ? list.tail : {};
node.next = tail = {};
node.context = context;
node.callback = callback;
calls[event] = {tail: tail, next: list ? list.next : node};
}

return this;
},

// Remove one or many callbacks. If `context` is null, removes all callbacks
// with that function. If `callback` is null, removes all callbacks for the
// event. If `events` is null, removes all bound callbacks for all events.
off: function(events, callback, context) {
var event, calls, node, tail, cb, ctx;

// No events, or removing *all* events.
if (!(calls = this._callbacks)) return;
if (!(events || callback || context)) {
delete this._callbacks;
return this;
}

// Loop through the listed events and contexts, splicing them out of the
// linked list of callbacks if appropriate.
events = events ? events.split(eventSplitter) : _.keys(calls);
while (event = events.shift()) {
node = calls[event];
delete calls[event];
if (!node || !(callback || context)) continue;
// Create a new list, omitting the indicated callbacks.
tail = node.tail;
while ((node = node.next) !== tail) {
cb = node.callback;
ctx = node.context;
if ((callback && cb !== callback) || (context && ctx !== context)) {
this.on(event, cb, ctx);
}
}
}

return this;
},

// Trigger one or many events, firing all bound callbacks. Callbacks are
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
trigger: function(events) {
var event, node, calls, tail, args, all, rest;
if (!(calls = this._callbacks)) return this;
all = calls.all;
events = events.split(eventSplitter);
rest = slice.call(arguments, 1);

// For each event, walk through the linked list of callbacks twice,
// first to trigger the event, then to trigger any `"all"` callbacks.
while (event = events.shift()) {
if (node = calls[event]) {
tail = node.tail;
while ((node = node.next) !== tail) {
node.callback.apply(node.context || this, rest);
}
}
if (node = all) {
tail = node.tail;
args = [event].concat(rest);
while ((node = node.next) !== tail) {
node.callback.apply(node.context || this, args);
}
}
}

return this;
}

};

// Aliases for backwards compatibility.
_.Events.bind = _.Events.on;
_.Events.unbind = _.Events.off;



// Data.Query // Data.Query
// -------------- // --------------


Expand Down Expand Up @@ -476,4 +592,4 @@
}; };
} }
}); });
})(); })();

0 comments on commit 3bfd19c

Please sign in to comment.