234 lines
6.7 KiB
JavaScript
234 lines
6.7 KiB
JavaScript
|
/*! backbone.collectionsubset - v0.1.2 - 2012-12-20
|
||
|
* https://github.com/anthonyshort/backbone.collectionsubset
|
||
|
* Copyright (c) 2012 Anthony Short; Licensed MIT */
|
||
|
// Patched for civicrm by colemanw - added global import of _ variable
|
||
|
(function(_) {
|
||
|
|
||
|
Backbone.CollectionSubset = (function() {
|
||
|
|
||
|
CollectionSubset.extend = Backbone.Model.extend;
|
||
|
|
||
|
_.extend(CollectionSubset.prototype, Backbone.Events);
|
||
|
|
||
|
function CollectionSubset(options) {
|
||
|
if (options == null) {
|
||
|
options = {};
|
||
|
}
|
||
|
options = _.defaults(options, {
|
||
|
refresh: true,
|
||
|
triggers: null,
|
||
|
filter: function() {
|
||
|
return true;
|
||
|
},
|
||
|
name: null,
|
||
|
child: null,
|
||
|
parent: null
|
||
|
});
|
||
|
this.triggers = options.triggers ? options.triggers.split(' ') : [];
|
||
|
if (!options.child) {
|
||
|
options.child = new options.parent.constructor;
|
||
|
}
|
||
|
this.setParent(options.parent);
|
||
|
this.setChild(options.child);
|
||
|
this.setFilter(options.filter);
|
||
|
if (options.model) {
|
||
|
this.child.model = options.model;
|
||
|
}
|
||
|
if (options.refresh) {
|
||
|
this.refresh();
|
||
|
}
|
||
|
this.name = options.name;
|
||
|
}
|
||
|
|
||
|
CollectionSubset.prototype.setParent = function(collection) {
|
||
|
var _ref,
|
||
|
_this = this;
|
||
|
if ((_ref = this.parent) != null) {
|
||
|
_ref.off(null, null, this);
|
||
|
}
|
||
|
this.parent = collection;
|
||
|
this.parent.on('add', this._onParentAdd, this);
|
||
|
this.parent.on('remove', this._onParentRemove, this);
|
||
|
this.parent.on('reset', this._onParentReset, this);
|
||
|
this.parent.on('change', this._onParentChange, this);
|
||
|
this.parent.on('dispose', this.dispose, this);
|
||
|
this.parent.on('loading', (function() {
|
||
|
return _this.child.trigger('loading');
|
||
|
}), this);
|
||
|
return this.parent.on('ready', (function() {
|
||
|
return _this.child.trigger('ready');
|
||
|
}), this);
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype.setChild = function(collection) {
|
||
|
var _ref;
|
||
|
if ((_ref = this.child) != null) {
|
||
|
_ref.off(null, null, this);
|
||
|
}
|
||
|
this.child = collection;
|
||
|
this.child.on('add', this._onChildAdd, this);
|
||
|
this.child.on('reset', this._onChildReset, this);
|
||
|
this.child.on('dispose', this.dispose, this);
|
||
|
this.child.superset = this.parent;
|
||
|
this.child.filterer = this;
|
||
|
this.child.url = this.parent.url;
|
||
|
return this.child.model = this.parent.model;
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype.setFilter = function(fn) {
|
||
|
var filter;
|
||
|
filter = function(model) {
|
||
|
var matchesFilter, matchesParentFilter;
|
||
|
matchesFilter = fn.call(this, model);
|
||
|
matchesParentFilter = this.parent.filterer ? this.parent.filterer.filter(model) : true;
|
||
|
return matchesFilter && matchesParentFilter;
|
||
|
};
|
||
|
return this.filter = _.bind(filter, this);
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype.refresh = function(options) {
|
||
|
var models;
|
||
|
if (options == null) {
|
||
|
options = {};
|
||
|
}
|
||
|
models = this.parent.filter(this.filter);
|
||
|
this.child.reset(models, {
|
||
|
subset: this
|
||
|
});
|
||
|
return this.child.trigger('refresh');
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._replaceChildModel = function(parentModel) {
|
||
|
var childModel, index;
|
||
|
childModel = this._getByCid(this.child, parentModel.cid);
|
||
|
if (childModel === parentModel) {
|
||
|
return;
|
||
|
}
|
||
|
if (_.isUndefined(childModel)) {
|
||
|
return this.child.add(parentModel, {
|
||
|
subset: this
|
||
|
});
|
||
|
} else {
|
||
|
index = this.child.indexOf(childModel);
|
||
|
this.child.remove(childModel);
|
||
|
return this.child.add(parentModel, {
|
||
|
at: index,
|
||
|
subset: this
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._onParentAdd = function(model, collection, options) {
|
||
|
if (options && options.subset === this) {
|
||
|
return;
|
||
|
}
|
||
|
if (this.filter(model)) {
|
||
|
return this._replaceChildModel(model);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._onParentRemove = function(model, collection, options) {
|
||
|
return this.child.remove(model, options);
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._onParentReset = function(collection, options) {
|
||
|
return this.refresh();
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._onParentChange = function(model, changes) {
|
||
|
if (!this.triggerMatched(model)) {
|
||
|
return;
|
||
|
}
|
||
|
if (this.filter(model)) {
|
||
|
return this.child.add(model);
|
||
|
} else {
|
||
|
return this.child.remove(model);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._onChildAdd = function(model, collection, options) {
|
||
|
var parentModel;
|
||
|
if (options && options.subset === this) {
|
||
|
return;
|
||
|
}
|
||
|
this.parent.add(model);
|
||
|
parentModel = this._getByCid(this.parent, model.cid);
|
||
|
if (!parentModel) {
|
||
|
return;
|
||
|
}
|
||
|
if (this.filter(parentModel)) {
|
||
|
return this._replaceChildModel(parentModel);
|
||
|
} else {
|
||
|
return this.child.remove(model);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._onChildReset = function(collection, options) {
|
||
|
if (options && options.subset === this) {
|
||
|
return;
|
||
|
}
|
||
|
this.parent.add(this.child.models);
|
||
|
return this.refresh();
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype._getByCid = function(model, cid) {
|
||
|
var fn;
|
||
|
fn = model.getByCid || model.get;
|
||
|
return fn.apply(model, [cid]);
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype.triggerMatched = function(model) {
|
||
|
var changedAttrs;
|
||
|
if (this.triggers.length === 0) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!model.hasChanged()) {
|
||
|
return false;
|
||
|
}
|
||
|
changedAttrs = _.keys(model.changedAttributes());
|
||
|
return _.intersection(this.triggers, changedAttrs).length > 0;
|
||
|
};
|
||
|
|
||
|
CollectionSubset.prototype.dispose = function() {
|
||
|
var prop, _base, _i, _len, _ref;
|
||
|
if (this.disposed) {
|
||
|
return;
|
||
|
}
|
||
|
this.trigger('dispose', this);
|
||
|
this.parent.off(null, null, this);
|
||
|
this.child.off(null, null, this);
|
||
|
if (typeof (_base = this.child).dispose === "function") {
|
||
|
_base.dispose();
|
||
|
}
|
||
|
this.off();
|
||
|
_ref = ['parent', 'child', 'options'];
|
||
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||
|
prop = _ref[_i];
|
||
|
delete this[prop];
|
||
|
}
|
||
|
return this.disposed = true;
|
||
|
};
|
||
|
|
||
|
return CollectionSubset;
|
||
|
|
||
|
})();
|
||
|
|
||
|
Backbone.Collection.prototype.subcollection = function(options) {
|
||
|
var subset;
|
||
|
if (options == null) {
|
||
|
options = {};
|
||
|
}
|
||
|
_.defaults(options, {
|
||
|
child: new this.constructor,
|
||
|
parent: this
|
||
|
});
|
||
|
subset = new Backbone.CollectionSubset(options);
|
||
|
return subset.child;
|
||
|
};
|
||
|
|
||
|
if (typeof module !== "undefined" && module !== null) {
|
||
|
module.exports = Backbone.CollectionSubset;
|
||
|
}
|
||
|
|
||
|
}(_));
|