marionette-rails 2.2.2 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6785ca4329e92cfb675a34ca251fd978c57e1e3
|
4
|
+
data.tar.gz: 0627a47da1f8b06cd8bb2316026ffcaaafcee58a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a63dbf909602bd5a283f5a4d622a9bfac2afa98aa4a78061216bfd14db9bafb4bbd267c75f8b2d29143ec6c83f8cedcdf5ca0431f235862487f0e55fae20628
|
7
|
+
data.tar.gz: 9a0560029ac2986b4a181ddc08cdca6043dbfed7864b518f5b53aca3d75d506058895cd5e723a4a37319ef688bf40e0b6954dd80b43fa2712479328e8ac6f069
|
@@ -1,8 +1,8 @@
|
|
1
1
|
// MarionetteJS (Backbone.Marionette)
|
2
2
|
// ----------------------------------
|
3
|
-
// v2.
|
3
|
+
// v2.3.2
|
4
4
|
//
|
5
|
-
// Copyright (c)
|
5
|
+
// Copyright (c)2015 Derick Bailey, Muted Solutions, LLC.
|
6
6
|
// Distributed under MIT license
|
7
7
|
//
|
8
8
|
// http://marionettejs.com
|
@@ -22,14 +22,14 @@
|
|
22
22
|
/* istanbul ignore next */
|
23
23
|
if (typeof define === 'function' && define.amd) {
|
24
24
|
define(['backbone', 'underscore'], function(Backbone, _) {
|
25
|
-
return (root.Marionette = factory(root, Backbone, _));
|
25
|
+
return (root.Marionette = root.Mn = factory(root, Backbone, _));
|
26
26
|
});
|
27
27
|
} else if (typeof exports !== 'undefined') {
|
28
28
|
var Backbone = require('backbone');
|
29
29
|
var _ = require('underscore');
|
30
30
|
module.exports = factory(root, Backbone, _);
|
31
31
|
} else {
|
32
|
-
root.Marionette = factory(root, root.Backbone, root._);
|
32
|
+
root.Marionette = root.Mn = factory(root, root.Backbone, root._);
|
33
33
|
}
|
34
34
|
|
35
35
|
}(this, function(root, Backbone, _) {
|
@@ -38,7 +38,7 @@
|
|
38
38
|
/* istanbul ignore next */
|
39
39
|
// Backbone.BabySitter
|
40
40
|
// -------------------
|
41
|
-
// v0.1.
|
41
|
+
// v0.1.5
|
42
42
|
//
|
43
43
|
// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
|
44
44
|
// Distributed under MIT license
|
@@ -167,7 +167,7 @@
|
|
167
167
|
// return the public API
|
168
168
|
return Container;
|
169
169
|
}(Backbone, _);
|
170
|
-
Backbone.ChildViewContainer.VERSION = "0.1.
|
170
|
+
Backbone.ChildViewContainer.VERSION = "0.1.5";
|
171
171
|
Backbone.ChildViewContainer.noConflict = function() {
|
172
172
|
Backbone.ChildViewContainer = previousChildViewContainer;
|
173
173
|
return this;
|
@@ -493,7 +493,7 @@
|
|
493
493
|
|
494
494
|
var Marionette = Backbone.Marionette = {};
|
495
495
|
|
496
|
-
Marionette.VERSION = '2.
|
496
|
+
Marionette.VERSION = '2.3.2';
|
497
497
|
|
498
498
|
Marionette.noConflict = function() {
|
499
499
|
root.Marionette = previousMarionette;
|
@@ -505,20 +505,26 @@
|
|
505
505
|
// Get the Deferred creator for later use
|
506
506
|
Marionette.Deferred = Backbone.$.Deferred;
|
507
507
|
|
508
|
-
/* jshint unused: false */
|
508
|
+
/* jshint unused: false *//* global console */
|
509
509
|
|
510
510
|
// Helpers
|
511
511
|
// -------
|
512
512
|
|
513
|
-
// For slicing `arguments` in functions
|
514
|
-
var slice = Array.prototype.slice;
|
515
|
-
|
516
513
|
// Marionette.extend
|
517
514
|
// -----------------
|
518
515
|
|
519
516
|
// Borrow the Backbone `extend` method so we can use it as needed
|
520
517
|
Marionette.extend = Backbone.Model.extend;
|
521
518
|
|
519
|
+
// Marionette.isNodeAttached
|
520
|
+
// -------------------------
|
521
|
+
|
522
|
+
// Determine if `el` is a child of the document
|
523
|
+
Marionette.isNodeAttached = function(el) {
|
524
|
+
return Backbone.$.contains(document.documentElement, el);
|
525
|
+
};
|
526
|
+
|
527
|
+
|
522
528
|
// Marionette.getOption
|
523
529
|
// --------------------
|
524
530
|
|
@@ -526,15 +532,11 @@
|
|
526
532
|
// object or its `options`, with `options` taking precedence.
|
527
533
|
Marionette.getOption = function(target, optionName) {
|
528
534
|
if (!target || !optionName) { return; }
|
529
|
-
var value;
|
530
|
-
|
531
535
|
if (target.options && (target.options[optionName] !== undefined)) {
|
532
|
-
|
536
|
+
return target.options[optionName];
|
533
537
|
} else {
|
534
|
-
|
538
|
+
return target[optionName];
|
535
539
|
}
|
536
|
-
|
537
|
-
return value;
|
538
540
|
};
|
539
541
|
|
540
542
|
// Proxy `Marionette.getOption`
|
@@ -542,23 +544,36 @@
|
|
542
544
|
return Marionette.getOption(this, optionName);
|
543
545
|
};
|
544
546
|
|
547
|
+
// Similar to `_.result`, this is a simple helper
|
548
|
+
// If a function is provided we call it with context
|
549
|
+
// otherwise just return the value. If the value is
|
550
|
+
// undefined return a default value
|
551
|
+
Marionette._getValue = function(value, context, params) {
|
552
|
+
if (_.isFunction(value)) {
|
553
|
+
// We need to ensure that params is not undefined
|
554
|
+
// to prevent `apply` from failing in ie8
|
555
|
+
params = params || [];
|
556
|
+
|
557
|
+
value = value.apply(context, params);
|
558
|
+
}
|
559
|
+
return value;
|
560
|
+
};
|
561
|
+
|
545
562
|
// Marionette.normalizeMethods
|
546
563
|
// ----------------------
|
547
564
|
|
548
565
|
// Pass in a mapping of events => functions or function names
|
549
566
|
// and return a mapping of events => functions
|
550
567
|
Marionette.normalizeMethods = function(hash) {
|
551
|
-
|
552
|
-
_.each(hash, function(method, name) {
|
568
|
+
return _.reduce(hash, function(normalizedHash, method, name) {
|
553
569
|
if (!_.isFunction(method)) {
|
554
570
|
method = this[method];
|
555
571
|
}
|
556
|
-
if (
|
557
|
-
|
572
|
+
if (method) {
|
573
|
+
normalizedHash[name] = method;
|
558
574
|
}
|
559
|
-
normalizedHash
|
560
|
-
}, this);
|
561
|
-
return normalizedHash;
|
575
|
+
return normalizedHash;
|
576
|
+
}, {}, this);
|
562
577
|
};
|
563
578
|
|
564
579
|
// utility method for parsing @ui. syntax strings
|
@@ -574,37 +589,22 @@
|
|
574
589
|
// swaps the @ui with the associated selector.
|
575
590
|
// Returns a new, non-mutated, parsed events hash.
|
576
591
|
Marionette.normalizeUIKeys = function(hash, ui) {
|
577
|
-
|
578
|
-
return;
|
579
|
-
}
|
580
|
-
|
581
|
-
hash = _.clone(hash);
|
582
|
-
|
583
|
-
_.each(_.keys(hash), function(key) {
|
592
|
+
return _.reduce(hash, function(memo, val, key) {
|
584
593
|
var normalizedKey = Marionette.normalizeUIString(key, ui);
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
}
|
589
|
-
});
|
590
|
-
|
591
|
-
return hash;
|
594
|
+
memo[normalizedKey] = val;
|
595
|
+
return memo;
|
596
|
+
}, {});
|
592
597
|
};
|
593
598
|
|
594
599
|
// allows for the use of the @ui. syntax within
|
595
600
|
// a given value for regions
|
596
601
|
// swaps the @ui with the associated selector
|
597
602
|
Marionette.normalizeUIValues = function(hash, ui) {
|
598
|
-
if (typeof(hash) === 'undefined') {
|
599
|
-
return;
|
600
|
-
}
|
601
|
-
|
602
603
|
_.each(hash, function(val, key) {
|
603
604
|
if (_.isString(val)) {
|
604
605
|
hash[key] = Marionette.normalizeUIString(val, ui);
|
605
606
|
}
|
606
607
|
});
|
607
|
-
|
608
608
|
return hash;
|
609
609
|
};
|
610
610
|
|
@@ -627,15 +627,31 @@
|
|
627
627
|
});
|
628
628
|
};
|
629
629
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
630
|
+
var deprecate = Marionette.deprecate = function(message, test) {
|
631
|
+
if (_.isObject(message)) {
|
632
|
+
message = (
|
633
|
+
message.prev + ' is going to be removed in the future. ' +
|
634
|
+
'Please use ' + message.next + ' instead.' +
|
635
|
+
(message.url ? ' See: ' + message.url : '')
|
636
|
+
);
|
637
|
+
}
|
638
|
+
|
639
|
+
if ((test === undefined || !test) && !deprecate._cache[message]) {
|
640
|
+
deprecate._warn('Deprecation warning: ' + message);
|
641
|
+
deprecate._cache[message] = true;
|
642
|
+
}
|
643
|
+
};
|
644
|
+
|
645
|
+
deprecate._warn = typeof console !== 'undefined' && (console.warn || console.log) || function() {};
|
646
|
+
deprecate._cache = {};
|
638
647
|
|
648
|
+
/* jshint maxstatements: 14, maxcomplexity: 7 */
|
649
|
+
|
650
|
+
// Trigger Method
|
651
|
+
// --------------
|
652
|
+
|
653
|
+
|
654
|
+
Marionette._triggerMethod = (function() {
|
639
655
|
// split the event name on the ":"
|
640
656
|
var splitter = /(^|:)(\w)/gi;
|
641
657
|
|
@@ -645,102 +661,109 @@
|
|
645
661
|
return eventName.toUpperCase();
|
646
662
|
}
|
647
663
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
664
|
+
return function(context, event, args) {
|
665
|
+
var noEventArg = arguments.length < 3;
|
666
|
+
if (noEventArg) {
|
667
|
+
args = event;
|
668
|
+
event = args[0];
|
669
|
+
}
|
652
670
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
result
|
657
|
-
}
|
671
|
+
// get the method name from the event name
|
672
|
+
var methodName = 'on' + event.replace(splitter, getEventName);
|
673
|
+
var method = context[methodName];
|
674
|
+
var result;
|
658
675
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
676
|
+
// call the onMethodName if it exists
|
677
|
+
if (_.isFunction(method)) {
|
678
|
+
// pass all args, except the event name
|
679
|
+
result = method.apply(context, noEventArg ? _.rest(args) : args);
|
680
|
+
}
|
681
|
+
|
682
|
+
// trigger the event, if a trigger method exists
|
683
|
+
if (_.isFunction(context.trigger)) {
|
684
|
+
if (noEventArg + args.length > 1) {
|
685
|
+
context.trigger.apply(context, noEventArg ? args : [event].concat(_.rest(args, 0)));
|
686
|
+
} else {
|
687
|
+
context.trigger(event);
|
688
|
+
}
|
689
|
+
}
|
690
|
+
|
691
|
+
return result;
|
692
|
+
};
|
693
|
+
})();
|
663
694
|
|
664
|
-
|
695
|
+
// Trigger an event and/or a corresponding method name. Examples:
|
696
|
+
//
|
697
|
+
// `this.triggerMethod("foo")` will trigger the "foo" event and
|
698
|
+
// call the "onFoo" method.
|
699
|
+
//
|
700
|
+
// `this.triggerMethod("foo:bar")` will trigger the "foo:bar" event and
|
701
|
+
// call the "onFooBar" method.
|
702
|
+
Marionette.triggerMethod = function(event) {
|
703
|
+
return Marionette._triggerMethod(this, arguments);
|
665
704
|
};
|
666
705
|
|
667
706
|
// triggerMethodOn invokes triggerMethod on a specific context
|
668
707
|
//
|
669
708
|
// e.g. `Marionette.triggerMethodOn(view, 'show')`
|
670
709
|
// will trigger a "show" event or invoke onShow the view.
|
671
|
-
Marionette.triggerMethodOn = function(context
|
672
|
-
var
|
673
|
-
|
674
|
-
|
675
|
-
if (_.isFunction(context.triggerMethod)) {
|
676
|
-
fnc = context.triggerMethod;
|
677
|
-
} else {
|
678
|
-
fnc = Marionette.triggerMethod;
|
679
|
-
}
|
710
|
+
Marionette.triggerMethodOn = function(context) {
|
711
|
+
var fnc = _.isFunction(context.triggerMethod) ?
|
712
|
+
context.triggerMethod :
|
713
|
+
Marionette.triggerMethod;
|
680
714
|
|
681
|
-
return fnc.apply(context,
|
715
|
+
return fnc.apply(context, _.rest(arguments));
|
682
716
|
};
|
683
717
|
|
684
|
-
//
|
685
|
-
//
|
686
|
-
|
718
|
+
// DOM Refresh
|
719
|
+
// -----------
|
720
|
+
|
687
721
|
// Monitor a view's state, and after it has been rendered and shown
|
688
722
|
// in the DOM, trigger a "dom:refresh" event every time it is
|
689
723
|
// re-rendered.
|
690
724
|
|
691
|
-
Marionette.MonitorDOMRefresh =
|
725
|
+
Marionette.MonitorDOMRefresh = function(view) {
|
726
|
+
|
692
727
|
// track when the view has been shown in the DOM,
|
693
728
|
// using a Marionette.Region (or by other means of triggering "show")
|
694
|
-
function handleShow(
|
729
|
+
function handleShow() {
|
695
730
|
view._isShown = true;
|
696
|
-
triggerDOMRefresh(
|
731
|
+
triggerDOMRefresh();
|
697
732
|
}
|
698
733
|
|
699
734
|
// track when the view has been rendered
|
700
|
-
function handleRender(
|
735
|
+
function handleRender() {
|
701
736
|
view._isRendered = true;
|
702
|
-
triggerDOMRefresh(
|
737
|
+
triggerDOMRefresh();
|
703
738
|
}
|
704
739
|
|
705
740
|
// Trigger the "dom:refresh" event and corresponding "onDomRefresh" method
|
706
|
-
function triggerDOMRefresh(
|
707
|
-
if (view._isShown && view._isRendered &&
|
741
|
+
function triggerDOMRefresh() {
|
742
|
+
if (view._isShown && view._isRendered && Marionette.isNodeAttached(view.el)) {
|
708
743
|
if (_.isFunction(view.triggerMethod)) {
|
709
744
|
view.triggerMethod('dom:refresh');
|
710
745
|
}
|
711
746
|
}
|
712
747
|
}
|
713
748
|
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
return function(view) {
|
720
|
-
view.listenTo(view, 'show', function() {
|
721
|
-
handleShow(view);
|
722
|
-
});
|
723
|
-
|
724
|
-
view.listenTo(view, 'render', function() {
|
725
|
-
handleRender(view);
|
726
|
-
});
|
727
|
-
};
|
728
|
-
})(document.documentElement);
|
749
|
+
view.on({
|
750
|
+
show: handleShow,
|
751
|
+
render: handleRender
|
752
|
+
});
|
753
|
+
};
|
729
754
|
|
730
|
-
|
731
755
|
/* jshint maxparams: 5 */
|
732
756
|
|
733
|
-
//
|
734
|
-
//
|
757
|
+
// Bind Entity Events & Unbind Entity Events
|
758
|
+
// -----------------------------------------
|
735
759
|
//
|
736
|
-
// These methods are used to bind/unbind a backbone "entity" (collection/model)
|
760
|
+
// These methods are used to bind/unbind a backbone "entity" (e.g. collection/model)
|
737
761
|
// to methods on a target object.
|
738
762
|
//
|
739
|
-
// The first parameter, `target`, must have
|
740
|
-
// EventBinder object.
|
763
|
+
// The first parameter, `target`, must have the Backbone.Events module mixed in.
|
741
764
|
//
|
742
|
-
// The second parameter is the entity (Backbone.Model
|
743
|
-
// to bind the events from.
|
765
|
+
// The second parameter is the `entity` (Backbone.Model, Backbone.Collection or
|
766
|
+
// any object that has Backbone.Events mixed in) to bind the events from.
|
744
767
|
//
|
745
768
|
// The third parameter is a hash of { "event:name": "eventHandler" }
|
746
769
|
// configuration. Multiple handlers can be separated by a space. A
|
@@ -793,7 +816,7 @@
|
|
793
816
|
if (!entity || !bindings) { return; }
|
794
817
|
|
795
818
|
// type-check bindings
|
796
|
-
if (!_.
|
819
|
+
if (!_.isObject(bindings)) {
|
797
820
|
throw new Marionette.Error({
|
798
821
|
message: 'Bindings must be an object or function.',
|
799
822
|
url: 'marionette.functions.html#marionettebindentityevents'
|
@@ -801,9 +824,7 @@
|
|
801
824
|
}
|
802
825
|
|
803
826
|
// allow the bindings to be a function
|
804
|
-
|
805
|
-
bindings = bindings.call(target);
|
806
|
-
}
|
827
|
+
bindings = Marionette._getValue(bindings, target);
|
807
828
|
|
808
829
|
// iterate the bindings and bind them
|
809
830
|
_.each(bindings, function(methods, evt) {
|
@@ -840,6 +861,9 @@
|
|
840
861
|
})(Marionette);
|
841
862
|
|
842
863
|
|
864
|
+
// Error
|
865
|
+
// -----
|
866
|
+
|
843
867
|
var errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number'];
|
844
868
|
|
845
869
|
Marionette.Error = Marionette.extend.call(Error, {
|
@@ -926,9 +950,9 @@
|
|
926
950
|
}
|
927
951
|
});
|
928
952
|
|
929
|
-
//
|
930
|
-
//
|
931
|
-
|
953
|
+
// Controller
|
954
|
+
// ----------
|
955
|
+
|
932
956
|
// A multi-purpose object to use as a controller for
|
933
957
|
// modules and routers, and as a mediator for workflow
|
934
958
|
// and coordination of other objects, views, and more.
|
@@ -948,9 +972,8 @@
|
|
948
972
|
// Ensure it can trigger events with Backbone.Events
|
949
973
|
_.extend(Marionette.Controller.prototype, Backbone.Events, {
|
950
974
|
destroy: function() {
|
951
|
-
|
952
|
-
|
953
|
-
this.triggerMethod.apply(this, ['destroy'].concat(args));
|
975
|
+
Marionette._triggerMethod(this, 'before:destroy', arguments);
|
976
|
+
Marionette._triggerMethod(this, 'destroy', arguments);
|
954
977
|
|
955
978
|
this.stopListening();
|
956
979
|
this.off();
|
@@ -966,9 +989,9 @@
|
|
966
989
|
|
967
990
|
});
|
968
991
|
|
969
|
-
//
|
970
|
-
//
|
971
|
-
|
992
|
+
// Object
|
993
|
+
// ------
|
994
|
+
|
972
995
|
// A Base Class that other Classes should descend from.
|
973
996
|
// Object borrows many conventions and utilities from Backbone.
|
974
997
|
Marionette.Object = function(options) {
|
@@ -982,7 +1005,8 @@
|
|
982
1005
|
// Object Methods
|
983
1006
|
// --------------
|
984
1007
|
|
985
|
-
|
1008
|
+
// Ensure it can trigger events with Backbone.Events
|
1009
|
+
_.extend(Marionette.Object.prototype, Backbone.Events, {
|
986
1010
|
|
987
1011
|
//this is a noop method intended to be overridden by classes that extend from this base
|
988
1012
|
initialize: function() {},
|
@@ -1000,138 +1024,43 @@
|
|
1000
1024
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1001
1025
|
getOption: Marionette.proxyGetOption,
|
1002
1026
|
|
1003
|
-
// Proxy `
|
1027
|
+
// Proxy `bindEntityEvents` to enable binding view's events from another entity.
|
1004
1028
|
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
1005
1029
|
|
1006
1030
|
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
|
1007
1031
|
unbindEntityEvents: Marionette.proxyUnbindEntityEvents
|
1008
1032
|
});
|
1009
1033
|
|
1010
|
-
|
1011
|
-
_.extend(Marionette.Object.prototype, Backbone.Events);
|
1012
|
-
|
1013
|
-
/* jshint maxcomplexity: 10, maxstatements: 29 */
|
1034
|
+
/* jshint maxcomplexity: 16, maxstatements: 45, maxlen: 120 */
|
1014
1035
|
|
1015
1036
|
// Region
|
1016
1037
|
// ------
|
1017
|
-
|
1038
|
+
|
1018
1039
|
// Manage the visual regions of your composite application. See
|
1019
1040
|
// http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
|
1020
1041
|
|
1021
|
-
Marionette.Region =
|
1022
|
-
|
1023
|
-
this.el = this.getOption('el');
|
1024
|
-
|
1025
|
-
// Handle when this.el is passed in as a $ wrapped element.
|
1026
|
-
this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;
|
1027
|
-
|
1028
|
-
if (!this.el) {
|
1029
|
-
throw new Marionette.Error({
|
1030
|
-
name: 'NoElError',
|
1031
|
-
message: 'An "el" must be specified for a region.'
|
1032
|
-
});
|
1033
|
-
}
|
1034
|
-
|
1035
|
-
this.$el = this.getEl(this.el);
|
1036
|
-
|
1037
|
-
if (this.initialize) {
|
1038
|
-
var args = slice.apply(arguments);
|
1039
|
-
this.initialize.apply(this, args);
|
1040
|
-
}
|
1041
|
-
};
|
1042
|
-
|
1043
|
-
|
1044
|
-
// Region Class methods
|
1045
|
-
// -------------------
|
1046
|
-
|
1047
|
-
_.extend(Marionette.Region, {
|
1042
|
+
Marionette.Region = Marionette.Object.extend({
|
1043
|
+
constructor: function (options) {
|
1048
1044
|
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
// a Region class directly, or an object literal that specifies both
|
1054
|
-
// a selector and regionClass:
|
1055
|
-
//
|
1056
|
-
// ```js
|
1057
|
-
// {
|
1058
|
-
// selector: "#foo",
|
1059
|
-
// regionClass: MyCustomRegion
|
1060
|
-
// }
|
1061
|
-
// ```
|
1062
|
-
//
|
1063
|
-
buildRegion: function(regionConfig, DefaultRegionClass) {
|
1064
|
-
if (_.isString(regionConfig)) {
|
1065
|
-
return this._buildRegionFromSelector(regionConfig, DefaultRegionClass);
|
1066
|
-
}
|
1067
|
-
|
1068
|
-
if (regionConfig.selector || regionConfig.el || regionConfig.regionClass) {
|
1069
|
-
return this._buildRegionFromObject(regionConfig, DefaultRegionClass);
|
1070
|
-
}
|
1071
|
-
|
1072
|
-
if (_.isFunction(regionConfig)) {
|
1073
|
-
return this._buildRegionFromRegionClass(regionConfig);
|
1074
|
-
}
|
1075
|
-
|
1076
|
-
throw new Marionette.Error({
|
1077
|
-
message: 'Improper region configuration type.',
|
1078
|
-
url: 'marionette.region.html#region-configuration-types'
|
1079
|
-
});
|
1080
|
-
},
|
1081
|
-
|
1082
|
-
// Build the region from a string selector like '#foo-region'
|
1083
|
-
_buildRegionFromSelector: function(selector, DefaultRegionClass) {
|
1084
|
-
return new DefaultRegionClass({ el: selector });
|
1085
|
-
},
|
1086
|
-
|
1087
|
-
// Build the region from a configuration object
|
1088
|
-
// ```js
|
1089
|
-
// { selector: '#foo', regionClass: FooRegion }
|
1090
|
-
// ```
|
1091
|
-
_buildRegionFromObject: function(regionConfig, DefaultRegionClass) {
|
1092
|
-
var RegionClass = regionConfig.regionClass || DefaultRegionClass;
|
1093
|
-
var options = _.omit(regionConfig, 'selector', 'regionClass');
|
1094
|
-
|
1095
|
-
if (regionConfig.selector && !options.el) {
|
1096
|
-
options.el = regionConfig.selector;
|
1097
|
-
}
|
1045
|
+
// set options temporarily so that we can get `el`.
|
1046
|
+
// options will be overriden by Object.constructor
|
1047
|
+
this.options = options || {};
|
1048
|
+
this.el = this.getOption('el');
|
1098
1049
|
|
1099
|
-
|
1050
|
+
// Handle when this.el is passed in as a $ wrapped element.
|
1051
|
+
this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;
|
1100
1052
|
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
// guaranteed to be in the DOM already, and will cause problems
|
1107
|
-
if (regionConfig.parentEl) {
|
1108
|
-
region.getEl = function(el) {
|
1109
|
-
if (_.isObject(el)) {
|
1110
|
-
return Backbone.$(el);
|
1111
|
-
}
|
1112
|
-
var parentEl = regionConfig.parentEl;
|
1113
|
-
if (_.isFunction(parentEl)) {
|
1114
|
-
parentEl = parentEl();
|
1115
|
-
}
|
1116
|
-
return parentEl.find(el);
|
1117
|
-
};
|
1053
|
+
if (!this.el) {
|
1054
|
+
throw new Marionette.Error({
|
1055
|
+
name: 'NoElError',
|
1056
|
+
message: 'An "el" must be specified for a region.'
|
1057
|
+
});
|
1118
1058
|
}
|
1119
1059
|
|
1120
|
-
|
1060
|
+
this.$el = this.getEl(this.el);
|
1061
|
+
Marionette.Object.call(this, options);
|
1121
1062
|
},
|
1122
1063
|
|
1123
|
-
// Build the region directly from a given `RegionClass`
|
1124
|
-
_buildRegionFromRegionClass: function(RegionClass) {
|
1125
|
-
return new RegionClass();
|
1126
|
-
}
|
1127
|
-
|
1128
|
-
});
|
1129
|
-
|
1130
|
-
// Region Instance Methods
|
1131
|
-
// -----------------------
|
1132
|
-
|
1133
|
-
_.extend(Marionette.Region.prototype, Backbone.Events, {
|
1134
|
-
|
1135
1064
|
// Displays a backbone view instance inside of the region.
|
1136
1065
|
// Handles calling the `render` method for you. Reads content
|
1137
1066
|
// directly from the `el` attribute. Also calls an optional
|
@@ -1141,9 +1070,12 @@
|
|
1141
1070
|
// the old view being destroyed on show.
|
1142
1071
|
// The `forceShow` option can be used to force a view to be
|
1143
1072
|
// re-rendered if it's already shown in the region.
|
1144
|
-
|
1145
1073
|
show: function(view, options){
|
1146
|
-
this._ensureElement()
|
1074
|
+
if (!this._ensureElement()) {
|
1075
|
+
return;
|
1076
|
+
}
|
1077
|
+
|
1078
|
+
this._ensureViewIsIntact(view);
|
1147
1079
|
|
1148
1080
|
var showOptions = options || {};
|
1149
1081
|
var isDifferentView = view !== this.currentView;
|
@@ -1163,11 +1095,21 @@
|
|
1163
1095
|
var _shouldShowView = isDifferentView || forceShow;
|
1164
1096
|
|
1165
1097
|
if (isChangingView) {
|
1166
|
-
this.triggerMethod('before:swapOut', this.currentView);
|
1098
|
+
this.triggerMethod('before:swapOut', this.currentView, this, options);
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
if (this.currentView) {
|
1102
|
+
delete this.currentView._parent;
|
1167
1103
|
}
|
1168
1104
|
|
1169
1105
|
if (_shouldDestroyView) {
|
1170
1106
|
this.empty();
|
1107
|
+
|
1108
|
+
// A `destroy` event is attached to the clean up manually removed views.
|
1109
|
+
// We need to detach this event when a new view is going to be shown as it
|
1110
|
+
// is no longer relevant.
|
1111
|
+
} else if (isChangingView && _shouldShowView) {
|
1112
|
+
this.currentView.off('destroy', this.empty, this);
|
1171
1113
|
}
|
1172
1114
|
|
1173
1115
|
if (_shouldShowView) {
|
@@ -1180,27 +1122,49 @@
|
|
1180
1122
|
view.once('destroy', this.empty, this);
|
1181
1123
|
view.render();
|
1182
1124
|
|
1125
|
+
view._parent = this;
|
1126
|
+
|
1183
1127
|
if (isChangingView) {
|
1184
|
-
this.triggerMethod('before:swap', view);
|
1128
|
+
this.triggerMethod('before:swap', view, this, options);
|
1185
1129
|
}
|
1186
1130
|
|
1187
|
-
this.triggerMethod('before:show', view);
|
1188
|
-
Marionette.triggerMethodOn(view, 'before:show');
|
1189
|
-
|
1190
|
-
this.attachHtml(view);
|
1131
|
+
this.triggerMethod('before:show', view, this, options);
|
1132
|
+
Marionette.triggerMethodOn(view, 'before:show', view, this, options);
|
1191
1133
|
|
1192
1134
|
if (isChangingView) {
|
1193
|
-
this.triggerMethod('swapOut', this.currentView);
|
1135
|
+
this.triggerMethod('swapOut', this.currentView, this, options);
|
1194
1136
|
}
|
1195
1137
|
|
1138
|
+
// An array of views that we're about to display
|
1139
|
+
var attachedRegion = Marionette.isNodeAttached(this.el);
|
1140
|
+
|
1141
|
+
// The views that we're about to attach to the document
|
1142
|
+
// It's important that we prevent _getNestedViews from being executed unnecessarily
|
1143
|
+
// as it's a potentially-slow method
|
1144
|
+
var displayedViews = [];
|
1145
|
+
|
1146
|
+
var triggerBeforeAttach = showOptions.triggerBeforeAttach || this.triggerBeforeAttach;
|
1147
|
+
var triggerAttach = showOptions.triggerAttach || this.triggerAttach;
|
1148
|
+
|
1149
|
+
if (attachedRegion && triggerBeforeAttach) {
|
1150
|
+
displayedViews = this._displayedViews(view);
|
1151
|
+
this._triggerAttach(displayedViews, 'before:');
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
this.attachHtml(view);
|
1196
1155
|
this.currentView = view;
|
1197
1156
|
|
1157
|
+
if (attachedRegion && triggerAttach) {
|
1158
|
+
displayedViews = this._displayedViews(view);
|
1159
|
+
this._triggerAttach(displayedViews);
|
1160
|
+
}
|
1161
|
+
|
1198
1162
|
if (isChangingView) {
|
1199
|
-
this.triggerMethod('swap', view);
|
1163
|
+
this.triggerMethod('swap', view, this, options);
|
1200
1164
|
}
|
1201
1165
|
|
1202
|
-
this.triggerMethod('show', view);
|
1203
|
-
Marionette.triggerMethodOn(view, 'show');
|
1166
|
+
this.triggerMethod('show', view, this, options);
|
1167
|
+
Marionette.triggerMethodOn(view, 'show', view, this, options);
|
1204
1168
|
|
1205
1169
|
return this;
|
1206
1170
|
}
|
@@ -1208,6 +1172,20 @@
|
|
1208
1172
|
return this;
|
1209
1173
|
},
|
1210
1174
|
|
1175
|
+
triggerBeforeAttach: true,
|
1176
|
+
triggerAttach: true,
|
1177
|
+
|
1178
|
+
_triggerAttach: function(views, prefix) {
|
1179
|
+
var eventName = (prefix || '') + 'attach';
|
1180
|
+
_.each(views, function(view) {
|
1181
|
+
Marionette.triggerMethodOn(view, eventName, view, this);
|
1182
|
+
}, this);
|
1183
|
+
},
|
1184
|
+
|
1185
|
+
_displayedViews: function(view) {
|
1186
|
+
return _.union([view], _.result(view, '_getNestedViews') || []);
|
1187
|
+
},
|
1188
|
+
|
1211
1189
|
_ensureElement: function(){
|
1212
1190
|
if (!_.isObject(this.el)) {
|
1213
1191
|
this.$el = this.getEl(this.el);
|
@@ -1215,21 +1193,43 @@
|
|
1215
1193
|
}
|
1216
1194
|
|
1217
1195
|
if (!this.$el || this.$el.length === 0) {
|
1218
|
-
|
1196
|
+
if (this.getOption('allowMissingEl')) {
|
1197
|
+
return false;
|
1198
|
+
} else {
|
1199
|
+
throw new Marionette.Error('An "el" ' + this.$el.selector + ' must exist in DOM');
|
1200
|
+
}
|
1219
1201
|
}
|
1202
|
+
return true;
|
1220
1203
|
},
|
1221
1204
|
|
1222
|
-
|
1223
|
-
|
1205
|
+
_ensureViewIsIntact: function(view) {
|
1206
|
+
if (!view) {
|
1207
|
+
throw new Marionette.Error({
|
1208
|
+
name: 'ViewNotValid',
|
1209
|
+
message: 'The view passed is undefined and therefore invalid. You must pass a view instance to show.'
|
1210
|
+
});
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
if (view.isDestroyed) {
|
1214
|
+
throw new Marionette.Error({
|
1215
|
+
name: 'ViewDestroyedError',
|
1216
|
+
message: 'View (cid: "' + view.cid + '") has already been destroyed and cannot be used.'
|
1217
|
+
});
|
1218
|
+
}
|
1219
|
+
},
|
1220
|
+
|
1221
|
+
// Override this method to change how the region finds the DOM
|
1222
|
+
// element that it manages. Return a jQuery selector object scoped
|
1223
|
+
// to a provided parent el or the document if none exists.
|
1224
1224
|
getEl: function(el) {
|
1225
|
-
return Backbone.$(el);
|
1225
|
+
return Backbone.$(el, Marionette._getValue(this.options.parentEl, this));
|
1226
1226
|
},
|
1227
1227
|
|
1228
1228
|
// Override this method to change how the new view is
|
1229
1229
|
// appended to the `$el` that the region is managing
|
1230
1230
|
attachHtml: function(view) {
|
1231
|
-
|
1232
|
-
|
1231
|
+
this.$el.contents().detach();
|
1232
|
+
|
1233
1233
|
this.el.appendChild(view.el);
|
1234
1234
|
},
|
1235
1235
|
|
@@ -1261,6 +1261,10 @@
|
|
1261
1261
|
view.destroy();
|
1262
1262
|
} else if (view.remove) {
|
1263
1263
|
view.remove();
|
1264
|
+
|
1265
|
+
// appending isDestroyed to raw Backbone View allows regions
|
1266
|
+
// to throw a ViewDestroyedError for this view
|
1267
|
+
view.isDestroyed = true;
|
1264
1268
|
}
|
1265
1269
|
},
|
1266
1270
|
|
@@ -1293,152 +1297,196 @@
|
|
1293
1297
|
|
1294
1298
|
delete this.$el;
|
1295
1299
|
return this;
|
1296
|
-
}
|
1300
|
+
}
|
1297
1301
|
|
1298
|
-
|
1299
|
-
getOption: Marionette.proxyGetOption,
|
1302
|
+
},
|
1300
1303
|
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1304
|
+
// Static Methods
|
1305
|
+
{
|
1306
|
+
|
1307
|
+
// Build an instance of a region by passing in a configuration object
|
1308
|
+
// and a default region class to use if none is specified in the config.
|
1309
|
+
//
|
1310
|
+
// The config object should either be a string as a jQuery DOM selector,
|
1311
|
+
// a Region class directly, or an object literal that specifies a selector,
|
1312
|
+
// a custom regionClass, and any options to be supplied to the region:
|
1313
|
+
//
|
1314
|
+
// ```js
|
1315
|
+
// {
|
1316
|
+
// selector: "#foo",
|
1317
|
+
// regionClass: MyCustomRegion,
|
1318
|
+
// allowMissingEl: false
|
1319
|
+
// }
|
1320
|
+
// ```
|
1321
|
+
//
|
1322
|
+
buildRegion: function(regionConfig, DefaultRegionClass) {
|
1323
|
+
if (_.isString(regionConfig)) {
|
1324
|
+
return this._buildRegionFromSelector(regionConfig, DefaultRegionClass);
|
1325
|
+
}
|
1305
1326
|
|
1306
|
-
|
1307
|
-
|
1327
|
+
if (regionConfig.selector || regionConfig.el || regionConfig.regionClass) {
|
1328
|
+
return this._buildRegionFromObject(regionConfig, DefaultRegionClass);
|
1329
|
+
}
|
1308
1330
|
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
// Manage one or more related `Marionette.Region` objects.
|
1313
|
-
Marionette.RegionManager = (function(Marionette) {
|
1331
|
+
if (_.isFunction(regionConfig)) {
|
1332
|
+
return this._buildRegionFromRegionClass(regionConfig);
|
1333
|
+
}
|
1314
1334
|
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1335
|
+
throw new Marionette.Error({
|
1336
|
+
message: 'Improper region configuration type.',
|
1337
|
+
url: 'marionette.region.html#region-configuration-types'
|
1338
|
+
});
|
1339
|
+
},
|
1320
1340
|
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
addRegions: function(regionDefinitions, defaults) {
|
1326
|
-
if (_.isFunction(regionDefinitions)) {
|
1327
|
-
regionDefinitions = regionDefinitions.apply(this, arguments);
|
1328
|
-
}
|
1341
|
+
// Build the region from a string selector like '#foo-region'
|
1342
|
+
_buildRegionFromSelector: function(selector, DefaultRegionClass) {
|
1343
|
+
return new DefaultRegionClass({ el: selector });
|
1344
|
+
},
|
1329
1345
|
|
1330
|
-
|
1346
|
+
// Build the region from a configuration object
|
1347
|
+
// ```js
|
1348
|
+
// { selector: '#foo', regionClass: FooRegion, allowMissingEl: false }
|
1349
|
+
// ```
|
1350
|
+
_buildRegionFromObject: function(regionConfig, DefaultRegionClass) {
|
1351
|
+
var RegionClass = regionConfig.regionClass || DefaultRegionClass;
|
1352
|
+
var options = _.omit(regionConfig, 'selector', 'regionClass');
|
1331
1353
|
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
}
|
1354
|
+
if (regionConfig.selector && !options.el) {
|
1355
|
+
options.el = regionConfig.selector;
|
1356
|
+
}
|
1336
1357
|
|
1337
|
-
|
1338
|
-
|
1339
|
-
}
|
1358
|
+
return new RegionClass(options);
|
1359
|
+
},
|
1340
1360
|
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1361
|
+
// Build the region directly from a given `RegionClass`
|
1362
|
+
_buildRegionFromRegionClass: function(RegionClass) {
|
1363
|
+
return new RegionClass();
|
1364
|
+
}
|
1365
|
+
});
|
1344
1366
|
|
1345
|
-
|
1346
|
-
|
1367
|
+
// Region Manager
|
1368
|
+
// --------------
|
1347
1369
|
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1370
|
+
// Manage one or more related `Marionette.Region` objects.
|
1371
|
+
Marionette.RegionManager = Marionette.Controller.extend({
|
1372
|
+
constructor: function(options) {
|
1373
|
+
this._regions = {};
|
1352
1374
|
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1375
|
+
Marionette.Controller.call(this, options);
|
1376
|
+
|
1377
|
+
this.addRegions(this.getOption('regions'));
|
1378
|
+
},
|
1379
|
+
|
1380
|
+
// Add multiple regions using an object literal or a
|
1381
|
+
// function that returns an object literal, where
|
1382
|
+
// each key becomes the region name, and each value is
|
1383
|
+
// the region definition.
|
1384
|
+
addRegions: function(regionDefinitions, defaults) {
|
1385
|
+
regionDefinitions = Marionette._getValue(regionDefinitions, this, arguments);
|
1386
|
+
|
1387
|
+
return _.reduce(regionDefinitions, function(regions, definition, name) {
|
1388
|
+
if (_.isString(definition)) {
|
1389
|
+
definition = {selector: definition};
|
1390
|
+
}
|
1391
|
+
if (definition.selector) {
|
1392
|
+
definition = _.defaults({}, definition, defaults);
|
1357
1393
|
}
|
1358
1394
|
|
1359
|
-
this.
|
1395
|
+
regions[name] = this.addRegion(name, definition);
|
1396
|
+
return regions;
|
1397
|
+
}, {}, this);
|
1398
|
+
},
|
1360
1399
|
|
1361
|
-
|
1400
|
+
// Add an individual region to the region manager,
|
1401
|
+
// and return the region instance
|
1402
|
+
addRegion: function(name, definition) {
|
1403
|
+
var region;
|
1362
1404
|
|
1363
|
-
|
1364
|
-
|
1365
|
-
}
|
1405
|
+
if (definition instanceof Marionette.Region) {
|
1406
|
+
region = definition;
|
1407
|
+
} else {
|
1408
|
+
region = Marionette.Region.buildRegion(definition, Marionette.Region);
|
1409
|
+
}
|
1366
1410
|
|
1367
|
-
|
1368
|
-
get: function(name) {
|
1369
|
-
return this._regions[name];
|
1370
|
-
},
|
1411
|
+
this.triggerMethod('before:add:region', name, region);
|
1371
1412
|
|
1372
|
-
|
1373
|
-
|
1374
|
-
getRegions: function(){
|
1375
|
-
return _.clone(this._regions);
|
1376
|
-
},
|
1413
|
+
region._parent = this;
|
1414
|
+
this._store(name, region);
|
1377
1415
|
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
this._remove(name, region);
|
1416
|
+
this.triggerMethod('add:region', name, region);
|
1417
|
+
return region;
|
1418
|
+
},
|
1382
1419
|
|
1383
|
-
|
1384
|
-
|
1420
|
+
// Get a region by name
|
1421
|
+
get: function(name) {
|
1422
|
+
return this._regions[name];
|
1423
|
+
},
|
1385
1424
|
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
this._remove(name, region);
|
1392
|
-
}, this);
|
1425
|
+
// Gets all the regions contained within
|
1426
|
+
// the `regionManager` instance.
|
1427
|
+
getRegions: function(){
|
1428
|
+
return _.clone(this._regions);
|
1429
|
+
},
|
1393
1430
|
|
1394
|
-
|
1395
|
-
|
1431
|
+
// Remove a region by name
|
1432
|
+
removeRegion: function(name) {
|
1433
|
+
var region = this._regions[name];
|
1434
|
+
this._remove(name, region);
|
1396
1435
|
|
1397
|
-
|
1398
|
-
|
1399
|
-
emptyRegions: function() {
|
1400
|
-
var regions = this.getRegions();
|
1401
|
-
_.each(regions, function(region) {
|
1402
|
-
region.empty();
|
1403
|
-
}, this);
|
1436
|
+
return region;
|
1437
|
+
},
|
1404
1438
|
|
1405
|
-
|
1406
|
-
|
1439
|
+
// Empty all regions in the region manager, and
|
1440
|
+
// remove them
|
1441
|
+
removeRegions: function() {
|
1442
|
+
var regions = this.getRegions();
|
1443
|
+
_.each(this._regions, function(region, name) {
|
1444
|
+
this._remove(name, region);
|
1445
|
+
}, this);
|
1407
1446
|
|
1408
|
-
|
1409
|
-
|
1410
|
-
destroy: function() {
|
1411
|
-
this.removeRegions();
|
1412
|
-
return Marionette.Controller.prototype.destroy.apply(this, arguments);
|
1413
|
-
},
|
1447
|
+
return regions;
|
1448
|
+
},
|
1414
1449
|
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1450
|
+
// Empty all regions in the region manager, but
|
1451
|
+
// leave them attached
|
1452
|
+
emptyRegions: function() {
|
1453
|
+
var regions = this.getRegions();
|
1454
|
+
_.invoke(regions, 'empty');
|
1455
|
+
return regions;
|
1456
|
+
},
|
1420
1457
|
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
this._setLength();
|
1428
|
-
this.triggerMethod('remove:region', name, region);
|
1429
|
-
},
|
1458
|
+
// Destroy all regions and shut down the region
|
1459
|
+
// manager entirely
|
1460
|
+
destroy: function() {
|
1461
|
+
this.removeRegions();
|
1462
|
+
return Marionette.Controller.prototype.destroy.apply(this, arguments);
|
1463
|
+
},
|
1430
1464
|
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1465
|
+
// internal method to store regions
|
1466
|
+
_store: function(name, region) {
|
1467
|
+
this._regions[name] = region;
|
1468
|
+
this._setLength();
|
1469
|
+
},
|
1435
1470
|
|
1436
|
-
|
1471
|
+
// internal method to remove a region
|
1472
|
+
_remove: function(name, region) {
|
1473
|
+
this.triggerMethod('before:remove:region', name, region);
|
1474
|
+
region.empty();
|
1475
|
+
region.stopListening();
|
1437
1476
|
|
1438
|
-
|
1477
|
+
delete region._parent;
|
1478
|
+
delete this._regions[name];
|
1479
|
+
this._setLength();
|
1480
|
+
this.triggerMethod('remove:region', name, region);
|
1481
|
+
},
|
1439
1482
|
|
1440
|
-
|
1441
|
-
|
1483
|
+
// set the number of regions current held
|
1484
|
+
_setLength: function() {
|
1485
|
+
this.length = _.size(this._regions);
|
1486
|
+
}
|
1487
|
+
});
|
1488
|
+
|
1489
|
+
Marionette.actAsCollection(Marionette.RegionManager.prototype, '_regions');
|
1442
1490
|
|
1443
1491
|
|
1444
1492
|
// Template Cache
|
@@ -1479,7 +1527,7 @@
|
|
1479
1527
|
// `clear("#t1", "#t2", "...")`
|
1480
1528
|
clear: function() {
|
1481
1529
|
var i;
|
1482
|
-
var args =
|
1530
|
+
var args = _.toArray(arguments);
|
1483
1531
|
var length = args.length;
|
1484
1532
|
|
1485
1533
|
if (length > 0) {
|
@@ -1557,12 +1605,7 @@
|
|
1557
1605
|
});
|
1558
1606
|
}
|
1559
1607
|
|
1560
|
-
var templateFunc;
|
1561
|
-
if (typeof template === 'function') {
|
1562
|
-
templateFunc = template;
|
1563
|
-
} else {
|
1564
|
-
templateFunc = Marionette.TemplateCache.get(template);
|
1565
|
-
}
|
1608
|
+
var templateFunc = _.isFunction(template) ? template : Marionette.TemplateCache.get(template);
|
1566
1609
|
|
1567
1610
|
return templateFunc(data);
|
1568
1611
|
}
|
@@ -1570,27 +1613,30 @@
|
|
1570
1613
|
|
1571
1614
|
|
1572
1615
|
/* jshint maxlen: 114, nonew: false */
|
1573
|
-
//
|
1574
|
-
//
|
1616
|
+
// View
|
1617
|
+
// ----
|
1575
1618
|
|
1576
1619
|
// The core view class that other Marionette views extend from.
|
1577
1620
|
Marionette.View = Backbone.View.extend({
|
1621
|
+
isDestroyed: false,
|
1578
1622
|
|
1579
1623
|
constructor: function(options) {
|
1580
1624
|
_.bindAll(this, 'render');
|
1581
1625
|
|
1626
|
+
options = Marionette._getValue(options, this);
|
1627
|
+
|
1582
1628
|
// this exposes view options to the view initializer
|
1583
1629
|
// this is a backfill since backbone removed the assignment
|
1584
1630
|
// of this.options
|
1585
1631
|
// at some point however this may be removed
|
1586
|
-
this.options = _.extend({}, _.result(this, 'options'),
|
1632
|
+
this.options = _.extend({}, _.result(this, 'options'), options);
|
1587
1633
|
|
1588
1634
|
this._behaviors = Marionette.Behaviors(this);
|
1589
1635
|
|
1590
1636
|
Backbone.View.apply(this, arguments);
|
1591
1637
|
|
1592
1638
|
Marionette.MonitorDOMRefresh(this);
|
1593
|
-
this.
|
1639
|
+
this.on('show', this.onShowCalled);
|
1594
1640
|
},
|
1595
1641
|
|
1596
1642
|
// Get the template for this view
|
@@ -1604,7 +1650,7 @@
|
|
1604
1650
|
// Serialize a model by returning its attributes. Clones
|
1605
1651
|
// the attributes to allow modification.
|
1606
1652
|
serializeModel: function(model){
|
1607
|
-
return model.toJSON.apply(model,
|
1653
|
+
return model.toJSON.apply(model, _.rest(arguments));
|
1608
1654
|
},
|
1609
1655
|
|
1610
1656
|
// Mix in template helper methods. Looks for a
|
@@ -1615,18 +1661,15 @@
|
|
1615
1661
|
mixinTemplateHelpers: function(target) {
|
1616
1662
|
target = target || {};
|
1617
1663
|
var templateHelpers = this.getOption('templateHelpers');
|
1618
|
-
|
1619
|
-
templateHelpers = templateHelpers.call(this);
|
1620
|
-
}
|
1664
|
+
templateHelpers = Marionette._getValue(templateHelpers, this);
|
1621
1665
|
return _.extend(target, templateHelpers);
|
1622
1666
|
},
|
1623
1667
|
|
1624
1668
|
// normalize the keys of passed hash with the views `ui` selectors.
|
1625
1669
|
// `{"@ui.foo": "bar"}`
|
1626
1670
|
normalizeUIKeys: function(hash) {
|
1627
|
-
var ui = _.result(this, 'ui');
|
1628
1671
|
var uiBindings = _.result(this, '_uiBindings');
|
1629
|
-
return Marionette.normalizeUIKeys(hash, uiBindings || ui);
|
1672
|
+
return Marionette.normalizeUIKeys(hash, uiBindings || _.result(this, 'ui'));
|
1630
1673
|
},
|
1631
1674
|
|
1632
1675
|
// normalize the values of passed hash with the views `ui` selectors.
|
@@ -1642,18 +1685,15 @@
|
|
1642
1685
|
configureTriggers: function() {
|
1643
1686
|
if (!this.triggers) { return; }
|
1644
1687
|
|
1645
|
-
var triggerEvents = {};
|
1646
|
-
|
1647
1688
|
// Allow `triggers` to be configured as a function
|
1648
1689
|
var triggers = this.normalizeUIKeys(_.result(this, 'triggers'));
|
1649
1690
|
|
1650
1691
|
// Configure the triggers, prevent default
|
1651
1692
|
// action and stop propagation of DOM events
|
1652
|
-
_.
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
return triggerEvents;
|
1693
|
+
return _.reduce(triggers, function(events, value, key) {
|
1694
|
+
events[key] = this._buildViewTrigger(value);
|
1695
|
+
return events;
|
1696
|
+
}, {}, this);
|
1657
1697
|
},
|
1658
1698
|
|
1659
1699
|
// Overriding Backbone.View's delegateEvents to handle
|
@@ -1673,8 +1713,7 @@
|
|
1673
1713
|
|
1674
1714
|
// internal method to delegate DOM events and triggers
|
1675
1715
|
_delegateDOMEvents: function(eventsArg) {
|
1676
|
-
var events = eventsArg || this.events;
|
1677
|
-
if (_.isFunction(events)) { events = events.call(this); }
|
1716
|
+
var events = Marionette._getValue(eventsArg || this.events, this);
|
1678
1717
|
|
1679
1718
|
// normalize ui keys
|
1680
1719
|
events = this.normalizeUIKeys(events);
|
@@ -1696,8 +1735,7 @@
|
|
1696
1735
|
// Overriding Backbone.View's undelegateEvents to handle unbinding
|
1697
1736
|
// the `triggers`, `modelEvents`, and `collectionEvents` config
|
1698
1737
|
undelegateEvents: function() {
|
1699
|
-
|
1700
|
-
Backbone.View.prototype.undelegateEvents.apply(this, args);
|
1738
|
+
Backbone.View.prototype.undelegateEvents.apply(this, arguments);
|
1701
1739
|
|
1702
1740
|
this.unbindEntityEvents(this.model, this.getOption('modelEvents'));
|
1703
1741
|
this.unbindEntityEvents(this.collection, this.getOption('collectionEvents'));
|
@@ -1730,7 +1768,7 @@
|
|
1730
1768
|
destroy: function() {
|
1731
1769
|
if (this.isDestroyed) { return; }
|
1732
1770
|
|
1733
|
-
var args =
|
1771
|
+
var args = _.toArray(arguments);
|
1734
1772
|
|
1735
1773
|
this.triggerMethod.apply(this, ['before:destroy'].concat(args));
|
1736
1774
|
|
@@ -1778,8 +1816,7 @@
|
|
1778
1816
|
this.ui = {};
|
1779
1817
|
|
1780
1818
|
// bind each of the selectors
|
1781
|
-
_.each(
|
1782
|
-
var selector = bindings[key];
|
1819
|
+
_.each(bindings, function(selector, key) {
|
1783
1820
|
this.ui[key] = this.$(selector);
|
1784
1821
|
}, this);
|
1785
1822
|
},
|
@@ -1850,17 +1887,35 @@
|
|
1850
1887
|
// import the `triggerMethod` to trigger events with corresponding
|
1851
1888
|
// methods if the method exists
|
1852
1889
|
triggerMethod: function() {
|
1853
|
-
var
|
1854
|
-
var
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
triggerMethod
|
1859
|
-
}
|
1890
|
+
var triggerMethod = Marionette._triggerMethod;
|
1891
|
+
var ret = triggerMethod(this, arguments);
|
1892
|
+
var behaviors = this._behaviors;
|
1893
|
+
// Use good ol' for as this is a very hot function
|
1894
|
+
for (var i = 0, length = behaviors && behaviors.length; i < length; i++) {
|
1895
|
+
triggerMethod(behaviors[i], arguments);
|
1896
|
+
}
|
1860
1897
|
|
1861
1898
|
return ret;
|
1862
1899
|
},
|
1863
1900
|
|
1901
|
+
// This method returns any views that are immediate
|
1902
|
+
// children of this view
|
1903
|
+
_getImmediateChildren: function() {
|
1904
|
+
return [];
|
1905
|
+
},
|
1906
|
+
|
1907
|
+
// Returns an array of every nested view within this view
|
1908
|
+
_getNestedViews: function() {
|
1909
|
+
var children = this._getImmediateChildren();
|
1910
|
+
|
1911
|
+
if (!children.length) { return children; }
|
1912
|
+
|
1913
|
+
return _.reduce(children, function(memo, view) {
|
1914
|
+
if (!view._getNestedViews) { return memo; }
|
1915
|
+
return memo.concat(view._getNestedViews());
|
1916
|
+
}, children);
|
1917
|
+
},
|
1918
|
+
|
1864
1919
|
// Imports the "normalizeMethods" to transform hashes of
|
1865
1920
|
// events=>function references/names to a hash of events=>function references
|
1866
1921
|
normalizeMethods: Marionette.normalizeMethods,
|
@@ -1868,7 +1923,7 @@
|
|
1868
1923
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1869
1924
|
getOption: Marionette.proxyGetOption,
|
1870
1925
|
|
1871
|
-
// Proxy `
|
1926
|
+
// Proxy `bindEntityEvents` to enable binding view's events from another entity.
|
1872
1927
|
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
1873
1928
|
|
1874
1929
|
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
|
@@ -1897,21 +1952,27 @@
|
|
1897
1952
|
// You can override the `serializeData` method in your own view definition,
|
1898
1953
|
// to provide custom serialization for your view's data.
|
1899
1954
|
serializeData: function(){
|
1900
|
-
|
1901
|
-
|
1902
|
-
if (this.model) {
|
1903
|
-
data = _.partial(this.serializeModel, this.model).apply(this, arguments);
|
1955
|
+
if (!this.model && !this.collection) {
|
1956
|
+
return {};
|
1904
1957
|
}
|
1905
|
-
|
1906
|
-
|
1958
|
+
|
1959
|
+
var args = [this.model || this.collection];
|
1960
|
+
if (arguments.length) {
|
1961
|
+
args.push.apply(args, arguments);
|
1907
1962
|
}
|
1908
1963
|
|
1909
|
-
|
1964
|
+
if (this.model) {
|
1965
|
+
return this.serializeModel.apply(this, args);
|
1966
|
+
} else {
|
1967
|
+
return {
|
1968
|
+
items: this.serializeCollection.apply(this, args)
|
1969
|
+
};
|
1970
|
+
}
|
1910
1971
|
},
|
1911
1972
|
|
1912
1973
|
// Serialize a collection by serializing each of its models.
|
1913
1974
|
serializeCollection: function(collection){
|
1914
|
-
return collection.toJSON.apply(collection,
|
1975
|
+
return collection.toJSON.apply(collection, _.rest(arguments));
|
1915
1976
|
},
|
1916
1977
|
|
1917
1978
|
// Render the view, defaulting to underscore.js templates.
|
@@ -1978,14 +2039,6 @@
|
|
1978
2039
|
this.$el.html(html);
|
1979
2040
|
|
1980
2041
|
return this;
|
1981
|
-
},
|
1982
|
-
|
1983
|
-
// Override the default destroy event to add a few
|
1984
|
-
// more events that are triggered.
|
1985
|
-
destroy: function() {
|
1986
|
-
if (this.isDestroyed) { return; }
|
1987
|
-
|
1988
|
-
return Marionette.View.prototype.destroy.apply(this, arguments);
|
1989
2042
|
}
|
1990
2043
|
});
|
1991
2044
|
|
@@ -2008,7 +2061,9 @@
|
|
2008
2061
|
// This will fallback onto appending childView's to the end.
|
2009
2062
|
constructor: function(options){
|
2010
2063
|
var initOptions = options || {};
|
2011
|
-
|
2064
|
+
if (_.isUndefined(this.sort)){
|
2065
|
+
this.sort = _.isUndefined(initOptions.sort) ? true : initOptions.sort;
|
2066
|
+
}
|
2012
2067
|
|
2013
2068
|
this.once('render', this._initialEvents);
|
2014
2069
|
this._initChildViewStorage();
|
@@ -2126,6 +2181,9 @@
|
|
2126
2181
|
}
|
2127
2182
|
},
|
2128
2183
|
|
2184
|
+
// Internal reference to what index a `emptyView` is.
|
2185
|
+
_emptyViewIndex: -1,
|
2186
|
+
|
2129
2187
|
// Internal method. Separated so that CompositeView can have
|
2130
2188
|
// more control over events being triggered, around the rendering
|
2131
2189
|
// process
|
@@ -2189,7 +2247,7 @@
|
|
2189
2247
|
},
|
2190
2248
|
|
2191
2249
|
// Render and show the emptyView. Similar to addChild method
|
2192
|
-
// but "child
|
2250
|
+
// but "add:child" events are not fired, and the event from
|
2193
2251
|
// emptyView are not forwarded
|
2194
2252
|
addEmptyView: function(child, EmptyView) {
|
2195
2253
|
|
@@ -2198,12 +2256,14 @@
|
|
2198
2256
|
this.getOption('childViewOptions');
|
2199
2257
|
|
2200
2258
|
if (_.isFunction(emptyViewOptions)){
|
2201
|
-
emptyViewOptions = emptyViewOptions.call(this);
|
2259
|
+
emptyViewOptions = emptyViewOptions.call(this, child, this._emptyViewIndex);
|
2202
2260
|
}
|
2203
2261
|
|
2204
2262
|
// build the empty view
|
2205
2263
|
var view = this.buildChildView(child, EmptyView, emptyViewOptions);
|
2206
2264
|
|
2265
|
+
view._parent = this;
|
2266
|
+
|
2207
2267
|
// Proxy emptyView events
|
2208
2268
|
this.proxyChildEvents(view);
|
2209
2269
|
|
@@ -2218,7 +2278,7 @@
|
|
2218
2278
|
this.children.add(view);
|
2219
2279
|
|
2220
2280
|
// Render it and show it
|
2221
|
-
this.renderChildView(view,
|
2281
|
+
this.renderChildView(view, this._emptyViewIndex);
|
2222
2282
|
|
2223
2283
|
// call the 'show' method if the collection view
|
2224
2284
|
// has already been shown
|
@@ -2252,9 +2312,7 @@
|
|
2252
2312
|
// in order to keep the children in sync with the collection.
|
2253
2313
|
addChild: function(child, ChildView, index) {
|
2254
2314
|
var childViewOptions = this.getOption('childViewOptions');
|
2255
|
-
|
2256
|
-
childViewOptions = childViewOptions.call(this, child, index);
|
2257
|
-
}
|
2315
|
+
childViewOptions = Marionette._getValue(childViewOptions, this, [child, index]);
|
2258
2316
|
|
2259
2317
|
var view = this.buildChildView(child, ChildView, childViewOptions);
|
2260
2318
|
|
@@ -2263,6 +2321,8 @@
|
|
2263
2321
|
|
2264
2322
|
this._addChildView(view, index);
|
2265
2323
|
|
2324
|
+
view._parent = this;
|
2325
|
+
|
2266
2326
|
return view;
|
2267
2327
|
},
|
2268
2328
|
|
@@ -2276,22 +2336,14 @@
|
|
2276
2336
|
if (increment) {
|
2277
2337
|
// assign the index to the view
|
2278
2338
|
view._index = index;
|
2279
|
-
|
2280
|
-
// increment the index of views after this one
|
2281
|
-
this.children.each(function (laterView) {
|
2282
|
-
if (laterView._index >= view._index) {
|
2283
|
-
laterView._index++;
|
2284
|
-
}
|
2285
|
-
});
|
2286
|
-
}
|
2287
|
-
else {
|
2288
|
-
// decrement the index of views after this one
|
2289
|
-
this.children.each(function (laterView) {
|
2290
|
-
if (laterView._index >= view._index) {
|
2291
|
-
laterView._index--;
|
2292
|
-
}
|
2293
|
-
});
|
2294
2339
|
}
|
2340
|
+
|
2341
|
+
// update the indexes of views after this one
|
2342
|
+
this.children.each(function (laterView) {
|
2343
|
+
if (laterView._index >= view._index) {
|
2344
|
+
laterView._index += increment ? 1 : -1;
|
2345
|
+
}
|
2346
|
+
});
|
2295
2347
|
},
|
2296
2348
|
|
2297
2349
|
|
@@ -2340,6 +2392,7 @@
|
|
2340
2392
|
if (view.destroy) { view.destroy(); }
|
2341
2393
|
else if (view.remove) { view.remove(); }
|
2342
2394
|
|
2395
|
+
delete view._parent;
|
2343
2396
|
this.stopListening(view);
|
2344
2397
|
this.children.remove(view);
|
2345
2398
|
this.triggerMethod('remove:child', view);
|
@@ -2448,7 +2501,7 @@
|
|
2448
2501
|
// Forward all child view events through the parent,
|
2449
2502
|
// prepending "childview:" to the event name
|
2450
2503
|
this.listenTo(view, 'all', function() {
|
2451
|
-
var args =
|
2504
|
+
var args = _.toArray(arguments);
|
2452
2505
|
var rootEvent = args[0];
|
2453
2506
|
var childEvents = this.normalizeMethods(_.result(this, 'childEvents'));
|
2454
2507
|
|
@@ -2462,6 +2515,10 @@
|
|
2462
2515
|
|
2463
2516
|
this.triggerMethod.apply(this, args);
|
2464
2517
|
}, this);
|
2518
|
+
},
|
2519
|
+
|
2520
|
+
_getImmediateChildren: function() {
|
2521
|
+
return _.values(this.children._views);
|
2465
2522
|
}
|
2466
2523
|
});
|
2467
2524
|
|
@@ -2510,17 +2567,10 @@
|
|
2510
2567
|
getChildView: function(child) {
|
2511
2568
|
var childView = this.getOption('childView') || this.constructor;
|
2512
2569
|
|
2513
|
-
if (!childView) {
|
2514
|
-
throw new Marionette.Error({
|
2515
|
-
name: 'NoChildViewError',
|
2516
|
-
message: 'A "childView" must be specified'
|
2517
|
-
});
|
2518
|
-
}
|
2519
|
-
|
2520
2570
|
return childView;
|
2521
2571
|
},
|
2522
2572
|
|
2523
|
-
// Serialize the
|
2573
|
+
// Serialize the model for the view.
|
2524
2574
|
// You can override the `serializeData` method in your own view
|
2525
2575
|
// definition, to provide custom serialization for your view's data.
|
2526
2576
|
serializeData: function() {
|
@@ -2533,9 +2583,7 @@
|
|
2533
2583
|
return data;
|
2534
2584
|
},
|
2535
2585
|
|
2536
|
-
// Renders the model
|
2537
|
-
// this again will tell the model's view to re-render itself
|
2538
|
-
// but the collection will not re-render.
|
2586
|
+
// Renders the model and the collection.
|
2539
2587
|
render: function() {
|
2540
2588
|
this._ensureViewIsIntact();
|
2541
2589
|
this.isRendered = true;
|
@@ -2604,13 +2652,13 @@
|
|
2604
2652
|
// Overidden from CollectionView to ensure view is appended to
|
2605
2653
|
// childViewContainer
|
2606
2654
|
_insertAfter: function (childView) {
|
2607
|
-
var $container = this.getChildViewContainer(this);
|
2655
|
+
var $container = this.getChildViewContainer(this, childView);
|
2608
2656
|
$container.append(childView.el);
|
2609
2657
|
},
|
2610
2658
|
|
2611
2659
|
// Internal method to ensure an `$childViewContainer` exists, for the
|
2612
2660
|
// `attachHtml` method to use.
|
2613
|
-
getChildViewContainer: function(containerView) {
|
2661
|
+
getChildViewContainer: function(containerView, childView) {
|
2614
2662
|
if ('$childViewContainer' in containerView) {
|
2615
2663
|
return containerView.$childViewContainer;
|
2616
2664
|
}
|
@@ -2619,7 +2667,7 @@
|
|
2619
2667
|
var childViewContainer = Marionette.getOption(containerView, 'childViewContainer');
|
2620
2668
|
if (childViewContainer) {
|
2621
2669
|
|
2622
|
-
var selector =
|
2670
|
+
var selector = Marionette._getValue(childViewContainer, containerView);
|
2623
2671
|
|
2624
2672
|
if (selector.charAt(0) === '@' && containerView.ui) {
|
2625
2673
|
container = containerView.ui[selector.substr(4)];
|
@@ -2650,8 +2698,8 @@
|
|
2650
2698
|
}
|
2651
2699
|
});
|
2652
2700
|
|
2653
|
-
//
|
2654
|
-
//
|
2701
|
+
// Layout View
|
2702
|
+
// -----------
|
2655
2703
|
|
2656
2704
|
// Used for managing application layoutViews, nested layoutViews and
|
2657
2705
|
// multiple regions within an application or sub-application.
|
@@ -2734,11 +2782,9 @@
|
|
2734
2782
|
|
2735
2783
|
// internal method to build regions
|
2736
2784
|
_buildRegions: function(regions) {
|
2737
|
-
var that = this;
|
2738
|
-
|
2739
2785
|
var defaults = {
|
2740
2786
|
regionClass: this.getOption('regionClass'),
|
2741
|
-
parentEl:
|
2787
|
+
parentEl: _.partial(_.result, this, 'el')
|
2742
2788
|
};
|
2743
2789
|
|
2744
2790
|
return this.regionManager.addRegions(regions, defaults);
|
@@ -2750,19 +2796,13 @@
|
|
2750
2796
|
var regions;
|
2751
2797
|
this._initRegionManager();
|
2752
2798
|
|
2753
|
-
|
2754
|
-
regions = this.regions(options);
|
2755
|
-
} else {
|
2756
|
-
regions = this.regions || {};
|
2757
|
-
}
|
2799
|
+
regions = Marionette._getValue(this.regions, this, [options]) || {};
|
2758
2800
|
|
2759
2801
|
// Enable users to define `regions` as instance options.
|
2760
2802
|
var regionOptions = this.getOption.call(options, 'regions');
|
2761
2803
|
|
2762
2804
|
// enable region options to be a function
|
2763
|
-
|
2764
|
-
regionOptions = regionOptions.call(this, options);
|
2765
|
-
}
|
2805
|
+
regionOptions = Marionette._getValue(regionOptions, this, [options]);
|
2766
2806
|
|
2767
2807
|
_.extend(regions, regionOptions);
|
2768
2808
|
|
@@ -2776,10 +2816,7 @@
|
|
2776
2816
|
// Internal method to re-initialize all of the regions by updating the `el` that
|
2777
2817
|
// they point to
|
2778
2818
|
_reInitializeRegions: function() {
|
2779
|
-
this.regionManager.
|
2780
|
-
this.regionManager.each(function(region) {
|
2781
|
-
region.reset();
|
2782
|
-
});
|
2819
|
+
this.regionManager.invoke('reset');
|
2783
2820
|
},
|
2784
2821
|
|
2785
2822
|
// Enable easy overriding of the default `RegionManager`
|
@@ -2793,6 +2830,7 @@
|
|
2793
2830
|
// and all regions in it
|
2794
2831
|
_initRegionManager: function() {
|
2795
2832
|
this.regionManager = this.getRegionManager();
|
2833
|
+
this.regionManager._parent = this;
|
2796
2834
|
|
2797
2835
|
this.listenTo(this.regionManager, 'before:add:region', function(name) {
|
2798
2836
|
this.triggerMethod('before:add:region', name);
|
@@ -2811,20 +2849,27 @@
|
|
2811
2849
|
delete this[name];
|
2812
2850
|
this.triggerMethod('remove:region', name, region);
|
2813
2851
|
});
|
2852
|
+
},
|
2853
|
+
|
2854
|
+
_getImmediateChildren: function() {
|
2855
|
+
return _.chain(this.regionManager.getRegions())
|
2856
|
+
.pluck('currentView')
|
2857
|
+
.compact()
|
2858
|
+
.value();
|
2814
2859
|
}
|
2815
2860
|
});
|
2816
2861
|
|
2817
2862
|
|
2818
2863
|
// Behavior
|
2819
|
-
//
|
2864
|
+
// --------
|
2820
2865
|
|
2821
2866
|
// A Behavior is an isolated set of DOM /
|
2822
2867
|
// user interactions that can be mixed into any View.
|
2823
2868
|
// Behaviors allow you to blackbox View specific interactions
|
2824
2869
|
// into portable logical chunks, keeping your views simple and your code DRY.
|
2825
2870
|
|
2826
|
-
Marionette.Behavior = (
|
2827
|
-
function
|
2871
|
+
Marionette.Behavior = Marionette.Object.extend({
|
2872
|
+
constructor: function(options, view) {
|
2828
2873
|
// Setup reference to the view.
|
2829
2874
|
// this comes in handle when a behavior
|
2830
2875
|
// wants to directly talk up the chain
|
@@ -2833,57 +2878,31 @@
|
|
2833
2878
|
this.defaults = _.result(this, 'defaults') || {};
|
2834
2879
|
this.options = _.extend({}, this.defaults, options);
|
2835
2880
|
|
2836
|
-
|
2837
|
-
|
2838
|
-
// scoped to behaviors view.
|
2839
|
-
this.$ = function() {
|
2840
|
-
return this.view.$.apply(this.view, arguments);
|
2841
|
-
};
|
2842
|
-
|
2843
|
-
// Call the initialize method passing
|
2844
|
-
// the arguments from the instance constructor
|
2845
|
-
this.initialize.apply(this, arguments);
|
2846
|
-
}
|
2847
|
-
|
2848
|
-
_.extend(Behavior.prototype, Backbone.Events, {
|
2849
|
-
initialize: function() {},
|
2850
|
-
|
2851
|
-
// stopListening to behavior `onListen` events.
|
2852
|
-
destroy: function() {
|
2853
|
-
this.stopListening();
|
2854
|
-
},
|
2855
|
-
|
2856
|
-
proxyViewProperties: function (view) {
|
2857
|
-
this.$el = view.$el;
|
2858
|
-
this.el = view.el;
|
2859
|
-
},
|
2860
|
-
|
2861
|
-
// import the `triggerMethod` to trigger events with corresponding
|
2862
|
-
// methods if the method exists
|
2863
|
-
triggerMethod: Marionette.triggerMethod,
|
2864
|
-
|
2865
|
-
// Proxy `getOption` to enable getting options from this or this.options by name.
|
2866
|
-
getOption: Marionette.proxyGetOption,
|
2867
|
-
|
2868
|
-
// Proxy `unbindEntityEvents` to enable binding view's events from another entity.
|
2869
|
-
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
2881
|
+
Marionette.Object.apply(this, arguments);
|
2882
|
+
},
|
2870
2883
|
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2884
|
+
// proxy behavior $ method to the view
|
2885
|
+
// this is useful for doing jquery DOM lookups
|
2886
|
+
// scoped to behaviors view.
|
2887
|
+
$: function() {
|
2888
|
+
return this.view.$.apply(this.view, arguments);
|
2889
|
+
},
|
2874
2890
|
|
2875
|
-
//
|
2876
|
-
//
|
2877
|
-
|
2878
|
-
|
2879
|
-
|
2891
|
+
// Stops the behavior from listening to events.
|
2892
|
+
// Overrides Object#destroy to prevent additional events from being triggered.
|
2893
|
+
destroy: function() {
|
2894
|
+
this.stopListening();
|
2895
|
+
},
|
2880
2896
|
|
2881
|
-
|
2882
|
-
|
2897
|
+
proxyViewProperties: function (view) {
|
2898
|
+
this.$el = view.$el;
|
2899
|
+
this.el = view.el;
|
2900
|
+
}
|
2901
|
+
});
|
2883
2902
|
|
2884
2903
|
/* jshint maxlen: 143 */
|
2885
|
-
//
|
2886
|
-
//
|
2904
|
+
// Behaviors
|
2905
|
+
// ---------
|
2887
2906
|
|
2888
2907
|
// Behaviors is a utility class that takes care of
|
2889
2908
|
// gluing your behavior instances to their given View.
|
@@ -2892,6 +2911,8 @@
|
|
2892
2911
|
// method for things to work properly.
|
2893
2912
|
|
2894
2913
|
Marionette.Behaviors = (function(Marionette, _) {
|
2914
|
+
// Borrow event splitter from Backbone
|
2915
|
+
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
|
2895
2916
|
|
2896
2917
|
function Behaviors(view, behaviors) {
|
2897
2918
|
|
@@ -2918,12 +2939,12 @@
|
|
2918
2939
|
|
2919
2940
|
behaviorEvents: function(behaviorEvents, behaviors) {
|
2920
2941
|
var _behaviorsEvents = {};
|
2921
|
-
var viewUI = _.result(this, 'ui');
|
2942
|
+
var viewUI = this._uiBindings || _.result(this, 'ui');
|
2922
2943
|
|
2923
2944
|
_.each(behaviors, function(b, i) {
|
2924
2945
|
var _events = {};
|
2925
2946
|
var behaviorEvents = _.clone(_.result(b, 'events')) || {};
|
2926
|
-
var behaviorUI = _.result(b, 'ui');
|
2947
|
+
var behaviorUI = b._uiBindings || _.result(b, 'ui');
|
2927
2948
|
|
2928
2949
|
// Construct an internal UI hash first using
|
2929
2950
|
// the views UI hash and then the behaviors UI hash.
|
@@ -2936,21 +2957,25 @@
|
|
2936
2957
|
// a user to use the @ui. syntax.
|
2937
2958
|
behaviorEvents = Marionette.normalizeUIKeys(behaviorEvents, ui);
|
2938
2959
|
|
2939
|
-
|
2940
|
-
|
2941
|
-
|
2942
|
-
|
2960
|
+
var j = 0;
|
2961
|
+
_.each(behaviorEvents, function(behaviour, key) {
|
2962
|
+
var match = key.match(delegateEventSplitter);
|
2963
|
+
|
2964
|
+
// Set event name to be namespaced using the view cid,
|
2965
|
+
// the behavior index, and the behavior event index
|
2966
|
+
// to generate a non colliding event namespace
|
2967
|
+
// http://api.jquery.com/event.namespace/
|
2968
|
+
var eventName = match[1] + '.' + [this.cid, i, j++, ' '].join(''),
|
2969
|
+
selector = match[2];
|
2943
2970
|
|
2944
|
-
|
2945
|
-
var
|
2946
|
-
var eventKey = key + whitespace;
|
2947
|
-
var handler = _.isFunction(behaviorEvents[key]) ? behaviorEvents[key] : b[behaviorEvents[key]];
|
2971
|
+
var eventKey = eventName + selector;
|
2972
|
+
var handler = _.isFunction(behaviour) ? behaviour : b[behaviour];
|
2948
2973
|
|
2949
2974
|
_events[eventKey] = _.bind(handler, b);
|
2950
|
-
});
|
2975
|
+
}, this);
|
2951
2976
|
|
2952
2977
|
_behaviorsEvents = _.extend(_behaviorsEvents, _events);
|
2953
|
-
});
|
2978
|
+
}, this);
|
2954
2979
|
|
2955
2980
|
return _behaviorsEvents;
|
2956
2981
|
}
|
@@ -2985,7 +3010,7 @@
|
|
2985
3010
|
}
|
2986
3011
|
|
2987
3012
|
// Get behavior class can be either a flat object or a method
|
2988
|
-
return
|
3013
|
+
return Marionette._getValue(Behaviors.behaviorsLookup, this, [options, key])[key];
|
2989
3014
|
},
|
2990
3015
|
|
2991
3016
|
// Iterate over the behaviors object, for each behavior
|
@@ -3036,7 +3061,7 @@
|
|
3036
3061
|
|
3037
3062
|
triggersHash = Marionette.normalizeUIKeys(triggersHash, ui);
|
3038
3063
|
|
3039
|
-
_.each(triggersHash, _.
|
3064
|
+
_.each(triggersHash, _.bind(this._setHandlerForBehavior, this, behavior, i));
|
3040
3065
|
},
|
3041
3066
|
|
3042
3067
|
// Internal method to create and assign the trigger handler for a given
|
@@ -3056,8 +3081,8 @@
|
|
3056
3081
|
})(Marionette, _);
|
3057
3082
|
|
3058
3083
|
|
3059
|
-
//
|
3060
|
-
//
|
3084
|
+
// App Router
|
3085
|
+
// ----------
|
3061
3086
|
|
3062
3087
|
// Reduce the boilerplate code of handling route events
|
3063
3088
|
// and then calling a single method on another object.
|
@@ -3077,10 +3102,10 @@
|
|
3077
3102
|
Marionette.AppRouter = Backbone.Router.extend({
|
3078
3103
|
|
3079
3104
|
constructor: function(options) {
|
3080
|
-
Backbone.Router.apply(this, arguments);
|
3081
|
-
|
3082
3105
|
this.options = options || {};
|
3083
3106
|
|
3107
|
+
Backbone.Router.apply(this, arguments);
|
3108
|
+
|
3084
3109
|
var appRoutes = this.getOption('appRoutes');
|
3085
3110
|
var controller = this._getController();
|
3086
3111
|
this.processAppRoutes(controller, appRoutes);
|
@@ -3097,11 +3122,10 @@
|
|
3097
3122
|
// process the route event and trigger the onRoute
|
3098
3123
|
// method call, if it exists
|
3099
3124
|
_processOnRoute: function(routeName, routeArgs) {
|
3100
|
-
//
|
3101
|
-
var routePath = _.invert(this.getOption('appRoutes'))[routeName];
|
3102
|
-
|
3103
|
-
// make sure an onRoute is there, and call it
|
3125
|
+
// make sure an onRoute before trying to call it
|
3104
3126
|
if (_.isFunction(this.onRoute)) {
|
3127
|
+
// find the path that matches the current route
|
3128
|
+
var routePath = _.invert(this.getOption('appRoutes'))[routeName];
|
3105
3129
|
this.onRoute(routeName, routePath, routeArgs);
|
3106
3130
|
}
|
3107
3131
|
},
|
@@ -3134,7 +3158,13 @@
|
|
3134
3158
|
},
|
3135
3159
|
|
3136
3160
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
3137
|
-
getOption: Marionette.proxyGetOption
|
3161
|
+
getOption: Marionette.proxyGetOption,
|
3162
|
+
|
3163
|
+
triggerMethod: Marionette.triggerMethod,
|
3164
|
+
|
3165
|
+
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
3166
|
+
|
3167
|
+
unbindEntityEvents: Marionette.proxyUnbindEntityEvents
|
3138
3168
|
});
|
3139
3169
|
|
3140
3170
|
// Application
|
@@ -3143,20 +3173,15 @@
|
|
3143
3173
|
// Contain and manage the composite application as a whole.
|
3144
3174
|
// Stores and starts up `Region` objects, includes an
|
3145
3175
|
// event aggregator as `app.vent`
|
3146
|
-
Marionette.Application =
|
3147
|
-
|
3148
|
-
|
3149
|
-
|
3150
|
-
|
3151
|
-
|
3152
|
-
|
3153
|
-
|
3154
|
-
|
3155
|
-
|
3156
|
-
_.extend(Marionette.Application.prototype, Backbone.Events, {
|
3157
|
-
// Initialize is an empty function by default. Override it with your own
|
3158
|
-
// initialization logic.
|
3159
|
-
initialize: function() {},
|
3176
|
+
Marionette.Application = Marionette.Object.extend({
|
3177
|
+
constructor: function(options) {
|
3178
|
+
this._initializeRegions(options);
|
3179
|
+
this._initCallbacks = new Marionette.Callbacks();
|
3180
|
+
this.submodules = {};
|
3181
|
+
_.extend(this, options);
|
3182
|
+
this._initChannel();
|
3183
|
+
Marionette.Object.call(this, options);
|
3184
|
+
},
|
3160
3185
|
|
3161
3186
|
// Command execution, facilitated by Backbone.Wreqr.Commands
|
3162
3187
|
execute: function() {
|
@@ -3222,9 +3247,7 @@
|
|
3222
3247
|
// Overwrite the module class if the user specifies one
|
3223
3248
|
var ModuleClass = Marionette.Module.getClass(moduleDefinition);
|
3224
3249
|
|
3225
|
-
|
3226
|
-
// first argument of the array
|
3227
|
-
var args = slice.call(arguments);
|
3250
|
+
var args = _.toArray(arguments);
|
3228
3251
|
args.unshift(this);
|
3229
3252
|
|
3230
3253
|
// see the Marionette.Module object for more information
|
@@ -3264,23 +3287,24 @@
|
|
3264
3287
|
// Internal method to set up the region manager
|
3265
3288
|
_initRegionManager: function() {
|
3266
3289
|
this._regionManager = this.getRegionManager();
|
3290
|
+
this._regionManager._parent = this;
|
3267
3291
|
|
3268
|
-
this.listenTo(this._regionManager, 'before:add:region', function(
|
3269
|
-
|
3292
|
+
this.listenTo(this._regionManager, 'before:add:region', function() {
|
3293
|
+
Marionette._triggerMethod(this, 'before:add:region', arguments);
|
3270
3294
|
});
|
3271
3295
|
|
3272
3296
|
this.listenTo(this._regionManager, 'add:region', function(name, region) {
|
3273
3297
|
this[name] = region;
|
3274
|
-
|
3298
|
+
Marionette._triggerMethod(this, 'add:region', arguments);
|
3275
3299
|
});
|
3276
3300
|
|
3277
|
-
this.listenTo(this._regionManager, 'before:remove:region', function(
|
3278
|
-
|
3301
|
+
this.listenTo(this._regionManager, 'before:remove:region', function() {
|
3302
|
+
Marionette._triggerMethod(this, 'before:remove:region', arguments);
|
3279
3303
|
});
|
3280
3304
|
|
3281
|
-
this.listenTo(this._regionManager, 'remove:region', function(name
|
3305
|
+
this.listenTo(this._regionManager, 'remove:region', function(name) {
|
3282
3306
|
delete this[name];
|
3283
|
-
|
3307
|
+
Marionette._triggerMethod(this, 'remove:region', arguments);
|
3284
3308
|
});
|
3285
3309
|
},
|
3286
3310
|
|
@@ -3291,19 +3315,9 @@
|
|
3291
3315
|
this.vent = _.result(this, 'vent') || this.channel.vent;
|
3292
3316
|
this.commands = _.result(this, 'commands') || this.channel.commands;
|
3293
3317
|
this.reqres = _.result(this, 'reqres') || this.channel.reqres;
|
3294
|
-
}
|
3295
|
-
|
3296
|
-
// import the `triggerMethod` to trigger events with corresponding
|
3297
|
-
// methods if the method exists
|
3298
|
-
triggerMethod: Marionette.triggerMethod,
|
3299
|
-
|
3300
|
-
// Proxy `getOption` to enable getting options from this or this.options by name.
|
3301
|
-
getOption: Marionette.proxyGetOption
|
3318
|
+
}
|
3302
3319
|
});
|
3303
3320
|
|
3304
|
-
// Copy the `extend` function used by Backbone's classes
|
3305
|
-
Marionette.Application.extend = Marionette.extend;
|
3306
|
-
|
3307
3321
|
/* jshint maxparams: 9 */
|
3308
3322
|
|
3309
3323
|
// Module
|
@@ -3391,7 +3405,7 @@
|
|
3391
3405
|
|
3392
3406
|
// stop the sub-modules; depth-first, to make sure the
|
3393
3407
|
// sub-modules are stopped / finalized before parents
|
3394
|
-
_.
|
3408
|
+
_.invoke(this.submodules, 'stop');
|
3395
3409
|
|
3396
3410
|
// run the finalizers
|
3397
3411
|
this._finalizerCallbacks.run(undefined, this);
|
@@ -3450,8 +3464,7 @@
|
|
3450
3464
|
|
3451
3465
|
// get the custom args passed in after the module definition and
|
3452
3466
|
// get rid of the module name and definition function
|
3453
|
-
var customArgs =
|
3454
|
-
customArgs.splice(0, 3);
|
3467
|
+
var customArgs = _.rest(arguments, 3);
|
3455
3468
|
|
3456
3469
|
// Split the module names and get the number of submodules.
|
3457
3470
|
// i.e. an example module name of `Doge.Wow.Amaze` would
|