Comparing version 0.6.2 to 0.6.3
@@ -5,3 +5,3 @@ { | ||
"description": "Client-side framework for structured applications.", | ||
"version": "0.6.2", | ||
"version": "0.6.3", | ||
"keywords": [ | ||
@@ -8,0 +8,0 @@ "clientside" |
@@ -107,4 +107,5 @@ define([ | ||
off: function(name, callback, context) { | ||
var retain, ev, events, names, i, l, j, k; | ||
if (!this._events || !this.multipleEvents('off', name, [callback, context])) return this; | ||
// Remove all callbacks for all events. | ||
if (!name && !callback && !context) { | ||
@@ -115,18 +116,35 @@ this._events = void 0; | ||
names = name ? [name] : _.keys(this._events); | ||
for (i = 0, l = names.length; i < l; i++) { | ||
var names = name ? [name] : _.keys(this._events); | ||
for (var i = 0, length = names.length; i < length; i++) { | ||
name = names[i]; | ||
if (events = this._events[name]) { | ||
this._events[name] = retain = []; | ||
if (callback || context) { | ||
for (j = 0, k = events.length; j < k; j++) { | ||
ev = events[j]; | ||
if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || | ||
(context && context !== ev.context)) { | ||
retain.push(ev); | ||
} | ||
} | ||
// Bail out if there are no events stored. | ||
var events = this._events[name]; | ||
if (!events) continue; | ||
// Remove all callbacks for this event. | ||
if (!callback && !context) { | ||
delete this._events[name]; | ||
continue; | ||
} | ||
// Find any remaining events. | ||
var remaining = []; | ||
for (var j = 0, k = events.length; j < k; j++) { | ||
var event = events[j]; | ||
if ( | ||
callback && callback !== event.callback && | ||
callback !== event.callback._callback || | ||
context && context !== event.context | ||
) { | ||
remaining.push(event); | ||
} | ||
if (!retain.length) delete this._events[name]; | ||
} | ||
// Replace events if there are any remaining. Otherwise, clean up. | ||
if (remaining.length) { | ||
this._events[name] = remaining; | ||
} else { | ||
delete this._events[name]; | ||
} | ||
} | ||
@@ -137,2 +155,19 @@ | ||
// Tell this object to stop listening to either specific events ... or | ||
// to every object it's currently listening to. | ||
stopListening: function(obj, name, callback) { | ||
var listeningTo = this._listeningTo; | ||
if (!listeningTo) return this; | ||
var remove = !name && !callback; | ||
if (!callback && typeof name === 'object') callback = this; | ||
if (obj) (listeningTo = {})[obj.cid] = obj; | ||
for (var id in listeningTo) { | ||
obj = listeningTo[id]; | ||
obj.off(name, callback, this); | ||
if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; | ||
} | ||
return this; | ||
}, | ||
/* | ||
@@ -204,3 +239,26 @@ * Trigger one or many events, firing all bound callbacks. Callbacks are | ||
}); | ||
// Inversion-of-control versions of `on` and `once`. Tell *this* object to | ||
// listen to an event in another object ... keeping track of what it's | ||
// listening to. | ||
var listenMethods = { | ||
listenTo: 'on', | ||
listenToOnce: 'once' | ||
}; | ||
_.each(listenMethods, function(implementation, method) { | ||
Class.prototype[method] = function(obj, name, callback) { | ||
var listeningTo = this._listeningTo || (this._listeningTo = {}); | ||
var id = obj.cid; | ||
listeningTo[id] = obj; | ||
if (!callback && typeof name === 'object') callback = this; | ||
obj[implementation](name, callback, this); | ||
return this; | ||
}; | ||
}); | ||
Class.prototype.bind = Class.prototype.on; | ||
Class.prototype.unbind = Class.prototype.off; | ||
return Class; | ||
}) |
@@ -104,2 +104,8 @@ define([ | ||
} | ||
// Remove reference | ||
for (var i = 0, length = this.models.length; i < length; i++) { | ||
this._removeReference(this.models[i], options); | ||
} | ||
options.previousModels = this.models; | ||
this.options.startIndex = 0; | ||
@@ -155,11 +161,5 @@ this.models = []; | ||
model.on('all', this._onModelEvent, this); | ||
model.on("id", function(newId, oldId) { | ||
var m = this.get(newId); | ||
if (m) this.remove(m); | ||
this.listenTo(model, 'all', this._onModelEvent); | ||
this.listenTo(model, 'id', this._onModelId); | ||
this._byId[newId] = this._byId[oldId]; | ||
delete this._byId[oldId]; | ||
}, this); | ||
index = options.at; | ||
@@ -177,2 +177,10 @@ this.models.splice(index, 0, model); | ||
/* | ||
* Internal method to sever a model's ties to a collection. | ||
*/ | ||
_removeReference: function(model, options) { | ||
if (this === model.collection) delete model.collection; | ||
this.stopListening(model); | ||
}, | ||
/* | ||
* Remove from model to the collection | ||
@@ -210,2 +218,4 @@ * @model : model to remove | ||
this.trigger('remove', model, this, options); | ||
this._removeReference(model); | ||
return this; | ||
@@ -215,2 +225,26 @@ }, | ||
/* | ||
* Pipe this colleciton into another one | ||
*/ | ||
pipe: function(to) { | ||
to.listenTo(this, "add", function(model) { | ||
this.add(model); | ||
}); | ||
to.listenTo(this, "remove", function(model) { | ||
this.remove(model); | ||
}); | ||
to.listenTo(this, "reset", function(colleciton, options) { | ||
_.each(options.previousModels, function(model) { | ||
this.remove(model); | ||
}, this); | ||
collection.each(function(model) { | ||
this.add(model); | ||
}, this); | ||
}); | ||
this.each(function(model) { | ||
to.add(model); | ||
}); | ||
}, | ||
/* | ||
* Add a model to the end of the collection. | ||
@@ -281,2 +315,13 @@ */ | ||
/* | ||
* Internal method called every time a model id change | ||
*/ | ||
_onModelId: function(newId, oldId) { | ||
var m = this.get(newId); | ||
if (m) this.remove(m); | ||
this._byId[newId] = this._byId[oldId]; | ||
delete this._byId[oldId]; | ||
}, | ||
/* | ||
* Get a model from the set by id. | ||
@@ -283,0 +328,0 @@ */ |
@@ -54,17 +54,17 @@ define([ | ||
} | ||
this.collection.on("reset", function() { | ||
this.listenTo(this.collection, "reset", function() { | ||
this.resetModels(); | ||
}, this); | ||
this.collection.on("sort", function() { | ||
}); | ||
this.listenTo(this.collection, "sort", function() { | ||
this.orderItems(); | ||
}, this); | ||
this.collection.on("add", function(elementmodel, collection, options) { | ||
}); | ||
this.listenTo(this.collection, "add", function(elementmodel, collection, options) { | ||
this.addModel(elementmodel, options); | ||
}, this); | ||
this.collection.on("remove", function(elementmodel) { | ||
}); | ||
this.listenTo(this.collection, "remove", function(elementmodel) { | ||
this.removeModel(elementmodel) | ||
}, this); | ||
this.collection.queue.on("tasks", function() { | ||
}); | ||
this.listenTo(this.collection.queue, "tasks", function() { | ||
this.update(); | ||
}, this); | ||
}); | ||
@@ -82,2 +82,12 @@ this.resetModels({ | ||
/* | ||
* Remove the view and all children | ||
*/ | ||
remove: function() { | ||
_.each(this.items, function(view) { | ||
view.remove(); | ||
}); | ||
return ListView.__super__.remove.apply(this, arguments); | ||
}, | ||
/* | ||
* Add a model to the list | ||
@@ -106,10 +116,11 @@ * @model : model to add | ||
}); | ||
model.on("set", function() { | ||
this.listenTo(model, "set", function() { | ||
item.update(); | ||
this.applyFilter(item); | ||
}, this); | ||
model.on("id", function(newId, oldId) { | ||
}); | ||
this.listenTo(model, "id", function() { | ||
this.items[newId] = this.items[oldId]; | ||
delete this.items[oldId]; | ||
}, this); | ||
}); | ||
item.update(); | ||
@@ -139,3 +150,3 @@ tag = this.Item.prototype.tagName; | ||
_.each(this.items, function(item) { | ||
item.$el.detach(); | ||
item.detach(); | ||
}, this); | ||
@@ -149,3 +160,3 @@ | ||
} | ||
item.$el.appendTo(this.$el); | ||
item.appendTo(this); | ||
}, this); | ||
@@ -166,2 +177,5 @@ return this; | ||
}); | ||
this.stopListening(model); | ||
if (this.items[model.id] == null) return this; | ||
@@ -168,0 +182,0 @@ |
@@ -152,2 +152,3 @@ define([ | ||
this.trigger("destroy", this, this.collection, options); | ||
this.off(); | ||
return this; | ||
@@ -154,0 +155,0 @@ }, |
@@ -52,2 +52,4 @@ define([ | ||
this.$el.remove(); | ||
this.stopListening(); | ||
this.off(); | ||
return this; | ||
@@ -57,2 +59,25 @@ }, | ||
/* | ||
* Detach the view from the dom (to be reinserted later) | ||
*/ | ||
detach: function() { | ||
// Signal detachment | ||
this.trigger("detach"); | ||
// Detach dom el | ||
this.$el.detach(); | ||
return this; | ||
}, | ||
/* | ||
* Append view | ||
*/ | ||
appendTo: function(el) { | ||
if (!(el instanceof $)) { | ||
el = el.$el; | ||
} | ||
this.$el.appendTo(el); | ||
return this; | ||
}, | ||
/* | ||
* jQuery delegate for the element of this view | ||
@@ -149,3 +174,3 @@ */ | ||
this.eachComponent(function(component) { | ||
component.$el.detach(); | ||
component.remove(); | ||
}, this); | ||
@@ -218,2 +243,5 @@ | ||
clearComponents: function() { | ||
this.eachComponent(function(view) { | ||
view.remove(); | ||
}); | ||
this.countComponents = 0; | ||
@@ -220,0 +248,0 @@ this.components = {}; |
898588
22781