marionette-rails 2.2.2 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
|