Permalink
Browse files

Huge refactor on proxy reset events. Only bubble to collections that …

…will receive any add or remove
  • Loading branch information...
1 parent 56a4d7e commit c52869a62869de1c62d1453223f012282754e16b @masylum committed Mar 30, 2012
Showing with 283 additions and 438 deletions.
  1. +88 −59 backbone.subset.js
  2. +195 −379 test/test.js
View
@@ -14,6 +14,17 @@
}
/**
+ * Returns the xor of two sets
+ *
+ * @param {Array} a
+ * @param {Array} b
+ * @return {Array}
+ */
+ function xor(a, b) {
+ return _.difference(_.union(a, b), _.intersection(a, b));
+ }
+
+ /**
* Subset constructor
*
* @param {String|Object} type
@@ -25,25 +36,25 @@
this.model = this.parent().model;
this.comparator = this.comparator || options.comparator || this.parent().comparator;
- this.liveupdate_keys = this.liveupdate_keys || options.liveupdate_keys || 'none';
+ this.liveupdate_keys = this.liveupdate_keys || options.liveupdate_keys;
- _.bindAll(this, '_onModelEvent', '_unbindModelEvents', '_proxyEvents');
+ _.bindAll(this, '_onModelEvent', '_unbindModelEvents', '_proxyAdd'
+ , '_proxyReset', '_proxyRemove', '_proxyChange');
- this.parent().bind('all', this._proxyEvents);
+ this.parent().bind('add', this._proxyAdd);
+ this.parent().bind('remove', this._proxyRemove);
+ this.parent().bind('reset', this._proxyReset);
+ this.parent().bind('all', this._proxyChange);
if (this.beforeInitialize) {
this.beforeInitialize.apply(this, arguments);
}
if (!options.no_reset) {
this._reset();
-
- if (models) {
- this.reset(models, {silent: true});
- }
- }
- else {
- this._resetSubset(this.parent().models, {silent: true});
+ this.reset(models || this.parent().models, {silent: true});
+ } else {
+ this._resetSubset({silent: true});
}
this.initialize.apply(this, arguments);
@@ -58,22 +69,28 @@
*/
Subset.reset = function (models, options) {
var parent_models = _.clone(this.parent().models)
- , ids = _(parent_models).pluck('id');
+ , xored_ids
+ , ids = this.pluck('id');
models = models || [];
models = _.isArray(models) ? models : [models];
options = options || {};
+ // delete parent reseted models
+ parent_models = _.reject(parent_models, function (model) {
+ return _.include(ids, model.id);
+ });
+
// insert parent reseted models
_.each(models, function (model) {
- if (ids.indexOf(model.id) === -1) {
- parent_models.push(model);
- }
- }, this);
+ parent_models.push(model);
+ });
- this.parent().reset(parent_models, _.extend(options, {subset_reset: true}));
+ // xored ids are the ones added/removed
+ xored_ids = xor(ids, _.pluck(models, 'id'));
- this._resetSubset(models, options);
+ this.parent().reset(parent_models, _.extend(options, {silent: true}));
+ this.parent().trigger('reset', this, {model_ids: xored_ids});
return this;
};
@@ -85,14 +102,12 @@
* @param {Object} options
* @return {Object} collection
*/
- Subset._resetSubset = function (models, options) {
- models = models || [];
- models = _.isArray(models) ? models : [models];
+ Subset._resetSubset = function (options) {
options = options || {};
this.each(this._unbindModelEvents);
this._reset();
- _(models).each(function (model) {
+ this.parent().each(function (model) {
this._addToSubset(model, {silent: true});
}, this);
@@ -122,22 +137,6 @@
* @return {Object} model
*/
Subset._addToSubset = function (model, options) {
- var parents_model;
-
- if (model.id && (parents_model = this.parent().get(model.id))) {
- if (!(model instanceof Backbone.Model)) {
- parents_model.set(model, {silent: true});
- model = parents_model;
- }
- else {
- parents_model.set(model.attributes, {silent: true});
- model = parents_model;
- }
- }
- else {
- model = Backbone.Collection.prototype._prepareModel.call(this, model, options);
- }
-
if (this.sieve(model)) {
return Backbone.Collection.prototype._add.call(this, model, options);
}
@@ -163,7 +162,7 @@
*/
Subset._removeFromSubset = function (model, options) {
return Backbone.Collection.prototype._remove.call(this, model, options);
- };
+ }
/**
* Prepare a model to be added to a collection
@@ -188,40 +187,70 @@
};
/**
- * Proxies an event happening into the parent collection to the Subset
+ * Proxies an `add` event happening into the parent collection to the Subset
*
* @param {Object} model
+ * @param {Object} collection
* @param {Object} options
- * @return {Object} model
*/
- Subset._proxyEvents = function (ev, model, collection, options) {
- if (collection !== this) {
- if (ev === 'change' && this.liveupdate_keys === 'all') {
- this._updateModelMembership(model);
- } else if (ev.slice(0, 7) === 'change:' && _.isArray(this.liveupdate_keys)
- && _.include(this.liveupdate_keys, ev.slice(7))) {
- this._updateModelMembership(model);
- }
+ Subset._proxyAdd = function (model, collection, options) {
+ options = options || {};
- if (ev === 'add' && this.sieve(model) && !options.noproxy) {
- this._addToSubset(model, options);
- }
+ if (collection !== this && this.sieve(model) && !options.noproxy) {
+ this._addToSubset(model, options);
+ }
+ };
- if (ev === 'remove' && this.sieve(model) && !options.noproxy) {
- this._removeFromSubset(model, options);
- }
+ /**
+ * Proxies a `remove` event happening into the parent collection to the Subset
+ *
+ * @param {Object} model
+ * @param {Object} collection
+ * @param {Object} options
+ */
+ Subset._proxyRemove = function (model, collection, options) {
+ options = options || {};
+
+ if (collection !== this && this.sieve(model) && !options.noproxy) {
+ this._removeFromSubset(model, options);
}
+ };
- // model == collection
- if (ev === 'reset' && model !== this) {
- if (!collection.subset_reset) {
- this._resetSubset(model.models, collection);
+ /**
+ * Proxies a `change` event happening into the parent collection to the Subset
+ *
+ * @param {Object} ev
+ * @param {Object} model
+ * @param {Object} collection
+ */
+ Subset._proxyChange = function (ev, model, collection) {
+ if (collection !== this && ev === 'change' && this.liveupdate_keys === 'all') {
+ this._updateModelMembership(model);
+ } else if (ev.slice(0, 7) === 'change:' && _.isArray(this.liveupdate_keys)
+ && _.include(this.liveupdate_keys, ev.slice(7))) {
+ this._updateModelMembership(model);
+ }
+ };
+
+ /**
+ * Proxies a `reset` event happening into the parent collection to the Subset
+ *
+ * @param {Object} collection
+ * @param {Object} options
+ */
+ Subset._proxyReset = function (collection, options) {
+ options = options || {};
+
+ if (collection !== this && !options || (options && !options.noproxy)) {
+ if (!options.model_ids || _.intersection(this.pluck('id'), options.model_ids).length) {
+ this._resetSubset(_.extend(_.clone(options), {proxied: true}));
}
}
};
/**
* Determines whether a model should be in the subset, and adds or removes it
+ *
* @param {Object} model
*/
Subset._updateModelMembership = function (model) {
@@ -250,4 +279,4 @@
_.extend(Backbone.Subset.prototype, Backbone.Collection.prototype, Subset);
Backbone.Subset.extend = Backbone.Collection.extend;
-}).call(this);
+}());
Oops, something went wrong.

0 comments on commit c52869a

Please sign in to comment.