Created
January 10, 2012 11:51
-
-
Save plagi/1588629 to your computer and use it in GitHub Desktop.
Implements an imaginary subset of a Backbone Collection (as superset)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
@date 05/31/2011 | |
@class Backbone.Subset | |
@name Backbone Subset | |
@desc | |
Implements an imaginary subset of a Backbone Collection (as superset) | |
*/ | |
// Extend the default Backbone.Collection | |
_.extend(Backbone.Collection.prototype, { | |
build: function (attrs) { | |
var model = new this.model(attrs); | |
this.add(model); | |
return model; | |
}, | |
merge: function (collection) { | |
this.add(collection.models); | |
return this | |
} | |
}); | |
// Standard Constructor | |
Backbone.Subset = function(options) { | |
this.options = options || (options={}); | |
// use the comparator supplied by the options | |
if(options.comparator) { | |
this.comparator = options.comparator; | |
delete options.comparator; | |
} | |
if(!options.superset) { throw 'Subset must belong to a superset!'; } | |
if(!options.filter) { throw 'Subset must have a filter'; } | |
if(!(options.superset instanceof Backbone.Collection) && !(options.superset instanceof Backbone.Subset)) { | |
throw "Subset must have Backbone.Collection or Backbone.Subset as its superset!"; | |
} | |
var self = this; | |
// transform method, to be applied on models | |
this.transform = options.transform || function(echo) { return echo; }; | |
this.filter = options.filter; | |
this.superset = options.superset; | |
// hook on superset's events | |
this.superset.bind("all", function(ev) { | |
// TODO: CLEAN UP RESET!!! | |
switch(ev) { | |
case "add": | |
case "remove": | |
if(self.filter(arguments[1])) { | |
// we are affected, forward events on this subset | |
self._reset(); | |
self.trigger.apply(self, arguments); | |
} | |
break; | |
case "refresh": | |
self._reset(); | |
break; | |
default: | |
// model has changed, maybe it doesn't belong in this subset anymore | |
if(ev.indexOf("change:") === 0) { | |
// sub collection already has object so it could be removed | |
if(self.getByCid(arguments[1])) { | |
// maybe trigger remove | |
if(!self.filter(arguments[1])) { | |
self._reset(); | |
self.trigger('remove', arguments[1], self); | |
} | |
else | |
{ | |
// still in the set, forward event to this subset | |
self._reset(); | |
self.trigger.apply(self, arguments); | |
} | |
} | |
// we got a new element, yay! | |
if(!self.getByCid(arguments[1]) && self.filter(arguments[1])) { | |
self._reset(); | |
self.trigger('add', arguments[1], self); | |
} | |
} | |
} | |
}); | |
// remove crucial entries from options | |
delete options.filter | |
delete options.superset; | |
// get an event if a model changes | |
this._boundOnModelEvent = _.bind(this._onModelEvent, this); | |
// refresh the models | |
this._reset(); | |
// call custom constructor | |
this.initialize(options); | |
}; | |
_.extend(Backbone.Subset.prototype, Backbone.Collection.prototype, { | |
// array holding the models as json objects | |
toJSON: function() { | |
return this.map(function(c) { | |
return c.toJSON(); | |
}) | |
}, | |
// add models | |
add: function(models, options) { | |
var self = this; | |
models = _.filter(models, this.filter); | |
// return if no models resist | |
if(models.length == 0) { return; } | |
// actually add the models to the superset | |
this.superset.add(models, options); | |
return this; | |
}, | |
// remove models | |
remove: function(models, options) { | |
// remove model from superset | |
this.superset.remove(_.filter(_.filter(models, function(cm) { | |
return m != null; | |
}), this.filter), options); | |
}, | |
// get a certain model by id! | |
get: function(model_id) { | |
return _.select(this.models, function(cm) { | |
return cm.id == model_id; | |
})[0] | |
}, | |
// get a certain model by cid ! | |
getByCid: function(model_cid) { | |
return _.select(this.models, function(cm) { | |
return cm.cid == (model_cid.cid || model_cid); | |
})[0] | |
}, | |
// get a model at a certain position in the _subset_ | |
at: function(index) { | |
return this.models[index] | |
}, | |
// sorting | |
sort: function(options) { | |
this.superset.sort(options); | |
return this; | |
}, | |
// pluck an attribute from each model in the subset | |
pluck: function(attr) { | |
return _.map(this.models, function(model) { | |
return model.get(m) | |
}) | |
}, | |
// refresh the superset (triggers event to refresh this one too) | |
refresh: function(models, options) { | |
this.superset.refresh(models, options); | |
return this; | |
}, | |
fetch: function(options) { | |
this.superset.fetch(options); | |
return this; | |
}, | |
create: function(model, options) { | |
return this.superset.create(model, options); | |
}, | |
parse: function(resp) { | |
return resp; | |
}, | |
length: function() { | |
this._reset(); | |
return this.models.length; | |
}, | |
chain: function() { | |
return this.superset.chain(); | |
}, | |
// reset state and refresh the models | |
_reset: function() { | |
this.model = this.options.model || this.superset.model; | |
this.models = this._models(); | |
}, | |
// get the models which belong to this collection | |
_models: function() { | |
// using internal filter method to filter the models that belong to this subset | |
return _.filter(_.filter(this.transform(this.superset.models), function(cm) { | |
return cm != null; | |
}), this.filter); | |
} | |
}); | |
var subsetMethods = ["forEach", "each", "map", "reduce", "reduceRight", "find", "detect", "filter", "select", "reject", "every", "all", "some", "any", "include", "invoke", "max", "min", "sortBy", "sortedIndex", "toArray", "size", "first", "rest", "last", "without", "indexOf", "lastIndexOf", "isEmpty"]; | |
// add common function to this subset | |
_.each(subsetMethods, function(cMethod) { | |
Backbone.Subset.prototype[cMethod] = function() { | |
return _[cMethod].apply(_, [this._models()].concat(_.toArray(arguments))) | |
}; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// holds ALL upload models | |
this.collection = new ncs.collection.UploadCollection(); | |
// subset of archived models | |
this.archiveCollection = new Backbone.Subset({ | |
superset: this.collection, | |
filter: function(upload) { | |
return (upload.hasFailed() || upload.isComplete()); | |
} | |
}); | |
// subset of active models | |
this.activeCollection = new Backbone.Subset({ | |
superset: this.collection, | |
filter: function(upload) { | |
return (upload.isQueued() || upload.isUploading()); | |
} | |
}); | |
// subset of queued models | |
this.queuedCollection = new Backbone.Subset({ | |
debug: 'queued', | |
superset: this.collection, | |
filter: function(upload) { | |
return upload.isQueued(); | |
} | |
}); | |
// subset of active models | |
this.uploadingCollection = new Backbone.Subset({ | |
debug: 'uploading', | |
superset: this.collection, | |
filter: function(upload) { | |
return upload.isUploading(); | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment