// Backbone.BabySitter, v0.0.3.1 // Primary Copyright (c)2012 Derick Bailey, Muted Solutions, LLC. // Distributed under MIT license // http://github.com/marionettejs/backbone.babysitter // Custom version by Jeremy McLeod, Isochronous.org // http://github.com/isochronous/backbone.babysitter (function (root, factory) { if (typeof exports === 'object') { var underscore = require('underscore'); var backbone = require('backbone'); module.exports = factory(underscore, backbone); } else if (typeof define === 'function' && define.amd) { define(['underscore', 'backbone'], factory); } }(this, function (_, Backbone) { "option strict"; // Backbone.ChildViewContainer // --------------------------- // // Provide a container to store, retrieve and // shut down child views. Backbone.ChildViewContainer = (function(Backbone, _) { // Container Constructor // --------------------- var Container = function(options) { this.options = options || (options = {}); this._views = {}; this._indexByModel = {}; this._indexByCollection = {}; this._indexByCustom = {}; this._updateLength(); var init = options.initialize || this.initialize || null; if (_.isFunction(init)) { init.apply(this, arguments); } }; Container.extend = Backbone.Model.extend; // Container Methods // ----------------- _.extend(Container.prototype, Backbone.Events, { // Add a view to this container. Stores the view // by `cid` and makes it searchable by the model // and/or collection of the view. Optionally specify // a custom key to store an retrieve the view. add: function(view, customIndex) { var viewCid = view.cid; // store the view this._views[viewCid] = view; // index it by model if (view.model) { this._indexByModel[view.model.cid] = viewCid; } // index it by collection if (view.collection) { this._indexByCollection[view.collection.cid] = viewCid; } // index by custom if (customIndex) { this._indexByCustom[customIndex] = viewCid; } this._updateLength(); }, // Find a view by the model that was attached to // it. Uses the model's `cid` to find it, and // retrieves the view by it's `cid` from the result findByModel: function(model) { var viewCid = this._indexByModel[model.cid]; return this.findByCid(viewCid); }, // Find a view by the collection that was attached to // it. Uses the collection's `cid` to find it, and // retrieves the view by it's `cid` from the result findByCollection: function(col) { var viewCid = this._indexByCollection[col.cid]; return this.findByCid(viewCid); }, // Find a view by a custom indexer. findByCustom: function(index) { var viewCid = this._indexByCustom[index]; return this.findByCid(viewCid); }, // Find by index. This is not guaranteed to be a // stable index. findByIndex: function(index) { return _.values(this._views)[index]; }, // retrieve a view by it's `cid` directly findByCid: function(cid) { return this._views[cid]; }, // Remove a view remove: function(view) { var viewCid = view.cid; // delete model index if (view.model) { delete this._indexByModel[view.model.cid]; } // delete collection index if (view.collection) { delete this._indexByCollection[view.collection.cid]; } // delete custom index var cust; for (var key in this._indexByCustom) { if (this._indexByCustom.hasOwnProperty(key)) { if (this._indexByCustom[key] === viewCid) { cust = key; break; } } } if (cust) { delete this._indexByCustom[cust]; } // remove the view from the container delete this._views[viewCid]; // update the length this._updateLength(); }, // Call a method on every view in the container, // passing parameters to the call method one at a // time, like `function.call`. call: function(method, args) { args = Array.prototype.slice.call(arguments, 1); this.apply(method, args); }, // Apply a method on every view in the container, // passing parameters to the call method one at a // time, like `function.apply`. apply: function(method, args) { var view; _.each(this._views, function(view, key) { if (_.isFunction(view[method])) { view[method].apply(view, args); } }); }, // Update the `.length` attribute on this container _updateLength: function() { this.length = _.size(this._views); } }); // Borrowing this code from Backbone.Collection: // http://backbonejs.org/docs/backbone.html#section-106 // // Mix in methods from Underscore, for iteration, and other // collection related features. var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', 'last', 'without', 'isEmpty', 'pluck']; _.each(methods, function(method) { Container.prototype[method] = function() { var views = _.values(this._views); var args = [views].concat(_.toArray(arguments)); return _[method].apply(_, args); }; }); // return the public API return Container; })(Backbone, _); return Backbone.ChildViewContainer; }));