marionette-rails 1.0.0.rc2 → 1.0.0.rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- // Backbone.Marionette, v1.0.0-rc2
2
- // Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
1
+ // Backbone.Marionette, v1.0.0-rc3
2
+ // Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
3
3
  // Distributed under MIT license
4
4
  // http://github.com/marionettejs/backbone.marionette
5
5
 
@@ -10,9 +10,6 @@
10
10
  *
11
11
  * Includes Wreqr
12
12
  * https://github.com/marionettejs/backbone.wreqr/
13
- *
14
- * Includes EventBinder
15
- * https://github.com/marionettejs/backbone.eventbinder/
16
13
  */
17
14
 
18
15
 
@@ -210,133 +207,7 @@ Backbone.ChildViewContainer = (function(Backbone, _){
210
207
  return Container;
211
208
  })(Backbone, _);
212
209
 
213
- // Backbone.EventBinder, v1.0.2
214
- // Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
215
- // Distributed under MIT license
216
- // http://github.com/marionettejs/backbone.eventbinder
217
- // EventBinder
218
- // -----------
219
- //
220
- // The event binder facilitates the binding and unbinding of events
221
- // from objects that extend `Backbone.Events`. It makes
222
- // unbinding events, even with anonymous callback functions,
223
- // easy.
224
- //
225
- // Inspired by [Johnny Oshika](http://stackoverflow.com/questions/7567404/backbone-js-repopulate-or-recreate-the-view/7607853#7607853)
226
-
227
- Backbone.EventBinder = (function(Backbone, _){
228
- "use strict";
229
-
230
- // A map of objects that support binding/unbinding events.
231
- // This allows EventBinder to support events on arbitrary
232
- // objects with EB's consistent api.
233
- var handlerMap = {
234
- // 'default' type accounts for Backbone style objects extending
235
- // Backbone.Events
236
- "default" : {
237
- bindTo : function (obj, eventName, callback, context) {
238
- context = context || this;
239
- obj.on(eventName, callback, context);
240
-
241
- var binding = {
242
- type : 'default',
243
- obj: obj,
244
- eventName: eventName,
245
- callback: callback,
246
- context: context
247
- };
248
-
249
- return binding;
250
- },
251
- unbindFrom : function(binding){
252
- binding.obj.off(binding.eventName, binding.callback, binding.context);
253
- }
254
- },
255
-
256
- // 'jquery' style handlers allow us to bind to jQuery
257
- // (or compatible) objects
258
- jquery : {
259
- bindTo : function (obj, eventName, callback, context) {
260
- context = context || this;
261
- callback = _(callback).bind(context);
262
- obj.on(eventName, callback);
263
-
264
- var binding = {
265
- type : 'jquery',
266
- obj: obj,
267
- eventName: eventName,
268
- callback: callback,
269
- context: context
270
- };
271
-
272
- return binding;
273
- },
274
- unbindFrom : function(binding){
275
- binding.obj.off(binding.eventName, binding.callback);
276
- }
277
- }
278
- };
279
-
280
- // Use whatever best logic necessary to determine the type
281
- // of the supplied object
282
- function getHandlerForObject(obj) {
283
- if (_.isUndefined(obj) || _.isNull(obj)) {
284
- throw new Error("Can't bindTo undefined");
285
- }
286
-
287
- if (obj.jquery) { return handlerMap.jquery; }
288
-
289
- return handlerMap["default"];
290
- }
291
-
292
- // Constructor function
293
- var EventBinder = function(){
294
- this._eventBindings = [];
295
- };
296
-
297
- // Copy the `extend` function used by Backbone's classes
298
- EventBinder.extend = Backbone.View.extend;
299
-
300
- // Extend the EventBinder with additional methods
301
- _.extend(EventBinder.prototype, {
302
-
303
- // Delegate to the bindTo for the appropriate type and
304
- // store the event binding in array so it can be unbound
305
- // easily, at a later point in time.
306
- bindTo: function(/* args... */) {
307
- var obj = arguments[0];
308
- var handlers = getHandlerForObject(obj);
309
-
310
- var args = Array.prototype.slice.apply(arguments);
311
- var binding = handlers.bindTo.apply(this, args);
312
-
313
- this._eventBindings.push(binding);
314
-
315
- return binding;
316
- },
317
-
318
- // Unbind from a single binding object. Binding objects are
319
- // returned from the `bindTo` method call.
320
- unbindFrom: function(binding) {
321
- var args = Array.prototype.slice.apply(arguments);
322
- handlerMap[binding.type].unbindFrom.apply(this, args);
323
-
324
- this._eventBindings = _.reject(this._eventBindings, function(bind){return bind === binding;});
325
- },
326
-
327
- // Unbind all of the events that we have stored.
328
- unbindAll: function() {
329
- // The `unbindFrom` call removes elements from the array
330
- // while it is being iterated, so clone it first.
331
- var bindings = _.map(this._eventBindings, _.identity);
332
- _.each(bindings, this.unbindFrom, this);
333
- }
334
- });
335
-
336
- return EventBinder;
337
- })(Backbone, _);
338
-
339
- // Backbone.Wreqr, v0.1.0
210
+ // Backbone.Wreqr, v0.2.0
340
211
  // Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
341
212
  // Distributed under MIT license
342
213
  // http://github.com/marionettejs/backbone.wreqr
@@ -451,24 +322,43 @@ Backbone.Wreqr = (function(Backbone, Marionette, _){
451
322
  // of an application through event-driven architecture.
452
323
 
453
324
  Wreqr.EventAggregator = (function(Backbone, _){
454
- "option strict";
455
- var EA = function(){};
456
325
 
457
- // Copy the `extend` function used by Backbone's classes
458
- EA.extend = Backbone.Model.extend;
326
+ // Grab a reference to the original listenTo
327
+ var listenTo = Backbone.Events.listenTo;
459
328
 
460
- // Copy the basic Backbone.Events on to the event aggregator
461
- _.extend(EA.prototype, Backbone.Events);
329
+ // Create a version of listenTo that allows contexting binding
330
+ function contextBoundListenTo(obj, evtSource, events, callback, context){
331
+ context = context || obj;
332
+ return listenTo.call(obj, evtSource, events, _.bind(callback, context));
333
+ }
462
334
 
463
- return EA;
335
+ // Define the EventAggregator
336
+ function EventAggregator(){}
337
+
338
+ // Mix Backbone.Events in to it
339
+ _.extend(EventAggregator.prototype, Backbone.Events, {
340
+ // Override the listenTo so that we can have a version that
341
+ // correctly binds context
342
+ listenTo: function(evtSource, events, callback, context){
343
+ return contextBoundListenTo(this, evtSource, events, callback, context);
344
+ }
345
+ });
346
+
347
+ // Allow it to be extended
348
+ EventAggregator.extend = Backbone.Model.extend;
349
+
350
+ return EventAggregator;
464
351
  })(Backbone, _);
465
352
 
466
353
 
467
354
  return Wreqr;
468
355
  })(Backbone, Backbone.Marionette, _);
469
356
 
470
- Backbone.Marionette = Marionette = (function(Backbone, _, $){
357
+ var Marionette = (function(Backbone, _, $){
358
+ "use strict";
359
+
471
360
  var Marionette = {};
361
+ Backbone.Marionette = Marionette;
472
362
 
473
363
  // Helpers
474
364
  // -------
@@ -608,44 +498,48 @@ Marionette.MonitorDOMRefresh = (function(){
608
498
 
609
499
  // Export public API
610
500
  return function(view){
611
- view.bindTo(view, "show", function(){
501
+ view.listenTo(view, "show", function(){
612
502
  handleShow(view);
613
503
  });
614
504
 
615
- view.bindTo(view, "render", function(){
505
+ view.listenTo(view, "render", function(){
616
506
  handleRender(view);
617
507
  });
618
508
  };
619
509
  })();
620
510
 
621
511
 
622
- // EventBinder
623
- // -----------
624
- // Import the event binder from it's new home
625
- // https://github.com/marionettejs/backbone.eventbinder
626
- Marionette.EventBinder = Backbone.EventBinder.extend();
627
-
628
- // Add the EventBinder methods to the view directly,
629
- // but keep them bound to the EventBinder instance so they work properly.
630
- // This allows the event binder's implementation to vary independently
631
- // of it being attached to the view... for example the internal structure
632
- // used to store the events can change without worry about it interfering
633
- // with Marionette's views.
634
- Marionette.addEventBinder = function(target){
635
- var eventBinder = new Marionette.EventBinder();
636
- target.eventBinder = eventBinder;
637
-
638
- target.bindTo = function(source, event, callback, context){
639
- // check the context of the bindTo and set it to the object
640
- // that is having the eventBinder attached to it, if no context
641
- // has been specified in the .bindTo call
642
- context = context || target;
643
- eventBinder.bindTo(source, event, callback, context);
512
+ // addEventBinder
513
+ // --------------
514
+ //
515
+ // Mixes in Backbone.Events to the target object, if it is not present
516
+ // already. Also adjusts the listenTo method to accept a 4th parameter
517
+ // for the callback context.
518
+
519
+ (function(Backbone, Marionette, _){
520
+
521
+ // grab a reference to the original listenTo
522
+ var listenTo = Backbone.Events.listenTo;
523
+
524
+ // Fix the listenTo method on the target object, allowing the 4th
525
+ // context parameter to be specified
526
+ Marionette.addEventBinder = function(target){
527
+ // If the target is not already extending Backbone.Events,
528
+ // then extend that on to it first
529
+ if (!target.on && !target.off && !target.listenTo && !target.stopListening){
530
+ _.extend(target, Backbone.Events);
531
+ }
532
+
533
+ // Override the built-in listenTo method to make sure we
534
+ // account for context
535
+ target.listenTo = function(evtSource, events, callback, context){
536
+ context = context || this;
537
+ return listenTo.call(this, evtSource, events, _.bind(callback, context));
538
+ };
644
539
  };
645
540
 
646
- target.unbindFrom = _.bind(eventBinder.unbindFrom, eventBinder);
647
- target.unbindAll = _.bind(eventBinder.unbindAll, eventBinder);
648
- };
541
+ })(Backbone, Marionette, _);
542
+
649
543
 
650
544
  // Event Aggregator
651
545
  // ----------------
@@ -665,13 +559,13 @@ Marionette.EventAggregator = Backbone.Wreqr.EventAggregator.extend({
665
559
 
666
560
  });
667
561
 
668
- // Marionette.bindEntityEvents
562
+ // Marionette.bindEntityEvents & unbindEntityEvents
669
563
  // ---------------------------
670
564
  //
671
- // This method is used to bind a backbone "entity" (collection/model)
565
+ // These methods are used to bind/unbind a backbone "entity" (collection/model)
672
566
  // to methods on a target object.
673
567
  //
674
- // The first paremter, `target`, must have a `bindTo` method from the
568
+ // The first paremter, `target`, must have a `listenTo` method from the
675
569
  // EventBinder object.
676
570
  //
677
571
  // The second parameter is the entity (Backbone.Model or Backbone.Collection)
@@ -680,7 +574,9 @@ Marionette.EventAggregator = Backbone.Wreqr.EventAggregator.extend({
680
574
  // The third parameter is a hash of { "event:name": "eventHandler" }
681
575
  // configuration. Multiple handlers can be separated by a space. A
682
576
  // function can be supplied instead of a string handler name.
683
- Marionette.bindEntityEvents = (function(){
577
+
578
+ (function(Marionette){
579
+ "use strict";
684
580
 
685
581
  // Bind the event to handlers specified as a string of
686
582
  // handler names on the target object
@@ -694,32 +590,65 @@ Marionette.bindEntityEvents = (function(){
694
590
  throw new Error("Method '"+ methodName +"' was configured as an event handler, but does not exist.");
695
591
  }
696
592
 
697
- target.bindTo(entity, evt, method, target);
593
+ target.listenTo(entity, evt, method, target);
698
594
  });
699
595
  }
700
596
 
701
597
  // Bind the event to a supplied callback function
702
598
  function bindToFunction(target, entity, evt, method){
703
- target.bindTo(entity, evt, method, target);
599
+ target.listenTo(entity, evt, method, target);
600
+ }
601
+
602
+ // Bind the event to handlers specified as a string of
603
+ // handler names on the target object
604
+ function unbindFromStrings(target, entity, evt, methods){
605
+ var methodNames = methods.split(/\s+/);
606
+
607
+ _.each(methodNames,function(methodName) {
608
+ var method = target[method];
609
+ target.stopListening(entity, evt, method, target);
610
+ });
611
+ }
612
+
613
+ // Bind the event to a supplied callback function
614
+ function unbindToFunction(target, entity, evt, method){
615
+ target.stopListening(entity, evt, method, target);
704
616
  }
705
617
 
706
- // Export the bindEntityEvents method
707
- return function(target, entity, bindings){
618
+
619
+ // generic looping function
620
+ function iterateEvents(target, entity, bindings, functionCallback, stringCallback){
708
621
  if (!entity || !bindings) { return; }
709
622
 
623
+ // allow the bindings to be a function
624
+ if (_.isFunction(bindings)){
625
+ bindings = bindings.call(target);
626
+ }
627
+
628
+ // iterate the bindings and bind them
710
629
  _.each(bindings, function(methods, evt){
711
630
 
712
631
  // allow for a function as the handler,
713
632
  // or a list of event names as a string
714
633
  if (_.isFunction(methods)){
715
- bindToFunction(target, entity, evt, methods);
634
+ functionCallback(target, entity, evt, methods);
716
635
  } else {
717
- bindFromStrings(target, entity, evt, methods);
636
+ stringCallback(target, entity, evt, methods);
718
637
  }
719
638
 
720
639
  });
640
+ }
641
+
642
+ // Export Public API
643
+ Marionette.bindEntityEvents = function(target, entity, bindings){
644
+ iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings);
721
645
  };
722
- })();
646
+
647
+ Marionette.unbindEntityEvents = function(target, entity, bindings){
648
+ iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings);
649
+ };
650
+
651
+ })(Marionette);
723
652
 
724
653
 
725
654
  // Callbacks
@@ -793,7 +722,7 @@ Marionette.Controller.extend = Marionette.extend;
793
722
  // Ensure it can trigger events with Backbone.Events
794
723
  _.extend(Marionette.Controller.prototype, Backbone.Events, {
795
724
  close: function(){
796
- this.unbindAll();
725
+ this.stopListening();
797
726
  this.triggerMethod("close");
798
727
  this.unbind();
799
728
  }
@@ -1099,11 +1028,8 @@ Marionette.View = Backbone.View.extend({
1099
1028
  var args = Array.prototype.slice.apply(arguments);
1100
1029
  Backbone.View.prototype.constructor.apply(this, args);
1101
1030
 
1102
- Marionette.bindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
1103
- Marionette.bindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
1104
-
1105
1031
  Marionette.MonitorDOMRefresh(this);
1106
- this.bindTo(this, "show", this.onShowCalled, this);
1032
+ this.listenTo(this, "show", this.onShowCalled, this);
1107
1033
  },
1108
1034
 
1109
1035
  // import the "triggerMethod" to trigger events with corresponding
@@ -1147,10 +1073,22 @@ Marionette.View = Backbone.View.extend({
1147
1073
  // action and stop propagation of DOM events
1148
1074
  _.each(triggers, function(value, key){
1149
1075
 
1076
+ // build the event handler function for the DOM event
1150
1077
  triggerEvents[key] = function(e){
1078
+
1079
+ // stop the event in it's tracks
1151
1080
  if (e && e.preventDefault){ e.preventDefault(); }
1152
1081
  if (e && e.stopPropagation){ e.stopPropagation(); }
1153
- that.trigger(value);
1082
+
1083
+ // buil the args for the event
1084
+ var args = {
1085
+ view: this,
1086
+ model: this.model,
1087
+ collection: this.collection
1088
+ };
1089
+
1090
+ // trigger the event
1091
+ that.trigger(value, args);
1154
1092
  };
1155
1093
 
1156
1094
  });
@@ -1158,9 +1096,16 @@ Marionette.View = Backbone.View.extend({
1158
1096
  return triggerEvents;
1159
1097
  },
1160
1098
 
1161
- // Overriding Backbone.View's delegateEvents specifically
1162
- // to handle the `triggers` configuration
1099
+ // Overriding Backbone.View's delegateEvents to handle
1100
+ // the `triggers`, `modelEvents`, and `collectionEvents` configuration
1163
1101
  delegateEvents: function(events){
1102
+ this._delegateDOMEvents(events);
1103
+ Marionette.bindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
1104
+ Marionette.bindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
1105
+ },
1106
+
1107
+ // internal method to delegate DOM events and triggers
1108
+ _delegateDOMEvents: function(events){
1164
1109
  events = events || this.events;
1165
1110
  if (_.isFunction(events)){ events = events.call(this); }
1166
1111
 
@@ -1171,6 +1116,16 @@ Marionette.View = Backbone.View.extend({
1171
1116
  Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
1172
1117
  },
1173
1118
 
1119
+ // Overriding Backbone.View's undelegateEvents to handle unbinding
1120
+ // the `triggers`, `modelEvents`, and `collectionEvents` config
1121
+ undelegateEvents: function(){
1122
+ var args = Array.prototype.slice.call(arguments);
1123
+ Backbone.View.prototype.undelegateEvents.apply(this, args);
1124
+
1125
+ Marionette.unbindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
1126
+ Marionette.unbindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
1127
+ },
1128
+
1174
1129
  // Internal method, handles the `show` event.
1175
1130
  onShowCalled: function(){},
1176
1131
 
@@ -1192,10 +1147,9 @@ Marionette.View = Backbone.View.extend({
1192
1147
  // prevent infinite loops within "close" event handlers
1193
1148
  // that are trying to close other views
1194
1149
  this.isClosed = true;
1150
+ this.triggerMethod("close");
1195
1151
 
1196
1152
  this.remove();
1197
- this.triggerMethod("close");
1198
- this.unbindAll();
1199
1153
  },
1200
1154
 
1201
1155
  // This method binds the elements specified in the "ui" hash inside the view's code with
@@ -1208,7 +1162,7 @@ Marionette.View = Backbone.View.extend({
1208
1162
  if (!this.uiBindings) {
1209
1163
  // We want to store the ui hash in uiBindings, since afterwards the values in the ui hash
1210
1164
  // will be overridden with jQuery selectors.
1211
- this.uiBindings = this.ui;
1165
+ this.uiBindings = _.result(this, "ui");
1212
1166
  }
1213
1167
 
1214
1168
  // refreshing the associated selectors since they should point to the newly rendered elements.
@@ -1230,10 +1184,6 @@ Marionette.ItemView = Marionette.View.extend({
1230
1184
  constructor: function(){
1231
1185
  var args = Array.prototype.slice.apply(arguments);
1232
1186
  Marionette.View.prototype.constructor.apply(this, args);
1233
-
1234
- if (this.initialEvents){
1235
- this.initialEvents();
1236
- }
1237
1187
  },
1238
1188
 
1239
1189
  // Serialize the model or collection for the view. If a model is
@@ -1306,23 +1256,22 @@ Marionette.CollectionView = Marionette.View.extend({
1306
1256
 
1307
1257
  // constructor
1308
1258
  constructor: function(options){
1309
- this.initChildViewStorage();
1310
- this.onShowCallbacks = new Marionette.Callbacks();
1259
+ this._initChildViewStorage();
1311
1260
 
1312
1261
  var args = Array.prototype.slice.apply(arguments);
1313
1262
  Marionette.View.prototype.constructor.apply(this, args);
1314
1263
 
1315
- this.initialEvents();
1264
+ this._initialEvents();
1316
1265
  },
1317
1266
 
1318
1267
  // Configured the initial events that the collection view
1319
1268
  // binds to. Override this method to prevent the initial
1320
1269
  // events, or to add your own initial events.
1321
- initialEvents: function(){
1270
+ _initialEvents: function(){
1322
1271
  if (this.collection){
1323
- this.bindTo(this.collection, "add", this.addChildView, this);
1324
- this.bindTo(this.collection, "remove", this.removeItemView, this);
1325
- this.bindTo(this.collection, "reset", this.render, this);
1272
+ this.listenTo(this.collection, "add", this.addChildView, this);
1273
+ this.listenTo(this.collection, "remove", this.removeItemView, this);
1274
+ this.listenTo(this.collection, "reset", this.render, this);
1326
1275
  }
1327
1276
  },
1328
1277
 
@@ -1330,21 +1279,16 @@ Marionette.CollectionView = Marionette.View.extend({
1330
1279
  addChildView: function(item, collection, options){
1331
1280
  this.closeEmptyView();
1332
1281
  var ItemView = this.getItemView(item);
1333
-
1334
- var index;
1335
- if(options && options.index){
1336
- index = options.index;
1337
- } else {
1338
- index = 0;
1339
- }
1340
-
1341
- return this.addItemView(item, ItemView, index);
1282
+ var index = this.collection.indexOf(item);
1283
+ this.addItemView(item, ItemView, index);
1342
1284
  },
1343
1285
 
1344
1286
  // Override from `Marionette.View` to guarantee the `onShow` method
1345
1287
  // of child views is called.
1346
1288
  onShowCalled: function(){
1347
- this.onShowCallbacks.run();
1289
+ this.children.each(function(child){
1290
+ Marionette.triggerMethod.call(child, "show");
1291
+ });
1348
1292
  },
1349
1293
 
1350
1294
  // Internal method to trigger the before render callbacks
@@ -1454,18 +1398,17 @@ Marionette.CollectionView = Marionette.View.extend({
1454
1398
  // remove and/or close it later
1455
1399
  this.children.add(view);
1456
1400
 
1401
+ // call the "show" method if the collection view
1402
+ // has already been shown
1403
+ if (this._isShown){
1404
+ Marionette.triggerMethod.call(view, "show");
1405
+ }
1406
+
1457
1407
  // Render it and show it
1458
1408
  var renderResult = this.renderItemView(view, index);
1459
1409
 
1460
1410
  // this view was added
1461
1411
  this.triggerMethod("after:item:added", view);
1462
-
1463
- // call onShow for child item views
1464
- if (view.onShow){
1465
- this.onShowCallbacks.add(view.onShow, view);
1466
- }
1467
-
1468
- return renderResult;
1469
1412
  },
1470
1413
 
1471
1414
  // Set up the child view event forwarding. Uses an "itemview:"
@@ -1475,18 +1418,13 @@ Marionette.CollectionView = Marionette.View.extend({
1475
1418
 
1476
1419
  // Forward all child item view events through the parent,
1477
1420
  // prepending "itemview:" to the event name
1478
- var childBinding = this.bindTo(view, "all", function(){
1421
+ this.listenTo(view, "all", function(){
1479
1422
  var args = slice.call(arguments);
1480
1423
  args[0] = prefix + ":" + args[0];
1481
1424
  args.splice(1, 0, view);
1482
1425
 
1483
- this.triggerMethod.apply(this, args);
1426
+ Marionette.triggerMethod.apply(this, args);
1484
1427
  }, this);
1485
-
1486
- // Store all child event bindings so we can unbind
1487
- // them when removing / closing the child view
1488
- this._childBindings = this._childBindings || {};
1489
- this._childBindings[view.cid] = childBinding;
1490
1428
  },
1491
1429
 
1492
1430
  // render the item view
@@ -1502,16 +1440,19 @@ Marionette.CollectionView = Marionette.View.extend({
1502
1440
  return view;
1503
1441
  },
1504
1442
 
1505
- // Remove the child view and close it
1443
+ // get the child view by item it holds, and remove it
1506
1444
  removeItemView: function(item){
1507
1445
  var view = this.children.findByModel(item);
1446
+ this.removeChildView(view);
1447
+ },
1448
+
1449
+ // Remove the child view and close it
1450
+ removeChildView: function(view){
1508
1451
 
1452
+ // shut down the child view properly,
1453
+ // including events that the collection has from it
1509
1454
  if (view){
1510
- var childBinding = this._childBindings[view.cid];
1511
- if (childBinding) {
1512
- this.unbindFrom(childBinding);
1513
- delete this._childBindings[view.cid];
1514
- }
1455
+ this.stopListening(view);
1515
1456
 
1516
1457
  if (view.close){
1517
1458
  view.close();
@@ -1520,6 +1461,8 @@ Marionette.CollectionView = Marionette.View.extend({
1520
1461
  this.children.remove(view);
1521
1462
  }
1522
1463
 
1464
+ // check if we're empty now, and if we are, show the
1465
+ // empty view
1523
1466
  if (!this.collection || this.collection.length === 0){
1524
1467
  this.showEmptyView();
1525
1468
  }
@@ -1536,7 +1479,7 @@ Marionette.CollectionView = Marionette.View.extend({
1536
1479
 
1537
1480
  // Internal method to set up the `children` object for
1538
1481
  // storing all of the child views
1539
- initChildViewStorage: function(){
1482
+ _initChildViewStorage: function(){
1540
1483
  this.children = new Backbone.ChildViewContainer();
1541
1484
  },
1542
1485
 
@@ -1556,10 +1499,12 @@ Marionette.CollectionView = Marionette.View.extend({
1556
1499
  // Close the child views that this collection view
1557
1500
  // is holding on to, if any
1558
1501
  closeChildren: function(){
1559
- var that = this;
1560
- this.children.apply("close");
1502
+ this.children.each(function(child){
1503
+ this.removeChildView(child);
1504
+ }, this);
1505
+
1561
1506
  // re-initialize to clean up after ourselves
1562
- this.initChildViewStorage();
1507
+ this._initChildViewStorage();
1563
1508
  }
1564
1509
  });
1565
1510
 
@@ -1581,11 +1526,11 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
1581
1526
  // Configured the initial events that the composite view
1582
1527
  // binds to. Override this method to prevent the initial
1583
1528
  // events, or to add your own initial events.
1584
- initialEvents: function(){
1529
+ _initialEvents: function(){
1585
1530
  if (this.collection){
1586
- this.bindTo(this.collection, "add", this.addChildView, this);
1587
- this.bindTo(this.collection, "remove", this.removeItemView, this);
1588
- this.bindTo(this.collection, "reset", this.renderCollection, this);
1531
+ this.listenTo(this.collection, "add", this.addChildView, this);
1532
+ this.listenTo(this.collection, "remove", this.removeItemView, this);
1533
+ this.listenTo(this.collection, "reset", this.renderCollection, this);
1589
1534
  }
1590
1535
  },
1591
1536
 
@@ -1724,7 +1669,7 @@ Marionette.Layout = Marionette.ItemView.extend({
1724
1669
  this.initializeRegions();
1725
1670
 
1726
1671
  var args = Array.prototype.slice.apply(arguments);
1727
- Backbone.Marionette.ItemView.apply(this, args);
1672
+ Marionette.ItemView.apply(this, args);
1728
1673
  },
1729
1674
 
1730
1675
  // Layout's render will use the existing region objects the
@@ -1758,7 +1703,7 @@ Marionette.Layout = Marionette.ItemView.extend({
1758
1703
  this.destroyRegions();
1759
1704
 
1760
1705
  var args = Array.prototype.slice.apply(arguments);
1761
- Backbone.Marionette.ItemView.prototype.close.apply(this, args);
1706
+ Marionette.ItemView.prototype.close.apply(this, args);
1762
1707
  },
1763
1708
 
1764
1709
  // Initialize the regions that have been defined in a
@@ -1988,15 +1933,15 @@ Marionette.Module = function(moduleName, app){
1988
1933
  this._setupInitializersAndFinalizers();
1989
1934
 
1990
1935
  // store the configuration for this module
1991
- this.config = {};
1992
- this.config.app = app;
1936
+ this.app = app;
1937
+ this.startWithParent = true;
1993
1938
 
1994
1939
  // extend this module with an event binder
1995
1940
  Marionette.addEventBinder(this);
1996
1941
  this.triggerMethod = Marionette.triggerMethod;
1997
1942
  };
1998
1943
 
1999
- // Extend the Module prototype with events / bindTo, so that the module
1944
+ // Extend the Module prototype with events / listenTo, so that the module
2000
1945
  // can be used as an event aggregator or pub/sub.
2001
1946
  _.extend(Marionette.Module.prototype, Backbone.Events, {
2002
1947
 
@@ -2022,9 +1967,7 @@ _.extend(Marionette.Module.prototype, Backbone.Events, {
2022
1967
  _.each(this.submodules, function(mod){
2023
1968
  // check to see if we should start the sub-module with this parent
2024
1969
  var startWithParent = true;
2025
- if (mod.config && mod.config.options){
2026
- startWithParent = mod.config.options.startWithParent;
2027
- }
1970
+ startWithParent = mod.startWithParent;
2028
1971
 
2029
1972
  // start the sub-module
2030
1973
  if (startWithParent){
@@ -2078,7 +2021,7 @@ _.extend(Marionette.Module.prototype, Backbone.Events, {
2078
2021
  // build the correct list of arguments for the module definition
2079
2022
  var args = _.flatten([
2080
2023
  this,
2081
- this.config.app,
2024
+ this.app,
2082
2025
  Backbone,
2083
2026
  Marionette,
2084
2027
  $, _,
@@ -2097,79 +2040,39 @@ _.extend(Marionette.Module.prototype, Backbone.Events, {
2097
2040
  }
2098
2041
  });
2099
2042
 
2100
- // Function level methods to create modules
2043
+ // Type methods to create modules
2101
2044
  _.extend(Marionette.Module, {
2102
2045
 
2103
2046
  // Create a module, hanging off the app parameter as the parent object.
2104
2047
  create: function(app, moduleNames, moduleDefinition){
2105
2048
  var that = this;
2106
- var parentModule = app;
2107
- moduleNames = moduleNames.split(".");
2049
+ var module = app;
2108
2050
 
2109
2051
  // get the custom args passed in after the module definition and
2110
2052
  // get rid of the module name and definition function
2111
2053
  var customArgs = slice.apply(arguments);
2112
2054
  customArgs.splice(0, 3);
2113
2055
 
2114
- // Loop through all the parts of the module definition
2056
+ // split the module names and get the length
2057
+ moduleNames = moduleNames.split(".");
2115
2058
  var length = moduleNames.length;
2116
- _.each(moduleNames, function(moduleName, i){
2117
- var isLastModuleInChain = (i === length-1);
2118
- var isFirstModuleInChain = (i === 0);
2119
- var module = that._getModuleDefinition(parentModule, moduleName, app);
2120
-
2121
- // if this is the last module in the chain, then set up
2122
- // all of the module options from the configuration
2123
- if (isLastModuleInChain){
2124
- module.config.options = that._getModuleOptions(module, parentModule, moduleDefinition);
2125
-
2126
- // Only add a module definition and initializer when this is the last
2127
- // module in a "parent.child.grandchild" hierarchy of module names and
2128
- // when the module call has a definition function supplied
2129
- if (module.config.options.hasDefinition){
2130
- module.addDefinition(module.config.options.definition, customArgs);
2131
- }
2132
- }
2133
2059
 
2134
- // if it's a top level module, and this is the only
2135
- // module in the chain, then this one gets configured
2136
- // to start with the parent app.
2137
- if (isFirstModuleInChain && isLastModuleInChain ){
2138
- that._configureStartWithApp(app, module);
2139
- }
2060
+ // store the module definition for the last module in the chain
2061
+ var moduleDefinitions = [];
2062
+ moduleDefinitions[length-1] = moduleDefinition;
2140
2063
 
2141
- // Reset the parent module so that the next child
2142
- // in the list will be added to the correct parent
2143
- parentModule = module;
2064
+ // Loop through all the parts of the module definition
2065
+ _.each(moduleNames, function(moduleName, i){
2066
+ var parentModule = module;
2067
+ module = that._getModule(parentModule, moduleName, app);
2068
+ that._addModuleDefinition(parentModule, module, moduleDefinitions[i], customArgs);
2144
2069
  });
2145
2070
 
2146
2071
  // Return the last module in the definition chain
2147
- return parentModule;
2148
- },
2149
-
2150
- // Only add the initializer if it is set to start with parent (the app),
2151
- // and if it has not yet been added
2152
- _configureStartWithApp: function(app, module){
2153
- // skip this if we have already configured the module to start w/ the app
2154
- if (module.config.startWithAppIsConfigured){
2155
- return;
2156
- }
2157
-
2158
- // start the module when the app starts
2159
- app.addInitializer(function(options){
2160
- // but only if the module is configured to start w/ parent
2161
- if (module.config.options.startWithParent){
2162
- module.start(options);
2163
- }
2164
- });
2165
-
2166
- // prevent this module from being configured for
2167
- // auto start again. the first time the module
2168
- // is defined, determines it's auto-start
2169
- module.config.startWithAppIsConfigured = true;
2072
+ return module;
2170
2073
  },
2171
2074
 
2172
- _getModuleDefinition: function(parentModule, moduleName, app){
2075
+ _getModule: function(parentModule, moduleName, app, def, args){
2173
2076
  // Get an existing module of this name if we have one
2174
2077
  var module = parentModule[moduleName];
2175
2078
 
@@ -2184,45 +2087,54 @@ _.extend(Marionette.Module, {
2184
2087
  return module;
2185
2088
  },
2186
2089
 
2187
- _getModuleOptions: function(module, parentModule, moduleDefinition){
2188
- // default to starting the module with it's parent to whatever the
2189
- var startWithParent = true;
2190
- if (module.config.options && !module.config.options.startWithParent){
2191
- startWithParent = false;
2192
- }
2090
+ _addModuleDefinition: function(parentModule, module, def, args){
2091
+ var fn;
2092
+ var startWithParent;
2193
2093
 
2194
- // set up initial options for the module
2195
- var options = {
2196
- startWithParent: startWithParent,
2197
- hasDefinition: !!moduleDefinition
2198
- };
2094
+ if (_.isFunction(def)){
2095
+ // if a function is supplied for the module definition
2096
+ fn = def;
2097
+ startWithParent = true;
2199
2098
 
2200
- // short circuit if we don't have a module definition
2201
- if (!options.hasDefinition){ return options; }
2099
+ } else if (_.isObject(def)){
2100
+ // if an object is supplied
2101
+ fn = def.define;
2102
+ startWithParent = def.startWithParent;
2103
+
2104
+ } else {
2105
+ // if nothing is supplied
2106
+ startWithParent = true;
2107
+ }
2202
2108
 
2203
- if (_.isFunction(moduleDefinition)){
2204
- // if the definition is a function, assign it directly
2205
- // and use the defaults
2206
- options.definition = moduleDefinition;
2109
+ // add module definition if needed
2110
+ if (fn){
2111
+ module.addDefinition(fn, args);
2112
+ }
2207
2113
 
2208
- } else {
2114
+ // `and` the two together, ensuring a single `false` will prevent it
2115
+ // from starting with the parent
2116
+ var tmp = module.startWithParent;
2117
+ module.startWithParent = module.startWithParent && startWithParent;
2209
2118
 
2210
- // the definition is an object.
2119
+ // setup auto-start if needed
2120
+ if (module.startWithParent && !module.startWithParentIsConfigured){
2211
2121
 
2212
- // grab the "define" attribute
2213
- options.hasDefinition = !!moduleDefinition.define;
2214
- options.definition = moduleDefinition.define;
2122
+ // only configure this once
2123
+ module.startWithParentIsConfigured = true;
2124
+
2125
+ // add the module initializer config
2126
+ parentModule.addInitializer(function(options){
2127
+ if (module.startWithParent){
2128
+ module.start(options);
2129
+ }
2130
+ });
2215
2131
 
2216
- // grab the "startWithParent" attribute if one exists
2217
- if (moduleDefinition.hasOwnProperty("startWithParent")){
2218
- options.startWithParent = moduleDefinition.startWithParent;
2219
- }
2220
2132
  }
2221
2133
 
2222
- return options;
2223
2134
  }
2224
2135
  });
2225
2136
 
2226
2137
 
2138
+
2227
2139
  return Marionette;
2228
2140
  })(Backbone, _, $ || window.jQuery || window.Zepto || window.ender);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marionette-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc2
4
+ version: 1.0.0.rc3
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors: