// Generated by CoffeeScript 1.6.3 /*! Backbone.CoComp v0.0.7 (c) 2013 David Biehl Backbone.CoComp may be freely distributed under the MIT license. For all details and documentation: https://github.com/davidbiehl/backbone.cocomp */ (function() { var __slice = [].slice; Backbone.CoComp = (function() { _.extend(CoComp.prototype, Backbone.Events); function CoComp(opts) { var attr; if (opts == null) { opts = {}; } this._collections = {}; if (_.isFunction(opts.comparator)) { this.comparator = opts.comparator; } else { if (opts.comparator === "===") { this.comparator = function(obj) { return obj[0] === obj[1]; }; } else { attr = opts.comparator || "id"; this.comparator = function(obj) { return obj[0].get(attr) === obj[1].get(attr); }; } } } CoComp.prototype.set = function(name, collection, options) { var old; if (options == null) { options = {}; } if (name === 0 || name === 1) { throw "" + name + " is a reserved collection name, please use a different name"; } old = this.get(name); if (old) { this.stopListening(old); } this._collections[name] = collection; this.listenTo(collection, 'add remove', this._onChange); this.listenTo(collection, 'reset', function() { return this.compare(name); }); if (!options.silent) { return this.compare(name); } }; CoComp.prototype.get = function(name) { return this._collections[name]; }; CoComp.prototype.unset = function(name, options) { if (options == null) { options = {}; } if (!this.get(name)) { return; } if (!options.silent) { this.compare(name, { reverse: true }); } return delete this._collections[name]; }; CoComp.prototype.compare = function() { var a, aName, b, bName, comparable, compared, names, options, _i, _ref, _results; names = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), options = arguments[_i++]; if (options == null) { options = {}; } if (!_.isObject(options)) { names.push(options); options = {}; } compared = []; comparable = function(aName, bName) { return aName !== bName && (names.length === 0 || _.contains(names, aName) || _.contains(names, bName)) && !(_.findWhere(compared, { aName: bName, bName: aName })); }; _ref = this._collections; _results = []; for (aName in _ref) { a = _ref[aName]; _results.push((function() { var _ref1, _results1; _ref1 = this._collections; _results1 = []; for (bName in _ref1) { b = _ref1[bName]; if (comparable(aName, bName)) { compared.push({ aName: aName, bName: bName }); _results1.push(this._compareCollections(a, b, { aName: aName, bName: bName, reverse: options.reverse })); } else { _results1.push(void 0); } } return _results1; }).call(this)); } return _results; }; CoComp.prototype._compareCollections = function(a, b, options) { var aName, bName, event, _this = this; if (options == null) { options = {}; } aName = options.aName || this._collectionName(a); bName = options.bName || this._collectionName(b); if (!_.has(options, 'invert')) { options.invert = true; } event = "in"; if (options.reverse) { event = "out"; } if (aName !== bName) { a.forEach(function(aModel) { return _this._compareModelToCollection(aModel, b, { modelCollectionName: aName, collectionName: bName, event: event }); }); if (options.invert) { return this._compareCollections(b, a, { aName: bName, bName: aName, invert: false }); } } }; CoComp.prototype._compareModelToCollection = function(aModel, b, options) { var aName, bName, event, inCollection, _this = this; if (options == null) { options = {}; } aName = options.modelCollectionName || (function() { throw "modelCollectionName is required"; })(); bName = options.collectionName || this._collectionName(b); event = options.event || "in"; if (aName !== bName) { inCollection = false; b.forEach(function(bModel) { var aExists, bExists; aExists = _this._compareOne(aModel, bModel, event, { aName: aName, bName: bName }); if (options.invert) { bExists = _this._compareOne(bModel, aModel, event, { aName: bName, bName: aName }); } return inCollection = inCollection || aExists || bExists; }); if (!inCollection && event !== "out") { return this._trigger(aModel, "out", bName); } } }; CoComp.prototype._trigger = function(model, event, name) { if (!_.contains(["in", "out"], event)) { throw "Invalid event: " + event; } model.trigger("cocomp:" + event + ":" + name); return model.trigger("cocomp:" + event); }; CoComp.prototype._compareOne = function(a, b, event, options) { var aName, bName, obj; if (options == null) { options = {}; } aName = options.aName || (function() { throw "aName is required"; })(); bName = options.bName || (function() { throw "bName is required"; })(); obj = {}; obj[aName] = obj[0] = a; obj[bName] = obj[1] = b; if (this.comparator.call(this.comparator, obj)) { this._trigger(b, event, aName); return true; } else { return false; } }; CoComp.prototype._collectionName = function(collection) { var c, cName, _ref; _ref = this._collections; for (cName in _ref) { c = _ref[cName]; if (c === collection) { return cName; } } }; CoComp.prototype._onChange = function(model, collection, e) { var aName, b, bName, event, _ref, _results; event = "in"; if (!e.add) { event = "out"; } aName = this._collectionName(collection); this._trigger(model, event, aName); _ref = this._collections; _results = []; for (bName in _ref) { b = _ref[bName]; _results.push(this._compareModelToCollection(model, b, { modelCollectionName: aName, collectionName: bName, invert: true, event: event })); } return _results; }; return CoComp; })(); }).call(this);