Code coverage report for src/marionette.view.js

Statements: 98.41% (62 / 63)      Branches: 85.71% (24 / 28)      Functions: 100% (15 / 15)      Lines: 100% (56 / 56)     

All files » src/ » marionette.view.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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178        1     479   479 479   478 478                       166                 166 166 166 3   166           481   9     9       9     16     16 16     16             16         9           481 481 480         481 481   481 481 481   481           485 485   485 485                     127       122 122 3           119 119     119     119           164       18 15       18     18     18 40 40           119     2 2       2 2      
// Marionette.View
// ---------------
 
// The core view type that other Marionette views extend from.
Marionette.View = Backbone.View.extend({
 
  constructor: function(){
    _.bindAll(this, "render");
 
    var args = Array.prototype.slice.apply(arguments);
    Backbone.View.prototype.constructor.apply(this, args);
 
    Marionette.MonitorDOMRefresh(this);
    this.listenTo(this, "show", this.onShowCalled, this);
  },
 
  // import the "triggerMethod" to trigger events with corresponding
  // methods if the method exists 
  triggerMethod: Marionette.triggerMethod,
 
  // Get the template for this view
  // instance. You can set a `template` attribute in the view
  // definition or pass a `template: "whatever"` parameter in
  // to the constructor options.
  getTemplate: function(){
    return Marionette.getOption(this, "template");
  },
 
  // Mix in template helper methods. Looks for a
  // `templateHelpers` attribute, which can either be an
  // object literal, or a function that returns an object
  // literal. All methods and attributes from this object
  // are copies to the object passed in.
  mixinTemplateHelpers: function(target){
    target = target || {};
    var templateHelpers = this.templateHelpers;
    if (_.isFunction(templateHelpers)){
      templateHelpers = templateHelpers.call(this);
    }
    return _.extend(target, templateHelpers);
  },
 
  // Configure `triggers` to forward DOM events to view
  // events. `triggers: {"click .foo": "do:foo"}`
  configureTriggers: function(){
    if (!this.triggers) { return; }
 
    var triggerEvents = {};
 
    // Allow `triggers` to be configured as a function
    var triggers = _.result(this, "triggers");
 
    // Configure the triggers, prevent default
    // action and stop propagation of DOM events
    _.each(triggers, function(value, key){
 
      // build the event handler function for the DOM event
      triggerEvents[key] = function(e){
 
        // stop the event in its tracks
        Eif (e && e.preventDefault){ e.preventDefault(); }
        Eif (e && e.stopPropagation){ e.stopPropagation(); }
 
        // build the args for the event
        var args = {
          view: this,
          model: this.model,
          collection: this.collection
        };
 
        // trigger the event
        this.triggerMethod(value, args);
      };
 
    }, this);
 
    return triggerEvents;
  },
 
  // Overriding Backbone.View's delegateEvents to handle 
  // the `triggers`, `modelEvents`, and `collectionEvents` configuration
  delegateEvents: function(events){
    this._delegateDOMEvents(events);
    Marionette.bindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
    Marionette.bindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
  },
 
  // internal method to delegate DOM events and triggers
  _delegateDOMEvents: function(events){
    events = events || this.events;
    Iif (_.isFunction(events)){ events = events.call(this); }
 
    var combinedEvents = {};
    var triggers = this.configureTriggers();
    _.extend(combinedEvents, events, triggers);
 
    Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
  },
 
  // Overriding Backbone.View's undelegateEvents to handle unbinding
  // the `triggers`, `modelEvents`, and `collectionEvents` config
  undelegateEvents: function(){
    var args = Array.prototype.slice.call(arguments);
    Backbone.View.prototype.undelegateEvents.apply(this, args);
 
    Marionette.unbindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
    Marionette.unbindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
  },
 
  // Internal method, handles the `show` event.
  onShowCalled: function(){},
 
  // Default `close` implementation, for removing a view from the
  // DOM and unbinding it. Regions will call this method
  // for you. You can specify an `onClose` method in your view to
  // add custom code that is called after the view is closed.
  close: function(){
    if (this.isClosed) { return; }
 
    // allow the close to be stopped by returning `false`
    // from the `onBeforeClose` method
    var shouldClose = this.triggerMethod("before:close");
    if (shouldClose === false){
      return;
    }
 
    // mark as closed before doing the actual close, to
    // prevent infinite loops within "close" event handlers
    // that are trying to close other views
    this.isClosed = true;
    this.triggerMethod("close");
 
    // unbind UI elements
    this.unbindUIElements();
 
    // remove the view from the DOM
    this.remove();
  },
 
  // This method binds the elements specified in the "ui" hash inside the view's code with
  // the associated jQuery selectors.
  bindUIElements: function(){
    if (!this.ui) { return; }
 
    // store the ui hash in _uiBindings so they can be reset later
    // and so re-rendering the view will be able to find the bindings
    if (!this._uiBindings){
      this._uiBindings = this.ui;
    }
 
    // get the bindings result, as a function or otherwise
    var bindings = _.result(this, "_uiBindings");
 
    // empty the ui so we don't have anything to start with
    this.ui = {};
 
    // bind each of the selectors
    _.each(_.keys(bindings), function(key) {
      var selector = bindings[key];
      this.ui[key] = this.$(selector);
    }, this);
  },
 
  // This method unbinds the elements specified in the "ui" hash
  unbindUIElements: function(){
    if (!this.ui){ return; }
 
    // delete all of the existing ui bindings
    _.each(this.ui, function($el, name){
      delete this.ui[name];
    }, this);
 
    // reset the ui element to the original bindings configuration
    this.ui = this._uiBindings;
    delete this._uiBindings;
  }
});