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.
- data/vendor/assets/javascripts/backbone.marionette.js +240 -328
- metadata +1 -1
@@ -1,5 +1,5 @@
|
|
1
|
-
// Backbone.Marionette, v1.0.0-
|
2
|
-
// Copyright (c)
|
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.
|
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
|
-
//
|
458
|
-
|
326
|
+
// Grab a reference to the original listenTo
|
327
|
+
var listenTo = Backbone.Events.listenTo;
|
459
328
|
|
460
|
-
//
|
461
|
-
|
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
|
-
|
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
|
-
|
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.
|
501
|
+
view.listenTo(view, "show", function(){
|
612
502
|
handleShow(view);
|
613
503
|
});
|
614
504
|
|
615
|
-
view.
|
505
|
+
view.listenTo(view, "render", function(){
|
616
506
|
handleRender(view);
|
617
507
|
});
|
618
508
|
};
|
619
509
|
})();
|
620
510
|
|
621
511
|
|
622
|
-
//
|
623
|
-
//
|
624
|
-
//
|
625
|
-
//
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
//
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
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
|
-
|
647
|
-
|
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
|
-
//
|
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 `
|
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
|
-
|
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.
|
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.
|
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
|
-
|
707
|
-
|
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
|
-
|
634
|
+
functionCallback(target, entity, evt, methods);
|
716
635
|
} else {
|
717
|
-
|
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.
|
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.
|
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
|
-
|
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
|
1162
|
-
//
|
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
|
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.
|
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.
|
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
|
-
|
1270
|
+
_initialEvents: function(){
|
1322
1271
|
if (this.collection){
|
1323
|
-
this.
|
1324
|
-
this.
|
1325
|
-
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
//
|
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
|
-
|
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
|
-
|
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
|
-
|
1560
|
-
|
1502
|
+
this.children.each(function(child){
|
1503
|
+
this.removeChildView(child);
|
1504
|
+
}, this);
|
1505
|
+
|
1561
1506
|
// re-initialize to clean up after ourselves
|
1562
|
-
this.
|
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
|
-
|
1529
|
+
_initialEvents: function(){
|
1585
1530
|
if (this.collection){
|
1586
|
-
this.
|
1587
|
-
this.
|
1588
|
-
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
|
-
|
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
|
-
|
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.
|
1992
|
-
this.
|
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 /
|
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
|
-
|
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.
|
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
|
-
//
|
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
|
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
|
-
//
|
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
|
-
|
2135
|
-
|
2136
|
-
|
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
|
-
|
2142
|
-
|
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
|
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
|
-
|
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
|
-
|
2188
|
-
|
2189
|
-
var startWithParent
|
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
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
};
|
2094
|
+
if (_.isFunction(def)){
|
2095
|
+
// if a function is supplied for the module definition
|
2096
|
+
fn = def;
|
2097
|
+
startWithParent = true;
|
2199
2098
|
|
2200
|
-
|
2201
|
-
|
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
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2109
|
+
// add module definition if needed
|
2110
|
+
if (fn){
|
2111
|
+
module.addDefinition(fn, args);
|
2112
|
+
}
|
2207
2113
|
|
2208
|
-
|
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
|
-
|
2119
|
+
// setup auto-start if needed
|
2120
|
+
if (module.startWithParent && !module.startWithParentIsConfigured){
|
2211
2121
|
|
2212
|
-
//
|
2213
|
-
|
2214
|
-
|
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);
|