PageRenderTime 52ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/bower_components/backbone.marionette/src/marionette.view.js

https://github.com/robertd/benm
JavaScript | 216 lines | 113 code | 45 blank | 58 comment | 18 complexity | 763ba6966893bfae81aeba9ce8ac5995 MD5 | raw file
  1. // Marionette.View
  2. // ---------------
  3. // The core view type that other Marionette views extend from.
  4. Marionette.View = Backbone.View.extend({
  5. constructor: function(options){
  6. _.bindAll(this, "render");
  7. var args = Array.prototype.slice.apply(arguments);
  8. // this exposes view options to the view initializer
  9. // this is a backfill since backbone removed the assignment
  10. // of this.options
  11. // at some point however this may be removed
  12. this.options = _.extend({}, this.options, options);
  13. // parses out the @ui DSL for events
  14. this.events = this.normalizeUIKeys(_.result(this, 'events'));
  15. Backbone.View.prototype.constructor.apply(this, args);
  16. Marionette.MonitorDOMRefresh(this);
  17. this.listenTo(this, "show", this.onShowCalled, this);
  18. },
  19. // import the "triggerMethod" to trigger events with corresponding
  20. // methods if the method exists
  21. triggerMethod: Marionette.triggerMethod,
  22. // Get the template for this view
  23. // instance. You can set a `template` attribute in the view
  24. // definition or pass a `template: "whatever"` parameter in
  25. // to the constructor options.
  26. getTemplate: function(){
  27. return Marionette.getOption(this, "template");
  28. },
  29. // Mix in template helper methods. Looks for a
  30. // `templateHelpers` attribute, which can either be an
  31. // object literal, or a function that returns an object
  32. // literal. All methods and attributes from this object
  33. // are copies to the object passed in.
  34. mixinTemplateHelpers: function(target){
  35. target = target || {};
  36. var templateHelpers = Marionette.getOption(this, "templateHelpers");
  37. if (_.isFunction(templateHelpers)){
  38. templateHelpers = templateHelpers.call(this);
  39. }
  40. return _.extend(target, templateHelpers);
  41. },
  42. // allows for the use of the @ui. syntax within
  43. // a given key for triggers and events
  44. // swaps the @ui with the associated selector
  45. normalizeUIKeys: function(hash) {
  46. if (typeof(hash) === "undefined") {
  47. return;
  48. }
  49. _.each(_.keys(hash), function(v) {
  50. var split = v.split("@ui.");
  51. if (split.length === 2) {
  52. hash[split[0]+this.ui[split[1]]] = hash[v];
  53. delete hash[v];
  54. }
  55. }, this);
  56. return hash;
  57. },
  58. // Configure `triggers` to forward DOM events to view
  59. // events. `triggers: {"click .foo": "do:foo"}`
  60. configureTriggers: function(){
  61. if (!this.triggers) { return; }
  62. var triggerEvents = {};
  63. // Allow `triggers` to be configured as a function
  64. var triggers = this.normalizeUIKeys(_.result(this, "triggers"));
  65. // Configure the triggers, prevent default
  66. // action and stop propagation of DOM events
  67. _.each(triggers, function(value, key){
  68. var hasOptions = _.isObject(value);
  69. var eventName = hasOptions ? value.event : value;
  70. // build the event handler function for the DOM event
  71. triggerEvents[key] = function(e){
  72. // stop the event in its tracks
  73. if (e) {
  74. var prevent = e.preventDefault;
  75. var stop = e.stopPropagation;
  76. var shouldPrevent = hasOptions ? value.preventDefault : prevent;
  77. var shouldStop = hasOptions ? value.stopPropagation : stop;
  78. if (shouldPrevent && prevent) { prevent.apply(e); }
  79. if (shouldStop && stop) { stop.apply(e); }
  80. }
  81. // build the args for the event
  82. var args = {
  83. view: this,
  84. model: this.model,
  85. collection: this.collection
  86. };
  87. // trigger the event
  88. this.triggerMethod(eventName, args);
  89. };
  90. }, this);
  91. return triggerEvents;
  92. },
  93. // Overriding Backbone.View's delegateEvents to handle
  94. // the `triggers`, `modelEvents`, and `collectionEvents` configuration
  95. delegateEvents: function(events){
  96. this._delegateDOMEvents(events);
  97. Marionette.bindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
  98. Marionette.bindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
  99. },
  100. // internal method to delegate DOM events and triggers
  101. _delegateDOMEvents: function(events){
  102. events = events || this.events;
  103. if (_.isFunction(events)){ events = events.call(this); }
  104. var combinedEvents = {};
  105. var triggers = this.configureTriggers();
  106. _.extend(combinedEvents, events, triggers);
  107. Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
  108. },
  109. // Overriding Backbone.View's undelegateEvents to handle unbinding
  110. // the `triggers`, `modelEvents`, and `collectionEvents` config
  111. undelegateEvents: function(){
  112. var args = Array.prototype.slice.call(arguments);
  113. Backbone.View.prototype.undelegateEvents.apply(this, args);
  114. Marionette.unbindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
  115. Marionette.unbindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
  116. },
  117. // Internal method, handles the `show` event.
  118. onShowCalled: function(){},
  119. // Default `close` implementation, for removing a view from the
  120. // DOM and unbinding it. Regions will call this method
  121. // for you. You can specify an `onClose` method in your view to
  122. // add custom code that is called after the view is closed.
  123. close: function(){
  124. if (this.isClosed) { return; }
  125. // allow the close to be stopped by returning `false`
  126. // from the `onBeforeClose` method
  127. var shouldClose = this.triggerMethod("before:close");
  128. if (shouldClose === false){
  129. return;
  130. }
  131. // mark as closed before doing the actual close, to
  132. // prevent infinite loops within "close" event handlers
  133. // that are trying to close other views
  134. this.isClosed = true;
  135. this.triggerMethod("close");
  136. // unbind UI elements
  137. this.unbindUIElements();
  138. // remove the view from the DOM
  139. this.remove();
  140. },
  141. // This method binds the elements specified in the "ui" hash inside the view's code with
  142. // the associated jQuery selectors.
  143. bindUIElements: function(){
  144. if (!this.ui) { return; }
  145. // store the ui hash in _uiBindings so they can be reset later
  146. // and so re-rendering the view will be able to find the bindings
  147. if (!this._uiBindings){
  148. this._uiBindings = this.ui;
  149. }
  150. // get the bindings result, as a function or otherwise
  151. var bindings = _.result(this, "_uiBindings");
  152. // empty the ui so we don't have anything to start with
  153. this.ui = {};
  154. // bind each of the selectors
  155. _.each(_.keys(bindings), function(key) {
  156. var selector = bindings[key];
  157. this.ui[key] = this.$(selector);
  158. }, this);
  159. },
  160. // This method unbinds the elements specified in the "ui" hash
  161. unbindUIElements: function(){
  162. if (!this.ui || !this._uiBindings){ return; }
  163. // delete all of the existing ui bindings
  164. _.each(this.ui, function($el, name){
  165. delete this.ui[name];
  166. }, this);
  167. // reset the ui element to the original bindings configuration
  168. this.ui = this._uiBindings;
  169. delete this._uiBindings;
  170. }
  171. });