Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Clean up `Backbone.Events`.

* Refactor `Backbone.Events` for increased clarity.
* Update documentation to include multiple events.
* Use `event` consistently throughout.
  • Loading branch information...
commit f92fa9a0bd061679f4ee3a42be252f7ebc6f3966 1 parent c8cbde2
brad dunbar braddunbar authored

Showing 1 changed file with 44 additions and 39 deletions. Show diff stats Hide diff stats

  1. +44 39 backbone.js
83 backbone.js
@@ -82,71 +82,76 @@
82 82 //
83 83 Backbone.Events = {
84 84
85   - // Bind an event, specified by a string name, `ev`, to a `callback`
  85 + // Bind one or more space separated events, `events`, to a `callback`
86 86 // function. Passing `"all"` will bind the callback to all events fired.
87 87 on: function(events, callback, context) {
88   - var ev;
  88 + var calls, event, node, tail, list;
89 89 if (!callback) return this;
90 90 events = events.split(/\s+/);
91   - var calls = this._callbacks || (this._callbacks = {});
92   - while (ev = events.shift()) {
  91 + calls = this._callbacks || (this._callbacks = {});
  92 + while (event = events.shift()) {
93 93 // Create an immutable callback list, allowing traversal during
94 94 // modification. The tail is an empty object that will always be used
95 95 // as the next node.
96   - var list = calls[ev] || (calls[ev] = {});
97   - var tail = list.tail || (list.tail = list.next = {});
98   - tail.callback = callback;
99   - tail.context = context;
100   - list.tail = tail.next = {};
  96 + list = calls[event];
  97 + node = list ? list.tail : {};
  98 + node.next = tail = {};
  99 + node.context = context;
  100 + node.callback = callback;
  101 + calls[event] = {tail: tail, next: list ? list.next : node};
101 102 }
102 103 return this;
103 104 },
104 105
105 106 // Remove one or many callbacks. If `context` is null, removes all callbacks
106 107 // with that function. If `callback` is null, removes all callbacks for the
107   - // event. If `ev` is null, removes all bound callbacks for all events.
  108 + // event. If `events` is null, removes all bound callbacks for all events.
108 109 off: function(events, callback, context) {
109   - var ev, calls, node;
  110 + var event, calls, node, tail, cb, ctx;
110 111 if (!events) {
111 112 delete this._callbacks;
112 113 } else if (calls = this._callbacks) {
113 114 events = events.split(/\s+/);
114   - while (ev = events.shift()) {
115   - node = calls[ev];
116   - delete calls[ev];
  115 + while (event = events.shift()) {
  116 + node = calls[event];
  117 + delete calls[event];
117 118 if (!callback || !node) continue;
118   - // Create a new list, omitting the indicated event/context pairs.
119   - while ((node = node.next) && node.next) {
120   - if (node.callback === callback &&
121   - (!context || node.context === context)) continue;
122   - this.on(ev, node.callback, node.context);
  119 + // Create a new list, omitting the indicated callbacks.
  120 + tail = node.tail;
  121 + while ((node = node.next) !== tail) {
  122 + cb = node.callback;
  123 + ctx = node.context;
  124 + if (cb !== callback || (context && ctx !== context)) {
  125 + this.on(event, cb, ctx);
  126 + }
123 127 }
124 128 }
125 129 }
126 130 return this;
127 131 },
128 132
129   - // Trigger an event, firing all bound callbacks. Callbacks are passed the
130   - // same arguments as `trigger` is, apart from the event name.
  133 + // Trigger one more many events, firing all bound callbacks. Callbacks are
  134 + // passed the same arguments as `trigger` is, apart from the event name.
131 135 // Listening for `"all"` passes the true event name as the first argument.
132 136 trigger: function(events) {
133 137 var event, node, calls, tail, args, all, rest;
134 138 if (!(calls = this._callbacks)) return this;
135   - all = calls['all'];
136   - (events = events.split(/\s+/)).push(null);
137   - // Save references to the current heads & tails.
138   - while (event = events.shift()) {
139   - if (all) events.push({next: all.next, tail: all.tail, event: event});
140   - if (!(node = calls[event])) continue;
141   - events.push({next: node.next, tail: node.tail});
142   - }
143   - // Traverse each list, stopping when the saved tail is reached.
  139 + all = calls.all;
  140 + events = events.split(/\s+/);
144 141 rest = slice.call(arguments, 1);
145   - while (node = events.pop()) {
146   - tail = node.tail;
147   - args = node.event ? [node.event].concat(rest) : rest;
148   - while ((node = node.next) !== tail) {
149   - node.callback.apply(node.context || this, args);
  142 + while (event = events.shift()) {
  143 + if (node = calls[event]) {
  144 + tail = node.tail;
  145 + while ((node = node.next) !== tail) {
  146 + node.callback.apply(node.context || this, rest);
  147 + }
  148 + }
  149 + if (node = all) {
  150 + tail = node.tail;
  151 + args = [event].concat(rest);
  152 + while ((node = node.next) !== tail) {
  153 + node.callback.apply(node.context || this, args);
  154 + }
150 155 }
151 156 }
152 157 return this;
@@ -766,12 +771,12 @@
766 771 // Sets need to update their indexes when models change ids. All other
767 772 // events simply proxy through. "add" and "remove" events that originate
768 773 // in other collections are ignored.
769   - _onModelEvent: function(ev, model, collection, options) {
770   - if ((ev == 'add' || ev == 'remove') && collection != this) return;
771   - if (ev == 'destroy') {
  774 + _onModelEvent: function(event, model, collection, options) {
  775 + if ((event == 'add' || event == 'remove') && collection != this) return;
  776 + if (event == 'destroy') {
772 777 this.remove(model, options);
773 778 }
774   - if (model && ev === 'change:' + model.idAttribute) {
  779 + if (model && event === 'change:' + model.idAttribute) {
775 780 delete this._byId[model.previous(model.idAttribute)];
776 781 this._byId[model.id] = model;
777 782 }

0 comments on commit f92fa9a

Please sign in to comment.
Something went wrong with that request. Please try again.