Code coverage report for src/childviewcontainer.js

Statements: 100% (43 / 43)      Branches: 75% (9 / 12)      Functions: 100% (16 / 16)      Lines: 100% (43 / 43)     

All files » src/ » childviewcontainer.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149            1         1 17 17 17 17   17           1             24     24     24 5       24 7     24           2             2 2         2 2           3         8         4     4 4       4 4 4 4         4     4             3             5 10 9             45                 1         1 23 2 2 2         1    
// Backbone.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();
    },
 
    // 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 it's `cid` directly
    findByCid: function(cid){
      return this._views[cid];
    },
 
    // Remove a view
    remove: function(view){
      var viewCid = view.cid;
 
      // delete model index
      Eif (view.model){
        delete this._indexByModel[view.model.cid];
      }
 
      // delete custom index
      _.any(this._indexByCustom, function(cid, key) {
        Eif (cid === viewCid) {
          delete this._indexByCustom[key];
          return true;
        }
      }, this);
 
      // 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){
      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, _);