--- /dev/null
+// Backbone.BabySitter
+// -------------------
+// v0.1.4
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/marionettejs/backbone.babysitter
+
+(function(root, factory) {
+
+ if (typeof define === 'function' && define.amd) {
+ define(['backbone', 'underscore'], function(Backbone, _) {
+ return factory(Backbone, _);
+ });
+ } else if (typeof exports !== 'undefined') {
+ var Backbone = require('backbone');
+ var _ = require('underscore');
+ module.exports = factory(Backbone, _);
+ } else {
+ factory(root.Backbone, root._);
+ }
+
+}(this, function(Backbone, _) {
+ 'use strict';
+
+ var previousChildViewContainer = Backbone.ChildViewContainer;
+
+ // BabySitter.ChildViewContainer
+ // -----------------------------
+ //
+ // Provide a container to store, retrieve and
+ // shut down child views.
+
+ Backbone.ChildViewContainer = (function (Backbone, _) {
+
+ // Container Constructor
+ // ---------------------
+
+ var Container = function(views){
+ this._views = {};
+ this._indexByModel = {};
+ this._indexByCustom = {};
+ this._updateLength();
+
+ _.each(views, this.add, this);
+ };
+
+ // Container Methods
+ // -----------------
+
+ _.extend(Container.prototype, {
+
+ // Add a view to this container. Stores the view
+ // by `cid` and makes it searchable by the model
+ // cid (and model itself). 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 by custom
+ if (customIndex){
+ this._indexByCustom[customIndex] = viewCid;
+ }
+
+ this._updateLength();
+ return this;
+ },
+
+ // Find a view by the model that was attached to
+ // it. Uses the model's `cid` to find it.
+ findByModel: function(model){
+ return this.findByModelCid(model.cid);
+ },
+
+ // Find a view by the `cid` of the model that was attached to
+ // it. Uses the model's `cid` to find the view `cid` and
+ // retrieve the view using it.
+ findByModelCid: function(modelCid){
+ var viewCid = this._indexByModel[modelCid];
+ 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 its `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 custom index
+ _.any(this._indexByCustom, function(cid, key) {
+ if (cid === viewCid) {
+ delete this._indexByCustom[key];
+ return true;
+ }
+ }, this);
+
+ // remove the view from the container
+ delete this._views[viewCid];
+
+ // update the length
+ this._updateLength();
+ return this;
+ },
+
+ // 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){
+ this.apply(method, _.tail(arguments));
+ },
+
+ // 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){
+ _.each(this._views, function(view){
+ 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, _);
+
+
+ Backbone.ChildViewContainer.VERSION = '0.1.4';
+
+ Backbone.ChildViewContainer.noConflict = function () {
+ Backbone.ChildViewContainer = previousChildViewContainer;
+ return this;
+ };
+
+ return Backbone.ChildViewContainer;
+
+}));