Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- @author Simon Schmid (sled)
- @date 05/312011
- @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) {
- switch(ev) {
- case "add":
- case "remove":
- if(self.filter(arguments[1])) {
- // we are affected, forward events on this subset
- self.trigger.apply(self,arguments);
- }
- break;
- case "refresh":
- 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.get(arguments[1])) {
- // maybe trigger remove
- if(!self.filter(arguments[1])) {
- self.trigger('remove', arguments[1], self);
- }
- else
- {
- // still in the set, forward event to this subset
- self.trigger.apply(self, arguments);
- }
- }
- // we got a new element, yay!
- if(!self.get(arguments[0]) && self.filter(arguments[1])) {
- this.trigger('add', arguments[1], self);
- }
- }
- }
- // always refresh the models
- self._reset();
- });
- // 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;
- })[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)))
- };
- });
Add Comment
Please, Sign In to add comment