marionette-rails 1.0.0.rc2 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: