marionette-rails 2.2.1 → 2.2.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 +4 -4
- data/LICENSE +2 -2
- data/README.md +1 -7
- data/lib/marionette-rails/version.rb +1 -1
- data/vendor/assets/javascripts/backbone.marionette.js +625 -620
- data/vendor/assets/javascripts/backbone.marionette.map +1 -1
- data/vendor/assets/javascripts/backbone.marionette.min.js +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bb72c3e7ebd42ae9f6ff1cab755e4d75cbd33d7
|
4
|
+
data.tar.gz: 93bb3dd197d7c37ffc2698eebf39c93476d84246
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 770e3d2afb69960a1572be93848b96a4a06dbc84f89652f0b0c61c98807fe3ecec3f088124750953b81d3c9b8914d9577c85ac575d061935e0d0bec7f63c01a6
|
7
|
+
data.tar.gz: aae08d6c39199c82b4ffb94c0c0b47a8b2b5b84d69b8c909a9ebc3815b35c89a710c851a009583cd0d61c2ada9a582d22ca161b9a5861da904d02912a9c05f6a
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2012 Godfrey Chan
|
1
|
+
Copyright (c) 2012-2014 Godfrey Chan & Stafford Brunk
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
THE SOFTWARE.
|
19
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ marionette-rails
|
|
5
5
|
|
6
6
|
This gem is a wrapper for Derick Bailey's [Backbone.Marionette](https://github.com/marionettejs/backbone.marionette) library. It vendors the javascript library code for use with Rails' asset pipeline (Rails 3.1+).
|
7
7
|
|
8
|
-
This gem is currently maintained by [@
|
8
|
+
This gem is currently maintained by [@wingrunr21](https://github.com/wingrunr21).
|
9
9
|
|
10
10
|
## Dependencies
|
11
11
|
|
@@ -44,12 +44,6 @@ For bugs in [Backbone.Marionette](https://github.com/marionettejs/backbone.mario
|
|
44
44
|
|
45
45
|
For bugs in this gem distribution, use the [GitHub issue tracker](https://github.com/chancancode/marionette-rails/issues). If you could submit a pull request - that's even better!
|
46
46
|
|
47
|
-
## Donations
|
48
|
-
|
49
|
-
If you're using Marionette and you're finding that it is saving you time and effort, then please consider donating to the upstream [Backbone.Marionette](https://github.com/marionettejs/backbone.marionette) project.
|
50
|
-
|
51
|
-
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7SJHYWJ487SF4)
|
52
|
-
|
53
47
|
## License
|
54
48
|
|
55
49
|
This library is distributed under the MIT license. Please see the LICENSE file.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// MarionetteJS (Backbone.Marionette)
|
2
2
|
// ----------------------------------
|
3
|
-
// v2.2.
|
3
|
+
// v2.2.2
|
4
4
|
//
|
5
5
|
// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
|
6
6
|
// Distributed under MIT license
|
@@ -493,7 +493,7 @@
|
|
493
493
|
|
494
494
|
var Marionette = Backbone.Marionette = {};
|
495
495
|
|
496
|
-
Marionette.VERSION = '2.2.
|
496
|
+
Marionette.VERSION = '2.2.2';
|
497
497
|
|
498
498
|
Marionette.noConflict = function() {
|
499
499
|
root.Marionette = previousMarionette;
|
@@ -506,45 +506,45 @@
|
|
506
506
|
Marionette.Deferred = Backbone.$.Deferred;
|
507
507
|
|
508
508
|
/* jshint unused: false */
|
509
|
-
|
509
|
+
|
510
510
|
// Helpers
|
511
511
|
// -------
|
512
|
-
|
512
|
+
|
513
513
|
// For slicing `arguments` in functions
|
514
514
|
var slice = Array.prototype.slice;
|
515
|
-
|
515
|
+
|
516
516
|
// Marionette.extend
|
517
517
|
// -----------------
|
518
|
-
|
518
|
+
|
519
519
|
// Borrow the Backbone `extend` method so we can use it as needed
|
520
520
|
Marionette.extend = Backbone.Model.extend;
|
521
|
-
|
521
|
+
|
522
522
|
// Marionette.getOption
|
523
523
|
// --------------------
|
524
|
-
|
524
|
+
|
525
525
|
// Retrieve an object, function or other value from a target
|
526
526
|
// object or its `options`, with `options` taking precedence.
|
527
527
|
Marionette.getOption = function(target, optionName) {
|
528
528
|
if (!target || !optionName) { return; }
|
529
529
|
var value;
|
530
|
-
|
530
|
+
|
531
531
|
if (target.options && (target.options[optionName] !== undefined)) {
|
532
532
|
value = target.options[optionName];
|
533
533
|
} else {
|
534
534
|
value = target[optionName];
|
535
535
|
}
|
536
|
-
|
536
|
+
|
537
537
|
return value;
|
538
538
|
};
|
539
|
-
|
539
|
+
|
540
540
|
// Proxy `Marionette.getOption`
|
541
541
|
Marionette.proxyGetOption = function(optionName) {
|
542
542
|
return Marionette.getOption(this, optionName);
|
543
543
|
};
|
544
|
-
|
544
|
+
|
545
545
|
// Marionette.normalizeMethods
|
546
546
|
// ----------------------
|
547
|
-
|
547
|
+
|
548
548
|
// Pass in a mapping of events => functions or function names
|
549
549
|
// and return a mapping of events => functions
|
550
550
|
Marionette.normalizeMethods = function(hash) {
|
@@ -560,7 +560,7 @@
|
|
560
560
|
}, this);
|
561
561
|
return normalizedHash;
|
562
562
|
};
|
563
|
-
|
563
|
+
|
564
564
|
// utility method for parsing @ui. syntax strings
|
565
565
|
// into associated selector
|
566
566
|
Marionette.normalizeUIString = function(uiString, ui) {
|
@@ -568,7 +568,7 @@
|
|
568
568
|
return ui[r.slice(4)];
|
569
569
|
});
|
570
570
|
};
|
571
|
-
|
571
|
+
|
572
572
|
// allows for the use of the @ui. syntax within
|
573
573
|
// a given key for triggers and events
|
574
574
|
// swaps the @ui with the associated selector.
|
@@ -577,9 +577,9 @@
|
|
577
577
|
if (typeof(hash) === 'undefined') {
|
578
578
|
return;
|
579
579
|
}
|
580
|
-
|
580
|
+
|
581
581
|
hash = _.clone(hash);
|
582
|
-
|
582
|
+
|
583
583
|
_.each(_.keys(hash), function(key) {
|
584
584
|
var normalizedKey = Marionette.normalizeUIString(key, ui);
|
585
585
|
if (normalizedKey !== key) {
|
@@ -587,10 +587,10 @@
|
|
587
587
|
delete hash[key];
|
588
588
|
}
|
589
589
|
});
|
590
|
-
|
590
|
+
|
591
591
|
return hash;
|
592
592
|
};
|
593
|
-
|
593
|
+
|
594
594
|
// allows for the use of the @ui. syntax within
|
595
595
|
// a given value for regions
|
596
596
|
// swaps the @ui with the associated selector
|
@@ -598,16 +598,16 @@
|
|
598
598
|
if (typeof(hash) === 'undefined') {
|
599
599
|
return;
|
600
600
|
}
|
601
|
-
|
601
|
+
|
602
602
|
_.each(hash, function(val, key) {
|
603
603
|
if (_.isString(val)) {
|
604
604
|
hash[key] = Marionette.normalizeUIString(val, ui);
|
605
605
|
}
|
606
606
|
});
|
607
|
-
|
607
|
+
|
608
608
|
return hash;
|
609
609
|
};
|
610
|
-
|
610
|
+
|
611
611
|
// Mix in methods from Underscore, for iteration, and other
|
612
612
|
// collection related features.
|
613
613
|
// Borrowing this code from Backbone.Collection:
|
@@ -617,7 +617,7 @@
|
|
617
617
|
'select', 'reject', 'every', 'all', 'some', 'any', 'include',
|
618
618
|
'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
|
619
619
|
'last', 'without', 'isEmpty', 'pluck'];
|
620
|
-
|
620
|
+
|
621
621
|
_.each(methods, function(method) {
|
622
622
|
object[method] = function() {
|
623
623
|
var list = _.values(_.result(this, listProperty));
|
@@ -626,7 +626,7 @@
|
|
626
626
|
};
|
627
627
|
});
|
628
628
|
};
|
629
|
-
|
629
|
+
|
630
630
|
// Trigger an event and/or a corresponding method name. Examples:
|
631
631
|
//
|
632
632
|
// `this.triggerMethod("foo")` will trigger the "foo" event and
|
@@ -635,35 +635,35 @@
|
|
635
635
|
// `this.triggerMethod("foo:bar")` will trigger the "foo:bar" event and
|
636
636
|
// call the "onFooBar" method.
|
637
637
|
Marionette.triggerMethod = function(event) {
|
638
|
-
|
638
|
+
|
639
639
|
// split the event name on the ":"
|
640
640
|
var splitter = /(^|:)(\w)/gi;
|
641
|
-
|
641
|
+
|
642
642
|
// take the event section ("section1:section2:section3")
|
643
643
|
// and turn it in to uppercase name
|
644
644
|
function getEventName(match, prefix, eventName) {
|
645
645
|
return eventName.toUpperCase();
|
646
646
|
}
|
647
|
-
|
647
|
+
|
648
648
|
// get the method name from the event name
|
649
649
|
var methodName = 'on' + event.replace(splitter, getEventName);
|
650
650
|
var method = this[methodName];
|
651
651
|
var result;
|
652
|
-
|
652
|
+
|
653
653
|
// call the onMethodName if it exists
|
654
654
|
if (_.isFunction(method)) {
|
655
655
|
// pass all arguments, except the event name
|
656
656
|
result = method.apply(this, _.tail(arguments));
|
657
657
|
}
|
658
|
-
|
658
|
+
|
659
659
|
// trigger the event, if a trigger method exists
|
660
660
|
if (_.isFunction(this.trigger)) {
|
661
661
|
this.trigger.apply(this, arguments);
|
662
662
|
}
|
663
|
-
|
663
|
+
|
664
664
|
return result;
|
665
665
|
};
|
666
|
-
|
666
|
+
|
667
667
|
// triggerMethodOn invokes triggerMethod on a specific context
|
668
668
|
//
|
669
669
|
// e.g. `Marionette.triggerMethodOn(view, 'show')`
|
@@ -671,23 +671,23 @@
|
|
671
671
|
Marionette.triggerMethodOn = function(context, event) {
|
672
672
|
var args = _.tail(arguments, 2);
|
673
673
|
var fnc;
|
674
|
-
|
674
|
+
|
675
675
|
if (_.isFunction(context.triggerMethod)) {
|
676
676
|
fnc = context.triggerMethod;
|
677
677
|
} else {
|
678
678
|
fnc = Marionette.triggerMethod;
|
679
679
|
}
|
680
|
-
|
680
|
+
|
681
681
|
return fnc.apply(context, [event].concat(args));
|
682
682
|
};
|
683
|
-
|
683
|
+
|
684
684
|
// DOMRefresh
|
685
685
|
// ----------
|
686
686
|
//
|
687
687
|
// Monitor a view's state, and after it has been rendered and shown
|
688
688
|
// in the DOM, trigger a "dom:refresh" event every time it is
|
689
689
|
// re-rendered.
|
690
|
-
|
690
|
+
|
691
691
|
Marionette.MonitorDOMRefresh = (function(documentElement) {
|
692
692
|
// track when the view has been shown in the DOM,
|
693
693
|
// using a Marionette.Region (or by other means of triggering "show")
|
@@ -695,13 +695,13 @@
|
|
695
695
|
view._isShown = true;
|
696
696
|
triggerDOMRefresh(view);
|
697
697
|
}
|
698
|
-
|
698
|
+
|
699
699
|
// track when the view has been rendered
|
700
700
|
function handleRender(view) {
|
701
701
|
view._isRendered = true;
|
702
702
|
triggerDOMRefresh(view);
|
703
703
|
}
|
704
|
-
|
704
|
+
|
705
705
|
// Trigger the "dom:refresh" event and corresponding "onDomRefresh" method
|
706
706
|
function triggerDOMRefresh(view) {
|
707
707
|
if (view._isShown && view._isRendered && isInDOM(view)) {
|
@@ -710,26 +710,26 @@
|
|
710
710
|
}
|
711
711
|
}
|
712
712
|
}
|
713
|
-
|
713
|
+
|
714
714
|
function isInDOM(view) {
|
715
715
|
return Backbone.$.contains(documentElement, view.el);
|
716
716
|
}
|
717
|
-
|
717
|
+
|
718
718
|
// Export public API
|
719
719
|
return function(view) {
|
720
720
|
view.listenTo(view, 'show', function() {
|
721
721
|
handleShow(view);
|
722
722
|
});
|
723
|
-
|
723
|
+
|
724
724
|
view.listenTo(view, 'render', function() {
|
725
725
|
handleRender(view);
|
726
726
|
});
|
727
727
|
};
|
728
728
|
})(document.documentElement);
|
729
|
-
|
729
|
+
|
730
730
|
|
731
731
|
/* jshint maxparams: 5 */
|
732
|
-
|
732
|
+
|
733
733
|
// Marionette.bindEntityEvents & unbindEntityEvents
|
734
734
|
// ---------------------------
|
735
735
|
//
|
@@ -745,53 +745,53 @@
|
|
745
745
|
// The third parameter is a hash of { "event:name": "eventHandler" }
|
746
746
|
// configuration. Multiple handlers can be separated by a space. A
|
747
747
|
// function can be supplied instead of a string handler name.
|
748
|
-
|
748
|
+
|
749
749
|
(function(Marionette) {
|
750
750
|
'use strict';
|
751
|
-
|
751
|
+
|
752
752
|
// Bind the event to handlers specified as a string of
|
753
753
|
// handler names on the target object
|
754
754
|
function bindFromStrings(target, entity, evt, methods) {
|
755
755
|
var methodNames = methods.split(/\s+/);
|
756
|
-
|
756
|
+
|
757
757
|
_.each(methodNames, function(methodName) {
|
758
|
-
|
758
|
+
|
759
759
|
var method = target[methodName];
|
760
760
|
if (!method) {
|
761
761
|
throw new Marionette.Error('Method "' + methodName +
|
762
762
|
'" was configured as an event handler, but does not exist.');
|
763
763
|
}
|
764
|
-
|
764
|
+
|
765
765
|
target.listenTo(entity, evt, method);
|
766
766
|
});
|
767
767
|
}
|
768
|
-
|
768
|
+
|
769
769
|
// Bind the event to a supplied callback function
|
770
770
|
function bindToFunction(target, entity, evt, method) {
|
771
771
|
target.listenTo(entity, evt, method);
|
772
772
|
}
|
773
|
-
|
773
|
+
|
774
774
|
// Bind the event to handlers specified as a string of
|
775
775
|
// handler names on the target object
|
776
776
|
function unbindFromStrings(target, entity, evt, methods) {
|
777
777
|
var methodNames = methods.split(/\s+/);
|
778
|
-
|
778
|
+
|
779
779
|
_.each(methodNames, function(methodName) {
|
780
780
|
var method = target[methodName];
|
781
781
|
target.stopListening(entity, evt, method);
|
782
782
|
});
|
783
783
|
}
|
784
|
-
|
784
|
+
|
785
785
|
// Bind the event to a supplied callback function
|
786
786
|
function unbindToFunction(target, entity, evt, method) {
|
787
787
|
target.stopListening(entity, evt, method);
|
788
788
|
}
|
789
|
-
|
790
|
-
|
789
|
+
|
790
|
+
|
791
791
|
// generic looping function
|
792
792
|
function iterateEvents(target, entity, bindings, functionCallback, stringCallback) {
|
793
793
|
if (!entity || !bindings) { return; }
|
794
|
-
|
794
|
+
|
795
795
|
// type-check bindings
|
796
796
|
if (!_.isFunction(bindings) && !_.isObject(bindings)) {
|
797
797
|
throw new Marionette.Error({
|
@@ -799,15 +799,15 @@
|
|
799
799
|
url: 'marionette.functions.html#marionettebindentityevents'
|
800
800
|
});
|
801
801
|
}
|
802
|
-
|
802
|
+
|
803
803
|
// allow the bindings to be a function
|
804
804
|
if (_.isFunction(bindings)) {
|
805
805
|
bindings = bindings.call(target);
|
806
806
|
}
|
807
|
-
|
807
|
+
|
808
808
|
// iterate the bindings and bind them
|
809
809
|
_.each(bindings, function(methods, evt) {
|
810
|
-
|
810
|
+
|
811
811
|
// allow for a function as the handler,
|
812
812
|
// or a list of event names as a string
|
813
813
|
if (_.isFunction(methods)) {
|
@@ -815,36 +815,36 @@
|
|
815
815
|
} else {
|
816
816
|
stringCallback(target, entity, evt, methods);
|
817
817
|
}
|
818
|
-
|
818
|
+
|
819
819
|
});
|
820
820
|
}
|
821
|
-
|
821
|
+
|
822
822
|
// Export Public API
|
823
823
|
Marionette.bindEntityEvents = function(target, entity, bindings) {
|
824
824
|
iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings);
|
825
825
|
};
|
826
|
-
|
826
|
+
|
827
827
|
Marionette.unbindEntityEvents = function(target, entity, bindings) {
|
828
828
|
iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings);
|
829
829
|
};
|
830
|
-
|
830
|
+
|
831
831
|
// Proxy `bindEntityEvents`
|
832
832
|
Marionette.proxyBindEntityEvents = function(entity, bindings) {
|
833
833
|
return Marionette.bindEntityEvents(this, entity, bindings);
|
834
834
|
};
|
835
|
-
|
835
|
+
|
836
836
|
// Proxy `unbindEntityEvents`
|
837
837
|
Marionette.proxyUnbindEntityEvents = function(entity, bindings) {
|
838
838
|
return Marionette.unbindEntityEvents(this, entity, bindings);
|
839
839
|
};
|
840
840
|
})(Marionette);
|
841
|
-
|
841
|
+
|
842
842
|
|
843
843
|
var errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number'];
|
844
|
-
|
844
|
+
|
845
845
|
Marionette.Error = Marionette.extend.call(Error, {
|
846
|
-
urlRoot: 'http://marionettejs.com/docs/' + Marionette.VERSION + '/',
|
847
|
-
|
846
|
+
urlRoot: 'http://marionettejs.com/docs/v' + Marionette.VERSION + '/',
|
847
|
+
|
848
848
|
constructor: function(message, options) {
|
849
849
|
if (_.isObject(message)) {
|
850
850
|
options = message;
|
@@ -852,33 +852,33 @@
|
|
852
852
|
} else if (!options) {
|
853
853
|
options = {};
|
854
854
|
}
|
855
|
-
|
855
|
+
|
856
856
|
var error = Error.call(this, message);
|
857
857
|
_.extend(this, _.pick(error, errorProps), _.pick(options, errorProps));
|
858
|
-
|
858
|
+
|
859
859
|
this.captureStackTrace();
|
860
|
-
|
860
|
+
|
861
861
|
if (options.url) {
|
862
862
|
this.url = this.urlRoot + options.url;
|
863
863
|
}
|
864
864
|
},
|
865
|
-
|
865
|
+
|
866
866
|
captureStackTrace: function() {
|
867
867
|
if (Error.captureStackTrace) {
|
868
868
|
Error.captureStackTrace(this, Marionette.Error);
|
869
869
|
}
|
870
870
|
},
|
871
|
-
|
871
|
+
|
872
872
|
toString: function() {
|
873
873
|
return this.name + ': ' + this.message + (this.url ? ' See: ' + this.url : '');
|
874
874
|
}
|
875
875
|
});
|
876
|
-
|
876
|
+
|
877
877
|
Marionette.Error.extend = Marionette.extend;
|
878
|
-
|
878
|
+
|
879
879
|
// Callbacks
|
880
880
|
// ---------
|
881
|
-
|
881
|
+
|
882
882
|
// A simple way of managing a collection of callbacks
|
883
883
|
// and executing them at a later point in time, using jQuery's
|
884
884
|
// `Deferred` object.
|
@@ -886,23 +886,23 @@
|
|
886
886
|
this._deferred = Marionette.Deferred();
|
887
887
|
this._callbacks = [];
|
888
888
|
};
|
889
|
-
|
889
|
+
|
890
890
|
_.extend(Marionette.Callbacks.prototype, {
|
891
|
-
|
891
|
+
|
892
892
|
// Add a callback to be executed. Callbacks added here are
|
893
893
|
// guaranteed to execute, even if they are added after the
|
894
894
|
// `run` method is called.
|
895
895
|
add: function(callback, contextOverride) {
|
896
896
|
var promise = _.result(this._deferred, 'promise');
|
897
|
-
|
897
|
+
|
898
898
|
this._callbacks.push({cb: callback, ctx: contextOverride});
|
899
|
-
|
899
|
+
|
900
900
|
promise.then(function(args) {
|
901
901
|
if (contextOverride){ args.context = contextOverride; }
|
902
902
|
callback.call(args.context, args.options);
|
903
903
|
});
|
904
904
|
},
|
905
|
-
|
905
|
+
|
906
906
|
// Run all registered callbacks with the context specified.
|
907
907
|
// Additional callbacks can be added after this has been run
|
908
908
|
// and they will still be executed.
|
@@ -912,20 +912,20 @@
|
|
912
912
|
context: context
|
913
913
|
});
|
914
914
|
},
|
915
|
-
|
915
|
+
|
916
916
|
// Resets the list of callbacks to be run, allowing the same list
|
917
917
|
// to be run multiple times - whenever the `run` method is called.
|
918
918
|
reset: function() {
|
919
919
|
var callbacks = this._callbacks;
|
920
920
|
this._deferred = Marionette.Deferred();
|
921
921
|
this._callbacks = [];
|
922
|
-
|
922
|
+
|
923
923
|
_.each(callbacks, function(cb) {
|
924
924
|
this.add(cb.cb, cb.ctx);
|
925
925
|
}, this);
|
926
926
|
}
|
927
927
|
});
|
928
|
-
|
928
|
+
|
929
929
|
// Marionette Controller
|
930
930
|
// ---------------------
|
931
931
|
//
|
@@ -934,38 +934,38 @@
|
|
934
934
|
// and coordination of other objects, views, and more.
|
935
935
|
Marionette.Controller = function(options) {
|
936
936
|
this.options = options || {};
|
937
|
-
|
937
|
+
|
938
938
|
if (_.isFunction(this.initialize)) {
|
939
939
|
this.initialize(this.options);
|
940
940
|
}
|
941
941
|
};
|
942
|
-
|
942
|
+
|
943
943
|
Marionette.Controller.extend = Marionette.extend;
|
944
|
-
|
944
|
+
|
945
945
|
// Controller Methods
|
946
946
|
// --------------
|
947
|
-
|
947
|
+
|
948
948
|
// Ensure it can trigger events with Backbone.Events
|
949
949
|
_.extend(Marionette.Controller.prototype, Backbone.Events, {
|
950
950
|
destroy: function() {
|
951
951
|
var args = slice.call(arguments);
|
952
952
|
this.triggerMethod.apply(this, ['before:destroy'].concat(args));
|
953
953
|
this.triggerMethod.apply(this, ['destroy'].concat(args));
|
954
|
-
|
954
|
+
|
955
955
|
this.stopListening();
|
956
956
|
this.off();
|
957
957
|
return this;
|
958
958
|
},
|
959
|
-
|
959
|
+
|
960
960
|
// import the `triggerMethod` to trigger events with corresponding
|
961
961
|
// methods if the method exists
|
962
962
|
triggerMethod: Marionette.triggerMethod,
|
963
|
-
|
963
|
+
|
964
964
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
965
965
|
getOption: Marionette.proxyGetOption
|
966
|
-
|
966
|
+
|
967
967
|
});
|
968
|
-
|
968
|
+
|
969
969
|
// Marionette Object
|
970
970
|
// ---------------------
|
971
971
|
//
|
@@ -973,79 +973,79 @@
|
|
973
973
|
// Object borrows many conventions and utilities from Backbone.
|
974
974
|
Marionette.Object = function(options) {
|
975
975
|
this.options = _.extend({}, _.result(this, 'options'), options);
|
976
|
-
|
976
|
+
|
977
977
|
this.initialize.apply(this, arguments);
|
978
978
|
};
|
979
|
-
|
979
|
+
|
980
980
|
Marionette.Object.extend = Marionette.extend;
|
981
|
-
|
981
|
+
|
982
982
|
// Object Methods
|
983
983
|
// --------------
|
984
|
-
|
984
|
+
|
985
985
|
_.extend(Marionette.Object.prototype, {
|
986
|
-
|
986
|
+
|
987
987
|
//this is a noop method intended to be overridden by classes that extend from this base
|
988
988
|
initialize: function() {},
|
989
|
-
|
989
|
+
|
990
990
|
destroy: function() {
|
991
991
|
this.triggerMethod('before:destroy');
|
992
992
|
this.triggerMethod('destroy');
|
993
993
|
this.stopListening();
|
994
994
|
},
|
995
|
-
|
995
|
+
|
996
996
|
// Import the `triggerMethod` to trigger events with corresponding
|
997
997
|
// methods if the method exists
|
998
998
|
triggerMethod: Marionette.triggerMethod,
|
999
|
-
|
999
|
+
|
1000
1000
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1001
1001
|
getOption: Marionette.proxyGetOption,
|
1002
|
-
|
1002
|
+
|
1003
1003
|
// Proxy `unbindEntityEvents` to enable binding view's events from another entity.
|
1004
1004
|
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
1005
|
-
|
1005
|
+
|
1006
1006
|
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
|
1007
1007
|
unbindEntityEvents: Marionette.proxyUnbindEntityEvents
|
1008
1008
|
});
|
1009
|
-
|
1009
|
+
|
1010
1010
|
// Ensure it can trigger events with Backbone.Events
|
1011
1011
|
_.extend(Marionette.Object.prototype, Backbone.Events);
|
1012
|
-
|
1012
|
+
|
1013
1013
|
/* jshint maxcomplexity: 10, maxstatements: 29 */
|
1014
|
-
|
1014
|
+
|
1015
1015
|
// Region
|
1016
1016
|
// ------
|
1017
1017
|
//
|
1018
1018
|
// Manage the visual regions of your composite application. See
|
1019
1019
|
// http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
|
1020
|
-
|
1020
|
+
|
1021
1021
|
Marionette.Region = function(options) {
|
1022
1022
|
this.options = options || {};
|
1023
1023
|
this.el = this.getOption('el');
|
1024
|
-
|
1024
|
+
|
1025
1025
|
// Handle when this.el is passed in as a $ wrapped element.
|
1026
1026
|
this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;
|
1027
|
-
|
1027
|
+
|
1028
1028
|
if (!this.el) {
|
1029
1029
|
throw new Marionette.Error({
|
1030
1030
|
name: 'NoElError',
|
1031
1031
|
message: 'An "el" must be specified for a region.'
|
1032
1032
|
});
|
1033
1033
|
}
|
1034
|
-
|
1034
|
+
|
1035
1035
|
this.$el = this.getEl(this.el);
|
1036
|
-
|
1036
|
+
|
1037
1037
|
if (this.initialize) {
|
1038
1038
|
var args = slice.apply(arguments);
|
1039
1039
|
this.initialize.apply(this, args);
|
1040
1040
|
}
|
1041
1041
|
};
|
1042
|
-
|
1043
|
-
|
1042
|
+
|
1043
|
+
|
1044
1044
|
// Region Class methods
|
1045
1045
|
// -------------------
|
1046
|
-
|
1046
|
+
|
1047
1047
|
_.extend(Marionette.Region, {
|
1048
|
-
|
1048
|
+
|
1049
1049
|
// Build an instance of a region by passing in a configuration object
|
1050
1050
|
// and a default region class to use if none is specified in the config.
|
1051
1051
|
//
|
@@ -1064,26 +1064,26 @@
|
|
1064
1064
|
if (_.isString(regionConfig)) {
|
1065
1065
|
return this._buildRegionFromSelector(regionConfig, DefaultRegionClass);
|
1066
1066
|
}
|
1067
|
-
|
1067
|
+
|
1068
1068
|
if (regionConfig.selector || regionConfig.el || regionConfig.regionClass) {
|
1069
1069
|
return this._buildRegionFromObject(regionConfig, DefaultRegionClass);
|
1070
1070
|
}
|
1071
|
-
|
1071
|
+
|
1072
1072
|
if (_.isFunction(regionConfig)) {
|
1073
1073
|
return this._buildRegionFromRegionClass(regionConfig);
|
1074
1074
|
}
|
1075
|
-
|
1075
|
+
|
1076
1076
|
throw new Marionette.Error({
|
1077
1077
|
message: 'Improper region configuration type.',
|
1078
1078
|
url: 'marionette.region.html#region-configuration-types'
|
1079
1079
|
});
|
1080
1080
|
},
|
1081
|
-
|
1081
|
+
|
1082
1082
|
// Build the region from a string selector like '#foo-region'
|
1083
1083
|
_buildRegionFromSelector: function(selector, DefaultRegionClass) {
|
1084
1084
|
return new DefaultRegionClass({ el: selector });
|
1085
1085
|
},
|
1086
|
-
|
1086
|
+
|
1087
1087
|
// Build the region from a configuration object
|
1088
1088
|
// ```js
|
1089
1089
|
// { selector: '#foo', regionClass: FooRegion }
|
@@ -1091,13 +1091,13 @@
|
|
1091
1091
|
_buildRegionFromObject: function(regionConfig, DefaultRegionClass) {
|
1092
1092
|
var RegionClass = regionConfig.regionClass || DefaultRegionClass;
|
1093
1093
|
var options = _.omit(regionConfig, 'selector', 'regionClass');
|
1094
|
-
|
1094
|
+
|
1095
1095
|
if (regionConfig.selector && !options.el) {
|
1096
1096
|
options.el = regionConfig.selector;
|
1097
1097
|
}
|
1098
|
-
|
1098
|
+
|
1099
1099
|
var region = new RegionClass(options);
|
1100
|
-
|
1100
|
+
|
1101
1101
|
// override the `getEl` function if we have a parentEl
|
1102
1102
|
// this must be overridden to ensure the selector is found
|
1103
1103
|
// on the first use of the region. if we try to assign the
|
@@ -1116,22 +1116,22 @@
|
|
1116
1116
|
return parentEl.find(el);
|
1117
1117
|
};
|
1118
1118
|
}
|
1119
|
-
|
1119
|
+
|
1120
1120
|
return region;
|
1121
1121
|
},
|
1122
|
-
|
1122
|
+
|
1123
1123
|
// Build the region directly from a given `RegionClass`
|
1124
1124
|
_buildRegionFromRegionClass: function(RegionClass) {
|
1125
1125
|
return new RegionClass();
|
1126
1126
|
}
|
1127
|
-
|
1127
|
+
|
1128
1128
|
});
|
1129
|
-
|
1129
|
+
|
1130
1130
|
// Region Instance Methods
|
1131
1131
|
// -----------------------
|
1132
|
-
|
1132
|
+
|
1133
1133
|
_.extend(Marionette.Region.prototype, Backbone.Events, {
|
1134
|
-
|
1134
|
+
|
1135
1135
|
// Displays a backbone view instance inside of the region.
|
1136
1136
|
// Handles calling the `render` method for you. Reads content
|
1137
1137
|
// directly from the `el` attribute. Also calls an optional
|
@@ -1141,86 +1141,90 @@
|
|
1141
1141
|
// the old view being destroyed on show.
|
1142
1142
|
// The `forceShow` option can be used to force a view to be
|
1143
1143
|
// re-rendered if it's already shown in the region.
|
1144
|
-
|
1144
|
+
|
1145
1145
|
show: function(view, options){
|
1146
1146
|
this._ensureElement();
|
1147
|
-
|
1148
|
-
var showOptions
|
1147
|
+
|
1148
|
+
var showOptions = options || {};
|
1149
1149
|
var isDifferentView = view !== this.currentView;
|
1150
|
-
var preventDestroy
|
1151
|
-
var forceShow
|
1152
|
-
|
1153
|
-
//
|
1150
|
+
var preventDestroy = !!showOptions.preventDestroy;
|
1151
|
+
var forceShow = !!showOptions.forceShow;
|
1152
|
+
|
1153
|
+
// We are only changing the view if there is a current view to change to begin with
|
1154
1154
|
var isChangingView = !!this.currentView;
|
1155
|
-
|
1156
|
-
//
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1155
|
+
|
1156
|
+
// Only destroy the current view if we don't want to `preventDestroy` and if
|
1157
|
+
// the view given in the first argument is different than `currentView`
|
1158
|
+
var _shouldDestroyView = isDifferentView && !preventDestroy;
|
1159
|
+
|
1160
|
+
// Only show the view given in the first argument if it is different than
|
1161
|
+
// the current view or if we want to re-show the view. Note that if
|
1162
|
+
// `_shouldDestroyView` is true, then `_shouldShowView` is also necessarily true.
|
1160
1163
|
var _shouldShowView = isDifferentView || forceShow;
|
1161
|
-
|
1164
|
+
|
1162
1165
|
if (isChangingView) {
|
1163
1166
|
this.triggerMethod('before:swapOut', this.currentView);
|
1164
1167
|
}
|
1165
|
-
|
1168
|
+
|
1166
1169
|
if (_shouldDestroyView) {
|
1167
1170
|
this.empty();
|
1168
1171
|
}
|
1169
|
-
|
1172
|
+
|
1170
1173
|
if (_shouldShowView) {
|
1171
|
-
|
1174
|
+
|
1172
1175
|
// We need to listen for if a view is destroyed
|
1173
1176
|
// in a way other than through the region.
|
1174
1177
|
// If this happens we need to remove the reference
|
1175
1178
|
// to the currentView since once a view has been destroyed
|
1176
1179
|
// we can not reuse it.
|
1177
|
-
view.once('destroy',
|
1180
|
+
view.once('destroy', this.empty, this);
|
1178
1181
|
view.render();
|
1179
|
-
|
1182
|
+
|
1180
1183
|
if (isChangingView) {
|
1181
1184
|
this.triggerMethod('before:swap', view);
|
1182
1185
|
}
|
1183
|
-
|
1186
|
+
|
1184
1187
|
this.triggerMethod('before:show', view);
|
1185
1188
|
Marionette.triggerMethodOn(view, 'before:show');
|
1186
|
-
|
1189
|
+
|
1190
|
+
this.attachHtml(view);
|
1191
|
+
|
1187
1192
|
if (isChangingView) {
|
1188
1193
|
this.triggerMethod('swapOut', this.currentView);
|
1189
1194
|
}
|
1190
|
-
|
1191
|
-
this.attachHtml(view);
|
1195
|
+
|
1192
1196
|
this.currentView = view;
|
1193
|
-
|
1197
|
+
|
1194
1198
|
if (isChangingView) {
|
1195
1199
|
this.triggerMethod('swap', view);
|
1196
1200
|
}
|
1197
|
-
|
1201
|
+
|
1198
1202
|
this.triggerMethod('show', view);
|
1199
1203
|
Marionette.triggerMethodOn(view, 'show');
|
1200
|
-
|
1204
|
+
|
1201
1205
|
return this;
|
1202
1206
|
}
|
1203
|
-
|
1207
|
+
|
1204
1208
|
return this;
|
1205
1209
|
},
|
1206
|
-
|
1210
|
+
|
1207
1211
|
_ensureElement: function(){
|
1208
1212
|
if (!_.isObject(this.el)) {
|
1209
1213
|
this.$el = this.getEl(this.el);
|
1210
1214
|
this.el = this.$el[0];
|
1211
1215
|
}
|
1212
|
-
|
1216
|
+
|
1213
1217
|
if (!this.$el || this.$el.length === 0) {
|
1214
1218
|
throw new Marionette.Error('An "el" ' + this.$el.selector + ' must exist in DOM');
|
1215
1219
|
}
|
1216
1220
|
},
|
1217
|
-
|
1221
|
+
|
1218
1222
|
// Override this method to change how the region finds the
|
1219
1223
|
// DOM element that it manages. Return a jQuery selector object.
|
1220
1224
|
getEl: function(el) {
|
1221
1225
|
return Backbone.$(el);
|
1222
1226
|
},
|
1223
|
-
|
1227
|
+
|
1224
1228
|
// Override this method to change how the new view is
|
1225
1229
|
// appended to the `$el` that the region is managing
|
1226
1230
|
attachHtml: function(view) {
|
@@ -1228,37 +1232,38 @@
|
|
1228
1232
|
this.el.innerHTML='';
|
1229
1233
|
this.el.appendChild(view.el);
|
1230
1234
|
},
|
1231
|
-
|
1235
|
+
|
1232
1236
|
// Destroy the current view, if there is one. If there is no
|
1233
1237
|
// current view, it does nothing and returns immediately.
|
1234
1238
|
empty: function() {
|
1235
1239
|
var view = this.currentView;
|
1236
|
-
|
1240
|
+
|
1237
1241
|
// If there is no view in the region
|
1238
1242
|
// we should not remove anything
|
1239
1243
|
if (!view) { return; }
|
1240
|
-
|
1244
|
+
|
1245
|
+
view.off('destroy', this.empty, this);
|
1241
1246
|
this.triggerMethod('before:empty', view);
|
1242
1247
|
this._destroyView();
|
1243
1248
|
this.triggerMethod('empty', view);
|
1244
|
-
|
1249
|
+
|
1245
1250
|
// Remove region pointer to the currentView
|
1246
1251
|
delete this.currentView;
|
1247
1252
|
return this;
|
1248
1253
|
},
|
1249
|
-
|
1254
|
+
|
1250
1255
|
// call 'destroy' or 'remove', depending on which is found
|
1251
1256
|
// on the view (if showing a raw Backbone view or a Marionette View)
|
1252
1257
|
_destroyView: function() {
|
1253
1258
|
var view = this.currentView;
|
1254
|
-
|
1259
|
+
|
1255
1260
|
if (view.destroy && !view.isDestroyed) {
|
1256
1261
|
view.destroy();
|
1257
1262
|
} else if (view.remove) {
|
1258
1263
|
view.remove();
|
1259
1264
|
}
|
1260
1265
|
},
|
1261
|
-
|
1266
|
+
|
1262
1267
|
// Attach an existing view to the region. This
|
1263
1268
|
// will not call `render` or `onShow` for the new view,
|
1264
1269
|
// and will not replace the current HTML for the `el`
|
@@ -1267,52 +1272,52 @@
|
|
1267
1272
|
this.currentView = view;
|
1268
1273
|
return this;
|
1269
1274
|
},
|
1270
|
-
|
1275
|
+
|
1271
1276
|
// Checks whether a view is currently present within
|
1272
1277
|
// the region. Returns `true` if there is and `false` if
|
1273
1278
|
// no view is present.
|
1274
1279
|
hasView: function() {
|
1275
1280
|
return !!this.currentView;
|
1276
1281
|
},
|
1277
|
-
|
1282
|
+
|
1278
1283
|
// Reset the region by destroying any existing view and
|
1279
1284
|
// clearing out the cached `$el`. The next time a view
|
1280
1285
|
// is shown via this region, the region will re-query the
|
1281
1286
|
// DOM for the region's `el`.
|
1282
1287
|
reset: function() {
|
1283
1288
|
this.empty();
|
1284
|
-
|
1289
|
+
|
1285
1290
|
if (this.$el) {
|
1286
1291
|
this.el = this.$el.selector;
|
1287
1292
|
}
|
1288
|
-
|
1293
|
+
|
1289
1294
|
delete this.$el;
|
1290
1295
|
return this;
|
1291
1296
|
},
|
1292
|
-
|
1297
|
+
|
1293
1298
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1294
1299
|
getOption: Marionette.proxyGetOption,
|
1295
|
-
|
1300
|
+
|
1296
1301
|
// import the `triggerMethod` to trigger events with corresponding
|
1297
1302
|
// methods if the method exists
|
1298
1303
|
triggerMethod: Marionette.triggerMethod
|
1299
1304
|
});
|
1300
|
-
|
1305
|
+
|
1301
1306
|
// Copy the `extend` function used by Backbone's classes
|
1302
1307
|
Marionette.Region.extend = Marionette.extend;
|
1303
|
-
|
1308
|
+
|
1304
1309
|
// Marionette.RegionManager
|
1305
1310
|
// ------------------------
|
1306
1311
|
//
|
1307
1312
|
// Manage one or more related `Marionette.Region` objects.
|
1308
1313
|
Marionette.RegionManager = (function(Marionette) {
|
1309
|
-
|
1314
|
+
|
1310
1315
|
var RegionManager = Marionette.Controller.extend({
|
1311
1316
|
constructor: function(options) {
|
1312
1317
|
this._regions = {};
|
1313
1318
|
Marionette.Controller.call(this, options);
|
1314
1319
|
},
|
1315
|
-
|
1320
|
+
|
1316
1321
|
// Add multiple regions using an object literal or a
|
1317
1322
|
// function that returns an object literal, where
|
1318
1323
|
// each key becomes the region name, and each value is
|
@@ -1321,63 +1326,63 @@
|
|
1321
1326
|
if (_.isFunction(regionDefinitions)) {
|
1322
1327
|
regionDefinitions = regionDefinitions.apply(this, arguments);
|
1323
1328
|
}
|
1324
|
-
|
1329
|
+
|
1325
1330
|
var regions = {};
|
1326
|
-
|
1331
|
+
|
1327
1332
|
_.each(regionDefinitions, function(definition, name) {
|
1328
1333
|
if (_.isString(definition)) {
|
1329
1334
|
definition = {selector: definition};
|
1330
1335
|
}
|
1331
|
-
|
1336
|
+
|
1332
1337
|
if (definition.selector) {
|
1333
1338
|
definition = _.defaults({}, definition, defaults);
|
1334
1339
|
}
|
1335
|
-
|
1340
|
+
|
1336
1341
|
var region = this.addRegion(name, definition);
|
1337
1342
|
regions[name] = region;
|
1338
1343
|
}, this);
|
1339
|
-
|
1344
|
+
|
1340
1345
|
return regions;
|
1341
1346
|
},
|
1342
|
-
|
1347
|
+
|
1343
1348
|
// Add an individual region to the region manager,
|
1344
1349
|
// and return the region instance
|
1345
1350
|
addRegion: function(name, definition) {
|
1346
1351
|
var region;
|
1347
|
-
|
1352
|
+
|
1348
1353
|
if (definition instanceof Marionette.Region) {
|
1349
1354
|
region = definition;
|
1350
1355
|
} else {
|
1351
1356
|
region = Marionette.Region.buildRegion(definition, Marionette.Region);
|
1352
1357
|
}
|
1353
|
-
|
1358
|
+
|
1354
1359
|
this.triggerMethod('before:add:region', name, region);
|
1355
|
-
|
1360
|
+
|
1356
1361
|
this._store(name, region);
|
1357
|
-
|
1362
|
+
|
1358
1363
|
this.triggerMethod('add:region', name, region);
|
1359
1364
|
return region;
|
1360
1365
|
},
|
1361
|
-
|
1366
|
+
|
1362
1367
|
// Get a region by name
|
1363
1368
|
get: function(name) {
|
1364
1369
|
return this._regions[name];
|
1365
1370
|
},
|
1366
|
-
|
1371
|
+
|
1367
1372
|
// Gets all the regions contained within
|
1368
1373
|
// the `regionManager` instance.
|
1369
1374
|
getRegions: function(){
|
1370
1375
|
return _.clone(this._regions);
|
1371
1376
|
},
|
1372
|
-
|
1377
|
+
|
1373
1378
|
// Remove a region by name
|
1374
1379
|
removeRegion: function(name) {
|
1375
1380
|
var region = this._regions[name];
|
1376
1381
|
this._remove(name, region);
|
1377
|
-
|
1382
|
+
|
1378
1383
|
return region;
|
1379
1384
|
},
|
1380
|
-
|
1385
|
+
|
1381
1386
|
// Empty all regions in the region manager, and
|
1382
1387
|
// remove them
|
1383
1388
|
removeRegions: function() {
|
@@ -1385,10 +1390,10 @@
|
|
1385
1390
|
_.each(this._regions, function(region, name) {
|
1386
1391
|
this._remove(name, region);
|
1387
1392
|
}, this);
|
1388
|
-
|
1393
|
+
|
1389
1394
|
return regions;
|
1390
1395
|
},
|
1391
|
-
|
1396
|
+
|
1392
1397
|
// Empty all regions in the region manager, but
|
1393
1398
|
// leave them attached
|
1394
1399
|
emptyRegions: function() {
|
@@ -1396,23 +1401,23 @@
|
|
1396
1401
|
_.each(regions, function(region) {
|
1397
1402
|
region.empty();
|
1398
1403
|
}, this);
|
1399
|
-
|
1404
|
+
|
1400
1405
|
return regions;
|
1401
1406
|
},
|
1402
|
-
|
1407
|
+
|
1403
1408
|
// Destroy all regions and shut down the region
|
1404
1409
|
// manager entirely
|
1405
1410
|
destroy: function() {
|
1406
1411
|
this.removeRegions();
|
1407
1412
|
return Marionette.Controller.prototype.destroy.apply(this, arguments);
|
1408
1413
|
},
|
1409
|
-
|
1414
|
+
|
1410
1415
|
// internal method to store regions
|
1411
1416
|
_store: function(name, region) {
|
1412
1417
|
this._regions[name] = region;
|
1413
1418
|
this._setLength();
|
1414
1419
|
},
|
1415
|
-
|
1420
|
+
|
1416
1421
|
// internal method to remove a region
|
1417
1422
|
_remove: function(name, region) {
|
1418
1423
|
this.triggerMethod('before:remove:region', name, region);
|
@@ -1422,49 +1427,49 @@
|
|
1422
1427
|
this._setLength();
|
1423
1428
|
this.triggerMethod('remove:region', name, region);
|
1424
1429
|
},
|
1425
|
-
|
1430
|
+
|
1426
1431
|
// set the number of regions current held
|
1427
1432
|
_setLength: function() {
|
1428
1433
|
this.length = _.size(this._regions);
|
1429
1434
|
}
|
1430
|
-
|
1435
|
+
|
1431
1436
|
});
|
1432
|
-
|
1437
|
+
|
1433
1438
|
Marionette.actAsCollection(RegionManager.prototype, '_regions');
|
1434
|
-
|
1439
|
+
|
1435
1440
|
return RegionManager;
|
1436
1441
|
})(Marionette);
|
1437
|
-
|
1442
|
+
|
1438
1443
|
|
1439
1444
|
// Template Cache
|
1440
1445
|
// --------------
|
1441
|
-
|
1446
|
+
|
1442
1447
|
// Manage templates stored in `<script>` blocks,
|
1443
1448
|
// caching them for faster access.
|
1444
1449
|
Marionette.TemplateCache = function(templateId) {
|
1445
1450
|
this.templateId = templateId;
|
1446
1451
|
};
|
1447
|
-
|
1452
|
+
|
1448
1453
|
// TemplateCache object-level methods. Manage the template
|
1449
1454
|
// caches from these method calls instead of creating
|
1450
1455
|
// your own TemplateCache instances
|
1451
1456
|
_.extend(Marionette.TemplateCache, {
|
1452
1457
|
templateCaches: {},
|
1453
|
-
|
1458
|
+
|
1454
1459
|
// Get the specified template by id. Either
|
1455
1460
|
// retrieves the cached version, or loads it
|
1456
1461
|
// from the DOM.
|
1457
1462
|
get: function(templateId) {
|
1458
1463
|
var cachedTemplate = this.templateCaches[templateId];
|
1459
|
-
|
1464
|
+
|
1460
1465
|
if (!cachedTemplate) {
|
1461
1466
|
cachedTemplate = new Marionette.TemplateCache(templateId);
|
1462
1467
|
this.templateCaches[templateId] = cachedTemplate;
|
1463
1468
|
}
|
1464
|
-
|
1469
|
+
|
1465
1470
|
return cachedTemplate.load();
|
1466
1471
|
},
|
1467
|
-
|
1472
|
+
|
1468
1473
|
// Clear templates from the cache. If no arguments
|
1469
1474
|
// are specified, clears all templates:
|
1470
1475
|
// `clear()`
|
@@ -1476,7 +1481,7 @@
|
|
1476
1481
|
var i;
|
1477
1482
|
var args = slice.call(arguments);
|
1478
1483
|
var length = args.length;
|
1479
|
-
|
1484
|
+
|
1480
1485
|
if (length > 0) {
|
1481
1486
|
for (i = 0; i < length; i++) {
|
1482
1487
|
delete this.templateCaches[args[i]];
|
@@ -1486,26 +1491,26 @@
|
|
1486
1491
|
}
|
1487
1492
|
}
|
1488
1493
|
});
|
1489
|
-
|
1494
|
+
|
1490
1495
|
// TemplateCache instance methods, allowing each
|
1491
1496
|
// template cache object to manage its own state
|
1492
1497
|
// and know whether or not it has been loaded
|
1493
1498
|
_.extend(Marionette.TemplateCache.prototype, {
|
1494
|
-
|
1499
|
+
|
1495
1500
|
// Internal method to load the template
|
1496
1501
|
load: function() {
|
1497
1502
|
// Guard clause to prevent loading this template more than once
|
1498
1503
|
if (this.compiledTemplate) {
|
1499
1504
|
return this.compiledTemplate;
|
1500
1505
|
}
|
1501
|
-
|
1506
|
+
|
1502
1507
|
// Load the template and compile it
|
1503
1508
|
var template = this.loadTemplate(this.templateId);
|
1504
1509
|
this.compiledTemplate = this.compileTemplate(template);
|
1505
|
-
|
1510
|
+
|
1506
1511
|
return this.compiledTemplate;
|
1507
1512
|
},
|
1508
|
-
|
1513
|
+
|
1509
1514
|
// Load a template from the DOM, by default. Override
|
1510
1515
|
// this method to provide your own template retrieval
|
1511
1516
|
// For asynchronous loading with AMD/RequireJS, consider
|
@@ -1513,17 +1518,17 @@
|
|
1513
1518
|
// https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs
|
1514
1519
|
loadTemplate: function(templateId) {
|
1515
1520
|
var template = Backbone.$(templateId).html();
|
1516
|
-
|
1521
|
+
|
1517
1522
|
if (!template || template.length === 0) {
|
1518
1523
|
throw new Marionette.Error({
|
1519
1524
|
name: 'NoTemplateError',
|
1520
1525
|
message: 'Could not find template: "' + templateId + '"'
|
1521
1526
|
});
|
1522
1527
|
}
|
1523
|
-
|
1528
|
+
|
1524
1529
|
return template;
|
1525
1530
|
},
|
1526
|
-
|
1531
|
+
|
1527
1532
|
// Pre-compile the template before caching it. Override
|
1528
1533
|
// this method if you do not need to pre-compile a template
|
1529
1534
|
// (JST / RequireJS for example) or if you want to change
|
@@ -1532,14 +1537,14 @@
|
|
1532
1537
|
return _.template(rawTemplate);
|
1533
1538
|
}
|
1534
1539
|
});
|
1535
|
-
|
1540
|
+
|
1536
1541
|
// Renderer
|
1537
1542
|
// --------
|
1538
|
-
|
1543
|
+
|
1539
1544
|
// Render a template with data by passing in the template
|
1540
1545
|
// selector and the data to render.
|
1541
1546
|
Marionette.Renderer = {
|
1542
|
-
|
1547
|
+
|
1543
1548
|
// Render a template with data. The `template` parameter is
|
1544
1549
|
// passed to the `TemplateCache` object to retrieve the
|
1545
1550
|
// template function. Override this method to provide your own
|
@@ -1551,43 +1556,43 @@
|
|
1551
1556
|
message: 'Cannot render the template since its false, null or undefined.'
|
1552
1557
|
});
|
1553
1558
|
}
|
1554
|
-
|
1559
|
+
|
1555
1560
|
var templateFunc;
|
1556
1561
|
if (typeof template === 'function') {
|
1557
1562
|
templateFunc = template;
|
1558
1563
|
} else {
|
1559
1564
|
templateFunc = Marionette.TemplateCache.get(template);
|
1560
1565
|
}
|
1561
|
-
|
1566
|
+
|
1562
1567
|
return templateFunc(data);
|
1563
1568
|
}
|
1564
1569
|
};
|
1565
|
-
|
1570
|
+
|
1566
1571
|
|
1567
1572
|
/* jshint maxlen: 114, nonew: false */
|
1568
1573
|
// Marionette.View
|
1569
1574
|
// ---------------
|
1570
|
-
|
1575
|
+
|
1571
1576
|
// The core view class that other Marionette views extend from.
|
1572
1577
|
Marionette.View = Backbone.View.extend({
|
1573
|
-
|
1578
|
+
|
1574
1579
|
constructor: function(options) {
|
1575
1580
|
_.bindAll(this, 'render');
|
1576
|
-
|
1581
|
+
|
1577
1582
|
// this exposes view options to the view initializer
|
1578
1583
|
// this is a backfill since backbone removed the assignment
|
1579
1584
|
// of this.options
|
1580
1585
|
// at some point however this may be removed
|
1581
1586
|
this.options = _.extend({}, _.result(this, 'options'), _.isFunction(options) ? options.call(this) : options);
|
1582
|
-
|
1587
|
+
|
1583
1588
|
this._behaviors = Marionette.Behaviors(this);
|
1584
|
-
|
1589
|
+
|
1585
1590
|
Backbone.View.apply(this, arguments);
|
1586
|
-
|
1591
|
+
|
1587
1592
|
Marionette.MonitorDOMRefresh(this);
|
1588
1593
|
this.listenTo(this, 'show', this.onShowCalled);
|
1589
1594
|
},
|
1590
|
-
|
1595
|
+
|
1591
1596
|
// Get the template for this view
|
1592
1597
|
// instance. You can set a `template` attribute in the view
|
1593
1598
|
// definition or pass a `template: "whatever"` parameter in
|
@@ -1595,13 +1600,13 @@
|
|
1595
1600
|
getTemplate: function() {
|
1596
1601
|
return this.getOption('template');
|
1597
1602
|
},
|
1598
|
-
|
1603
|
+
|
1599
1604
|
// Serialize a model by returning its attributes. Clones
|
1600
1605
|
// the attributes to allow modification.
|
1601
1606
|
serializeModel: function(model){
|
1602
1607
|
return model.toJSON.apply(model, slice.call(arguments, 1));
|
1603
1608
|
},
|
1604
|
-
|
1609
|
+
|
1605
1610
|
// Mix in template helper methods. Looks for a
|
1606
1611
|
// `templateHelpers` attribute, which can either be an
|
1607
1612
|
// object literal, or a function that returns an object
|
@@ -1615,7 +1620,7 @@
|
|
1615
1620
|
}
|
1616
1621
|
return _.extend(target, templateHelpers);
|
1617
1622
|
},
|
1618
|
-
|
1623
|
+
|
1619
1624
|
// normalize the keys of passed hash with the views `ui` selectors.
|
1620
1625
|
// `{"@ui.foo": "bar"}`
|
1621
1626
|
normalizeUIKeys: function(hash) {
|
@@ -1623,7 +1628,7 @@
|
|
1623
1628
|
var uiBindings = _.result(this, '_uiBindings');
|
1624
1629
|
return Marionette.normalizeUIKeys(hash, uiBindings || ui);
|
1625
1630
|
},
|
1626
|
-
|
1631
|
+
|
1627
1632
|
// normalize the values of passed hash with the views `ui` selectors.
|
1628
1633
|
// `{foo: "@ui.bar"}`
|
1629
1634
|
normalizeUIValues: function(hash) {
|
@@ -1631,83 +1636,83 @@
|
|
1631
1636
|
var uiBindings = _.result(this, '_uiBindings');
|
1632
1637
|
return Marionette.normalizeUIValues(hash, uiBindings || ui);
|
1633
1638
|
},
|
1634
|
-
|
1639
|
+
|
1635
1640
|
// Configure `triggers` to forward DOM events to view
|
1636
1641
|
// events. `triggers: {"click .foo": "do:foo"}`
|
1637
1642
|
configureTriggers: function() {
|
1638
1643
|
if (!this.triggers) { return; }
|
1639
|
-
|
1644
|
+
|
1640
1645
|
var triggerEvents = {};
|
1641
|
-
|
1646
|
+
|
1642
1647
|
// Allow `triggers` to be configured as a function
|
1643
1648
|
var triggers = this.normalizeUIKeys(_.result(this, 'triggers'));
|
1644
|
-
|
1649
|
+
|
1645
1650
|
// Configure the triggers, prevent default
|
1646
1651
|
// action and stop propagation of DOM events
|
1647
1652
|
_.each(triggers, function(value, key) {
|
1648
1653
|
triggerEvents[key] = this._buildViewTrigger(value);
|
1649
1654
|
}, this);
|
1650
|
-
|
1655
|
+
|
1651
1656
|
return triggerEvents;
|
1652
1657
|
},
|
1653
|
-
|
1658
|
+
|
1654
1659
|
// Overriding Backbone.View's delegateEvents to handle
|
1655
1660
|
// the `triggers`, `modelEvents`, and `collectionEvents` configuration
|
1656
1661
|
delegateEvents: function(events) {
|
1657
1662
|
this._delegateDOMEvents(events);
|
1658
1663
|
this.bindEntityEvents(this.model, this.getOption('modelEvents'));
|
1659
1664
|
this.bindEntityEvents(this.collection, this.getOption('collectionEvents'));
|
1660
|
-
|
1665
|
+
|
1661
1666
|
_.each(this._behaviors, function(behavior) {
|
1662
1667
|
behavior.bindEntityEvents(this.model, behavior.getOption('modelEvents'));
|
1663
1668
|
behavior.bindEntityEvents(this.collection, behavior.getOption('collectionEvents'));
|
1664
1669
|
}, this);
|
1665
|
-
|
1670
|
+
|
1666
1671
|
return this;
|
1667
1672
|
},
|
1668
|
-
|
1673
|
+
|
1669
1674
|
// internal method to delegate DOM events and triggers
|
1670
1675
|
_delegateDOMEvents: function(eventsArg) {
|
1671
1676
|
var events = eventsArg || this.events;
|
1672
1677
|
if (_.isFunction(events)) { events = events.call(this); }
|
1673
|
-
|
1678
|
+
|
1674
1679
|
// normalize ui keys
|
1675
1680
|
events = this.normalizeUIKeys(events);
|
1676
1681
|
if(_.isUndefined(eventsArg)) {this.events = events;}
|
1677
|
-
|
1682
|
+
|
1678
1683
|
var combinedEvents = {};
|
1679
|
-
|
1684
|
+
|
1680
1685
|
// look up if this view has behavior events
|
1681
1686
|
var behaviorEvents = _.result(this, 'behaviorEvents') || {};
|
1682
1687
|
var triggers = this.configureTriggers();
|
1683
1688
|
var behaviorTriggers = _.result(this, 'behaviorTriggers') || {};
|
1684
|
-
|
1689
|
+
|
1685
1690
|
// behavior events will be overriden by view events and or triggers
|
1686
1691
|
_.extend(combinedEvents, behaviorEvents, events, triggers, behaviorTriggers);
|
1687
|
-
|
1692
|
+
|
1688
1693
|
Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
|
1689
1694
|
},
|
1690
|
-
|
1695
|
+
|
1691
1696
|
// Overriding Backbone.View's undelegateEvents to handle unbinding
|
1692
1697
|
// the `triggers`, `modelEvents`, and `collectionEvents` config
|
1693
1698
|
undelegateEvents: function() {
|
1694
1699
|
var args = slice.call(arguments);
|
1695
1700
|
Backbone.View.prototype.undelegateEvents.apply(this, args);
|
1696
|
-
|
1701
|
+
|
1697
1702
|
this.unbindEntityEvents(this.model, this.getOption('modelEvents'));
|
1698
1703
|
this.unbindEntityEvents(this.collection, this.getOption('collectionEvents'));
|
1699
|
-
|
1704
|
+
|
1700
1705
|
_.each(this._behaviors, function(behavior) {
|
1701
1706
|
behavior.unbindEntityEvents(this.model, behavior.getOption('modelEvents'));
|
1702
1707
|
behavior.unbindEntityEvents(this.collection, behavior.getOption('collectionEvents'));
|
1703
1708
|
}, this);
|
1704
|
-
|
1709
|
+
|
1705
1710
|
return this;
|
1706
1711
|
},
|
1707
|
-
|
1712
|
+
|
1708
1713
|
// Internal method, handles the `show` event.
|
1709
1714
|
onShowCalled: function() {},
|
1710
|
-
|
1715
|
+
|
1711
1716
|
// Internal helper method to verify whether the view hasn't been destroyed
|
1712
1717
|
_ensureViewIsIntact: function() {
|
1713
1718
|
if (this.isDestroyed) {
|
@@ -1717,173 +1722,173 @@
|
|
1717
1722
|
});
|
1718
1723
|
}
|
1719
1724
|
},
|
1720
|
-
|
1725
|
+
|
1721
1726
|
// Default `destroy` implementation, for removing a view from the
|
1722
1727
|
// DOM and unbinding it. Regions will call this method
|
1723
1728
|
// for you. You can specify an `onDestroy` method in your view to
|
1724
1729
|
// add custom code that is called after the view is destroyed.
|
1725
1730
|
destroy: function() {
|
1726
1731
|
if (this.isDestroyed) { return; }
|
1727
|
-
|
1732
|
+
|
1728
1733
|
var args = slice.call(arguments);
|
1729
|
-
|
1734
|
+
|
1730
1735
|
this.triggerMethod.apply(this, ['before:destroy'].concat(args));
|
1731
|
-
|
1736
|
+
|
1732
1737
|
// mark as destroyed before doing the actual destroy, to
|
1733
1738
|
// prevent infinite loops within "destroy" event handlers
|
1734
1739
|
// that are trying to destroy other views
|
1735
1740
|
this.isDestroyed = true;
|
1736
1741
|
this.triggerMethod.apply(this, ['destroy'].concat(args));
|
1737
|
-
|
1742
|
+
|
1738
1743
|
// unbind UI elements
|
1739
1744
|
this.unbindUIElements();
|
1740
|
-
|
1745
|
+
|
1741
1746
|
// remove the view from the DOM
|
1742
1747
|
this.remove();
|
1743
|
-
|
1748
|
+
|
1744
1749
|
// Call destroy on each behavior after
|
1745
1750
|
// destroying the view.
|
1746
1751
|
// This unbinds event listeners
|
1747
1752
|
// that behaviors have registered for.
|
1748
1753
|
_.invoke(this._behaviors, 'destroy', args);
|
1749
|
-
|
1754
|
+
|
1750
1755
|
return this;
|
1751
1756
|
},
|
1752
|
-
|
1757
|
+
|
1753
1758
|
bindUIElements: function() {
|
1754
1759
|
this._bindUIElements();
|
1755
1760
|
_.invoke(this._behaviors, this._bindUIElements);
|
1756
1761
|
},
|
1757
|
-
|
1762
|
+
|
1758
1763
|
// This method binds the elements specified in the "ui" hash inside the view's code with
|
1759
1764
|
// the associated jQuery selectors.
|
1760
1765
|
_bindUIElements: function() {
|
1761
1766
|
if (!this.ui) { return; }
|
1762
|
-
|
1767
|
+
|
1763
1768
|
// store the ui hash in _uiBindings so they can be reset later
|
1764
1769
|
// and so re-rendering the view will be able to find the bindings
|
1765
1770
|
if (!this._uiBindings) {
|
1766
1771
|
this._uiBindings = this.ui;
|
1767
1772
|
}
|
1768
|
-
|
1773
|
+
|
1769
1774
|
// get the bindings result, as a function or otherwise
|
1770
1775
|
var bindings = _.result(this, '_uiBindings');
|
1771
|
-
|
1776
|
+
|
1772
1777
|
// empty the ui so we don't have anything to start with
|
1773
1778
|
this.ui = {};
|
1774
|
-
|
1779
|
+
|
1775
1780
|
// bind each of the selectors
|
1776
1781
|
_.each(_.keys(bindings), function(key) {
|
1777
1782
|
var selector = bindings[key];
|
1778
1783
|
this.ui[key] = this.$(selector);
|
1779
1784
|
}, this);
|
1780
1785
|
},
|
1781
|
-
|
1786
|
+
|
1782
1787
|
// This method unbinds the elements specified in the "ui" hash
|
1783
1788
|
unbindUIElements: function() {
|
1784
1789
|
this._unbindUIElements();
|
1785
1790
|
_.invoke(this._behaviors, this._unbindUIElements);
|
1786
1791
|
},
|
1787
|
-
|
1792
|
+
|
1788
1793
|
_unbindUIElements: function() {
|
1789
1794
|
if (!this.ui || !this._uiBindings) { return; }
|
1790
|
-
|
1795
|
+
|
1791
1796
|
// delete all of the existing ui bindings
|
1792
1797
|
_.each(this.ui, function($el, name) {
|
1793
1798
|
delete this.ui[name];
|
1794
1799
|
}, this);
|
1795
|
-
|
1800
|
+
|
1796
1801
|
// reset the ui element to the original bindings configuration
|
1797
1802
|
this.ui = this._uiBindings;
|
1798
1803
|
delete this._uiBindings;
|
1799
1804
|
},
|
1800
|
-
|
1805
|
+
|
1801
1806
|
// Internal method to create an event handler for a given `triggerDef` like
|
1802
1807
|
// 'click:foo'
|
1803
1808
|
_buildViewTrigger: function(triggerDef) {
|
1804
1809
|
var hasOptions = _.isObject(triggerDef);
|
1805
|
-
|
1810
|
+
|
1806
1811
|
var options = _.defaults({}, (hasOptions ? triggerDef : {}), {
|
1807
1812
|
preventDefault: true,
|
1808
1813
|
stopPropagation: true
|
1809
1814
|
});
|
1810
|
-
|
1815
|
+
|
1811
1816
|
var eventName = hasOptions ? options.event : triggerDef;
|
1812
|
-
|
1817
|
+
|
1813
1818
|
return function(e) {
|
1814
1819
|
if (e) {
|
1815
1820
|
if (e.preventDefault && options.preventDefault) {
|
1816
1821
|
e.preventDefault();
|
1817
1822
|
}
|
1818
|
-
|
1823
|
+
|
1819
1824
|
if (e.stopPropagation && options.stopPropagation) {
|
1820
1825
|
e.stopPropagation();
|
1821
1826
|
}
|
1822
1827
|
}
|
1823
|
-
|
1828
|
+
|
1824
1829
|
var args = {
|
1825
1830
|
view: this,
|
1826
1831
|
model: this.model,
|
1827
1832
|
collection: this.collection
|
1828
1833
|
};
|
1829
|
-
|
1834
|
+
|
1830
1835
|
this.triggerMethod(eventName, args);
|
1831
1836
|
};
|
1832
1837
|
},
|
1833
|
-
|
1838
|
+
|
1834
1839
|
setElement: function() {
|
1835
1840
|
var ret = Backbone.View.prototype.setElement.apply(this, arguments);
|
1836
|
-
|
1841
|
+
|
1837
1842
|
// proxy behavior $el to the view's $el.
|
1838
1843
|
// This is needed because a view's $el proxy
|
1839
1844
|
// is not set until after setElement is called.
|
1840
1845
|
_.invoke(this._behaviors, 'proxyViewProperties', this);
|
1841
|
-
|
1846
|
+
|
1842
1847
|
return ret;
|
1843
1848
|
},
|
1844
|
-
|
1849
|
+
|
1845
1850
|
// import the `triggerMethod` to trigger events with corresponding
|
1846
1851
|
// methods if the method exists
|
1847
1852
|
triggerMethod: function() {
|
1848
1853
|
var args = arguments;
|
1849
1854
|
var triggerMethod = Marionette.triggerMethod;
|
1850
|
-
|
1855
|
+
|
1851
1856
|
var ret = triggerMethod.apply(this, args);
|
1852
1857
|
_.each(this._behaviors, function(b) {
|
1853
1858
|
triggerMethod.apply(b, args);
|
1854
1859
|
});
|
1855
|
-
|
1860
|
+
|
1856
1861
|
return ret;
|
1857
1862
|
},
|
1858
|
-
|
1863
|
+
|
1859
1864
|
// Imports the "normalizeMethods" to transform hashes of
|
1860
1865
|
// events=>function references/names to a hash of events=>function references
|
1861
1866
|
normalizeMethods: Marionette.normalizeMethods,
|
1862
|
-
|
1867
|
+
|
1863
1868
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1864
1869
|
getOption: Marionette.proxyGetOption,
|
1865
|
-
|
1870
|
+
|
1866
1871
|
// Proxy `unbindEntityEvents` to enable binding view's events from another entity.
|
1867
1872
|
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
1868
|
-
|
1873
|
+
|
1869
1874
|
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
|
1870
1875
|
unbindEntityEvents: Marionette.proxyUnbindEntityEvents
|
1871
1876
|
});
|
1872
|
-
|
1877
|
+
|
1873
1878
|
// Item View
|
1874
1879
|
// ---------
|
1875
|
-
|
1880
|
+
|
1876
1881
|
// A single item view implementation that contains code for rendering
|
1877
1882
|
// with underscore.js templates, serializing the view's model or collection,
|
1878
1883
|
// and calling several methods on extended views, such as `onRender`.
|
1879
1884
|
Marionette.ItemView = Marionette.View.extend({
|
1880
|
-
|
1885
|
+
|
1881
1886
|
// Setting up the inheritance chain which allows changes to
|
1882
1887
|
// Marionette.View.prototype.constructor which allows overriding
|
1883
1888
|
constructor: function() {
|
1884
1889
|
Marionette.View.apply(this, arguments);
|
1885
1890
|
},
|
1886
|
-
|
1891
|
+
|
1887
1892
|
// Serialize the model or collection for the view. If a model is
|
1888
1893
|
// found, the view's `serializeModel` is called. If a collection is found,
|
1889
1894
|
// each model in the collection is serialized by calling
|
@@ -1893,22 +1898,22 @@
|
|
1893
1898
|
// to provide custom serialization for your view's data.
|
1894
1899
|
serializeData: function(){
|
1895
1900
|
var data = {};
|
1896
|
-
|
1901
|
+
|
1897
1902
|
if (this.model) {
|
1898
1903
|
data = _.partial(this.serializeModel, this.model).apply(this, arguments);
|
1899
1904
|
}
|
1900
1905
|
else if (this.collection) {
|
1901
1906
|
data = { items: _.partial(this.serializeCollection, this.collection).apply(this, arguments) };
|
1902
1907
|
}
|
1903
|
-
|
1908
|
+
|
1904
1909
|
return data;
|
1905
1910
|
},
|
1906
|
-
|
1911
|
+
|
1907
1912
|
// Serialize a collection by serializing each of its models.
|
1908
1913
|
serializeCollection: function(collection){
|
1909
1914
|
return collection.toJSON.apply(collection, slice.call(arguments, 1));
|
1910
1915
|
},
|
1911
|
-
|
1916
|
+
|
1912
1917
|
// Render the view, defaulting to underscore.js templates.
|
1913
1918
|
// You can override this in your view definition to provide
|
1914
1919
|
// a very specific rendering for your view. In general, though,
|
@@ -1916,47 +1921,47 @@
|
|
1916
1921
|
// change how Marionette renders views.
|
1917
1922
|
render: function() {
|
1918
1923
|
this._ensureViewIsIntact();
|
1919
|
-
|
1924
|
+
|
1920
1925
|
this.triggerMethod('before:render', this);
|
1921
|
-
|
1926
|
+
|
1922
1927
|
this._renderTemplate();
|
1923
1928
|
this.bindUIElements();
|
1924
|
-
|
1929
|
+
|
1925
1930
|
this.triggerMethod('render', this);
|
1926
|
-
|
1931
|
+
|
1927
1932
|
return this;
|
1928
1933
|
},
|
1929
|
-
|
1934
|
+
|
1930
1935
|
// Internal method to render the template with the serialized data
|
1931
1936
|
// and template helpers via the `Marionette.Renderer` object.
|
1932
1937
|
// Throws an `UndefinedTemplateError` error if the template is
|
1933
1938
|
// any falsely value but literal `false`.
|
1934
1939
|
_renderTemplate: function() {
|
1935
1940
|
var template = this.getTemplate();
|
1936
|
-
|
1941
|
+
|
1937
1942
|
// Allow template-less item views
|
1938
1943
|
if (template === false) {
|
1939
1944
|
return;
|
1940
1945
|
}
|
1941
|
-
|
1946
|
+
|
1942
1947
|
if (!template) {
|
1943
1948
|
throw new Marionette.Error({
|
1944
1949
|
name: 'UndefinedTemplateError',
|
1945
1950
|
message: 'Cannot render the template since it is null or undefined.'
|
1946
1951
|
});
|
1947
1952
|
}
|
1948
|
-
|
1953
|
+
|
1949
1954
|
// Add in entity data and template helpers
|
1950
1955
|
var data = this.serializeData();
|
1951
1956
|
data = this.mixinTemplateHelpers(data);
|
1952
|
-
|
1957
|
+
|
1953
1958
|
// Render and add to el
|
1954
1959
|
var html = Marionette.Renderer.render(template, data, this);
|
1955
1960
|
this.attachElContent(html);
|
1956
|
-
|
1961
|
+
|
1957
1962
|
return this;
|
1958
1963
|
},
|
1959
|
-
|
1964
|
+
|
1960
1965
|
// Attaches the content of a given view.
|
1961
1966
|
// This method can be overridden to optimize rendering,
|
1962
1967
|
// or to render in a non standard way.
|
@@ -1971,32 +1976,32 @@
|
|
1971
1976
|
// ```
|
1972
1977
|
attachElContent: function(html) {
|
1973
1978
|
this.$el.html(html);
|
1974
|
-
|
1979
|
+
|
1975
1980
|
return this;
|
1976
1981
|
},
|
1977
|
-
|
1982
|
+
|
1978
1983
|
// Override the default destroy event to add a few
|
1979
1984
|
// more events that are triggered.
|
1980
1985
|
destroy: function() {
|
1981
1986
|
if (this.isDestroyed) { return; }
|
1982
|
-
|
1987
|
+
|
1983
1988
|
return Marionette.View.prototype.destroy.apply(this, arguments);
|
1984
1989
|
}
|
1985
1990
|
});
|
1986
|
-
|
1991
|
+
|
1987
1992
|
/* jshint maxstatements: 14 */
|
1988
|
-
|
1993
|
+
|
1989
1994
|
// Collection View
|
1990
1995
|
// ---------------
|
1991
|
-
|
1996
|
+
|
1992
1997
|
// A view that iterates over a Backbone.Collection
|
1993
1998
|
// and renders an individual child view for each model.
|
1994
1999
|
Marionette.CollectionView = Marionette.View.extend({
|
1995
|
-
|
2000
|
+
|
1996
2001
|
// used as the prefix for child view events
|
1997
2002
|
// that are forwarded through the collectionview
|
1998
2003
|
childViewEventPrefix: 'childview',
|
1999
|
-
|
2004
|
+
|
2000
2005
|
// constructor
|
2001
2006
|
// option to pass `{sort: false}` to prevent the `CollectionView` from
|
2002
2007
|
// maintaining the sorted order of the collection.
|
@@ -2004,15 +2009,15 @@
|
|
2004
2009
|
constructor: function(options){
|
2005
2010
|
var initOptions = options || {};
|
2006
2011
|
this.sort = _.isUndefined(initOptions.sort) ? true : initOptions.sort;
|
2007
|
-
|
2012
|
+
|
2008
2013
|
this.once('render', this._initialEvents);
|
2009
2014
|
this._initChildViewStorage();
|
2010
|
-
|
2015
|
+
|
2011
2016
|
Marionette.View.apply(this, arguments);
|
2012
|
-
|
2017
|
+
|
2013
2018
|
this.initRenderBuffer();
|
2014
2019
|
},
|
2015
|
-
|
2020
|
+
|
2016
2021
|
// Instead of inserting elements one by one into the page,
|
2017
2022
|
// it's much more performant to insert elements into a document
|
2018
2023
|
// fragment and then insert that document fragment into the page
|
@@ -2020,12 +2025,12 @@
|
|
2020
2025
|
this.elBuffer = document.createDocumentFragment();
|
2021
2026
|
this._bufferedChildren = [];
|
2022
2027
|
},
|
2023
|
-
|
2028
|
+
|
2024
2029
|
startBuffering: function() {
|
2025
2030
|
this.initRenderBuffer();
|
2026
2031
|
this.isBuffering = true;
|
2027
2032
|
},
|
2028
|
-
|
2033
|
+
|
2029
2034
|
endBuffering: function() {
|
2030
2035
|
this.isBuffering = false;
|
2031
2036
|
this._triggerBeforeShowBufferedChildren();
|
@@ -2033,27 +2038,27 @@
|
|
2033
2038
|
this._triggerShowBufferedChildren();
|
2034
2039
|
this.initRenderBuffer();
|
2035
2040
|
},
|
2036
|
-
|
2041
|
+
|
2037
2042
|
_triggerBeforeShowBufferedChildren: function() {
|
2038
2043
|
if (this._isShown) {
|
2039
2044
|
_.each(this._bufferedChildren, _.partial(this._triggerMethodOnChild, 'before:show'));
|
2040
2045
|
}
|
2041
2046
|
},
|
2042
|
-
|
2047
|
+
|
2043
2048
|
_triggerShowBufferedChildren: function() {
|
2044
2049
|
if (this._isShown) {
|
2045
2050
|
_.each(this._bufferedChildren, _.partial(this._triggerMethodOnChild, 'show'));
|
2046
|
-
|
2051
|
+
|
2047
2052
|
this._bufferedChildren = [];
|
2048
2053
|
}
|
2049
2054
|
},
|
2050
|
-
|
2055
|
+
|
2051
2056
|
// Internal method for _.each loops to call `Marionette.triggerMethodOn` on
|
2052
2057
|
// a child view
|
2053
2058
|
_triggerMethodOnChild: function(event, childView) {
|
2054
2059
|
Marionette.triggerMethodOn(childView, event);
|
2055
2060
|
},
|
2056
|
-
|
2061
|
+
|
2057
2062
|
// Configured the initial events that the collection view
|
2058
2063
|
// binds to.
|
2059
2064
|
_initialEvents: function() {
|
@@ -2061,13 +2066,13 @@
|
|
2061
2066
|
this.listenTo(this.collection, 'add', this._onCollectionAdd);
|
2062
2067
|
this.listenTo(this.collection, 'remove', this._onCollectionRemove);
|
2063
2068
|
this.listenTo(this.collection, 'reset', this.render);
|
2064
|
-
|
2069
|
+
|
2065
2070
|
if (this.sort) {
|
2066
2071
|
this.listenTo(this.collection, 'sort', this._sortViews);
|
2067
2072
|
}
|
2068
2073
|
}
|
2069
2074
|
},
|
2070
|
-
|
2075
|
+
|
2071
2076
|
// Handle a child added to the collection
|
2072
2077
|
_onCollectionAdd: function(child) {
|
2073
2078
|
this.destroyEmptyView();
|
@@ -2075,19 +2080,19 @@
|
|
2075
2080
|
var index = this.collection.indexOf(child);
|
2076
2081
|
this.addChild(child, ChildView, index);
|
2077
2082
|
},
|
2078
|
-
|
2083
|
+
|
2079
2084
|
// get the child view by model it holds, and remove it
|
2080
2085
|
_onCollectionRemove: function(model) {
|
2081
2086
|
var view = this.children.findByModel(model);
|
2082
2087
|
this.removeChildView(view);
|
2083
2088
|
this.checkEmpty();
|
2084
2089
|
},
|
2085
|
-
|
2090
|
+
|
2086
2091
|
// Override from `Marionette.View` to trigger show on child views
|
2087
2092
|
onShowCalled: function() {
|
2088
2093
|
this.children.each(_.partial(this._triggerMethodOnChild, 'show'));
|
2089
2094
|
},
|
2090
|
-
|
2095
|
+
|
2091
2096
|
// Render children views. Override this method to
|
2092
2097
|
// provide your own implementation of a render function for
|
2093
2098
|
// the collection view.
|
@@ -2098,7 +2103,7 @@
|
|
2098
2103
|
this.triggerMethod('render', this);
|
2099
2104
|
return this;
|
2100
2105
|
},
|
2101
|
-
|
2106
|
+
|
2102
2107
|
// Render view after sorting. Override this method to
|
2103
2108
|
// change how the view renders after a `sort` on the collection.
|
2104
2109
|
// An example of this would be to only `renderChildren` in a `CompositeView`
|
@@ -2106,7 +2111,7 @@
|
|
2106
2111
|
resortView: function() {
|
2107
2112
|
this.render();
|
2108
2113
|
},
|
2109
|
-
|
2114
|
+
|
2110
2115
|
// Internal method. This checks for any changes in the order of the collection.
|
2111
2116
|
// If the index of any view doesn't match, it will render.
|
2112
2117
|
_sortViews: function() {
|
@@ -2115,19 +2120,19 @@
|
|
2115
2120
|
var view = this.children.findByModel(item);
|
2116
2121
|
return !view || view._index !== index;
|
2117
2122
|
}, this);
|
2118
|
-
|
2123
|
+
|
2119
2124
|
if (orderChanged) {
|
2120
2125
|
this.resortView();
|
2121
2126
|
}
|
2122
2127
|
},
|
2123
|
-
|
2128
|
+
|
2124
2129
|
// Internal method. Separated so that CompositeView can have
|
2125
2130
|
// more control over events being triggered, around the rendering
|
2126
2131
|
// process
|
2127
2132
|
_renderChildren: function() {
|
2128
2133
|
this.destroyEmptyView();
|
2129
2134
|
this.destroyChildren();
|
2130
|
-
|
2135
|
+
|
2131
2136
|
if (this.isEmpty(this.collection)) {
|
2132
2137
|
this.showEmptyView();
|
2133
2138
|
} else {
|
@@ -2138,7 +2143,7 @@
|
|
2138
2143
|
this.triggerMethod('render:collection', this);
|
2139
2144
|
}
|
2140
2145
|
},
|
2141
|
-
|
2146
|
+
|
2142
2147
|
// Internal method to loop through collection and show each child view.
|
2143
2148
|
showCollection: function() {
|
2144
2149
|
var ChildView;
|
@@ -2147,81 +2152,81 @@
|
|
2147
2152
|
this.addChild(child, ChildView, index);
|
2148
2153
|
}, this);
|
2149
2154
|
},
|
2150
|
-
|
2155
|
+
|
2151
2156
|
// Internal method to show an empty view in place of
|
2152
2157
|
// a collection of child views, when the collection is empty
|
2153
2158
|
showEmptyView: function() {
|
2154
2159
|
var EmptyView = this.getEmptyView();
|
2155
|
-
|
2160
|
+
|
2156
2161
|
if (EmptyView && !this._showingEmptyView) {
|
2157
2162
|
this.triggerMethod('before:render:empty');
|
2158
|
-
|
2163
|
+
|
2159
2164
|
this._showingEmptyView = true;
|
2160
2165
|
var model = new Backbone.Model();
|
2161
2166
|
this.addEmptyView(model, EmptyView);
|
2162
|
-
|
2167
|
+
|
2163
2168
|
this.triggerMethod('render:empty');
|
2164
2169
|
}
|
2165
2170
|
},
|
2166
|
-
|
2171
|
+
|
2167
2172
|
// Internal method to destroy an existing emptyView instance
|
2168
2173
|
// if one exists. Called when a collection view has been
|
2169
2174
|
// rendered empty, and then a child is added to the collection.
|
2170
2175
|
destroyEmptyView: function() {
|
2171
2176
|
if (this._showingEmptyView) {
|
2172
2177
|
this.triggerMethod('before:remove:empty');
|
2173
|
-
|
2178
|
+
|
2174
2179
|
this.destroyChildren();
|
2175
2180
|
delete this._showingEmptyView;
|
2176
|
-
|
2181
|
+
|
2177
2182
|
this.triggerMethod('remove:empty');
|
2178
2183
|
}
|
2179
2184
|
},
|
2180
|
-
|
2185
|
+
|
2181
2186
|
// Retrieve the empty view class
|
2182
2187
|
getEmptyView: function() {
|
2183
2188
|
return this.getOption('emptyView');
|
2184
2189
|
},
|
2185
|
-
|
2190
|
+
|
2186
2191
|
// Render and show the emptyView. Similar to addChild method
|
2187
2192
|
// but "child:added" events are not fired, and the event from
|
2188
2193
|
// emptyView are not forwarded
|
2189
2194
|
addEmptyView: function(child, EmptyView) {
|
2190
|
-
|
2195
|
+
|
2191
2196
|
// get the emptyViewOptions, falling back to childViewOptions
|
2192
2197
|
var emptyViewOptions = this.getOption('emptyViewOptions') ||
|
2193
2198
|
this.getOption('childViewOptions');
|
2194
|
-
|
2199
|
+
|
2195
2200
|
if (_.isFunction(emptyViewOptions)){
|
2196
2201
|
emptyViewOptions = emptyViewOptions.call(this);
|
2197
2202
|
}
|
2198
|
-
|
2203
|
+
|
2199
2204
|
// build the empty view
|
2200
2205
|
var view = this.buildChildView(child, EmptyView, emptyViewOptions);
|
2201
|
-
|
2206
|
+
|
2202
2207
|
// Proxy emptyView events
|
2203
2208
|
this.proxyChildEvents(view);
|
2204
|
-
|
2209
|
+
|
2205
2210
|
// trigger the 'before:show' event on `view` if the collection view
|
2206
2211
|
// has already been shown
|
2207
2212
|
if (this._isShown) {
|
2208
2213
|
Marionette.triggerMethodOn(view, 'before:show');
|
2209
2214
|
}
|
2210
|
-
|
2215
|
+
|
2211
2216
|
// Store the `emptyView` like a `childView` so we can properly
|
2212
2217
|
// remove and/or close it later
|
2213
2218
|
this.children.add(view);
|
2214
|
-
|
2219
|
+
|
2215
2220
|
// Render it and show it
|
2216
2221
|
this.renderChildView(view, -1);
|
2217
|
-
|
2222
|
+
|
2218
2223
|
// call the 'show' method if the collection view
|
2219
2224
|
// has already been shown
|
2220
2225
|
if (this._isShown) {
|
2221
2226
|
Marionette.triggerMethodOn(view, 'show');
|
2222
2227
|
}
|
2223
2228
|
},
|
2224
|
-
|
2229
|
+
|
2225
2230
|
// Retrieve the `childView` class, either from `this.options.childView`
|
2226
2231
|
// or from the `childView` in the object definition. The "options"
|
2227
2232
|
// takes precedence.
|
@@ -2230,17 +2235,17 @@
|
|
2230
2235
|
// to determine what `childView` class to return.
|
2231
2236
|
getChildView: function(child) {
|
2232
2237
|
var childView = this.getOption('childView');
|
2233
|
-
|
2238
|
+
|
2234
2239
|
if (!childView) {
|
2235
2240
|
throw new Marionette.Error({
|
2236
2241
|
name: 'NoChildViewError',
|
2237
2242
|
message: 'A "childView" must be specified'
|
2238
2243
|
});
|
2239
2244
|
}
|
2240
|
-
|
2245
|
+
|
2241
2246
|
return childView;
|
2242
2247
|
},
|
2243
|
-
|
2248
|
+
|
2244
2249
|
// Render the child's view and add it to the
|
2245
2250
|
// HTML for the collection view at a given index.
|
2246
2251
|
// This will also update the indices of later views in the collection
|
@@ -2250,28 +2255,28 @@
|
|
2250
2255
|
if (_.isFunction(childViewOptions)) {
|
2251
2256
|
childViewOptions = childViewOptions.call(this, child, index);
|
2252
2257
|
}
|
2253
|
-
|
2258
|
+
|
2254
2259
|
var view = this.buildChildView(child, ChildView, childViewOptions);
|
2255
|
-
|
2260
|
+
|
2256
2261
|
// increment indices of views after this one
|
2257
2262
|
this._updateIndices(view, true, index);
|
2258
|
-
|
2263
|
+
|
2259
2264
|
this._addChildView(view, index);
|
2260
|
-
|
2265
|
+
|
2261
2266
|
return view;
|
2262
2267
|
},
|
2263
|
-
|
2268
|
+
|
2264
2269
|
// Internal method. This decrements or increments the indices of views after the
|
2265
2270
|
// added/removed view to keep in sync with the collection.
|
2266
2271
|
_updateIndices: function(view, increment, index) {
|
2267
2272
|
if (!this.sort) {
|
2268
2273
|
return;
|
2269
2274
|
}
|
2270
|
-
|
2275
|
+
|
2271
2276
|
if (increment) {
|
2272
2277
|
// assign the index to the view
|
2273
2278
|
view._index = index;
|
2274
|
-
|
2279
|
+
|
2275
2280
|
// increment the index of views after this one
|
2276
2281
|
this.children.each(function (laterView) {
|
2277
2282
|
if (laterView._index >= view._index) {
|
@@ -2288,81 +2293,81 @@
|
|
2288
2293
|
});
|
2289
2294
|
}
|
2290
2295
|
},
|
2291
|
-
|
2292
|
-
|
2296
|
+
|
2297
|
+
|
2293
2298
|
// Internal Method. Add the view to children and render it at
|
2294
2299
|
// the given index.
|
2295
2300
|
_addChildView: function(view, index) {
|
2296
2301
|
// set up the child view event forwarding
|
2297
2302
|
this.proxyChildEvents(view);
|
2298
|
-
|
2303
|
+
|
2299
2304
|
this.triggerMethod('before:add:child', view);
|
2300
|
-
|
2305
|
+
|
2301
2306
|
// Store the child view itself so we can properly
|
2302
2307
|
// remove and/or destroy it later
|
2303
2308
|
this.children.add(view);
|
2304
2309
|
this.renderChildView(view, index);
|
2305
|
-
|
2310
|
+
|
2306
2311
|
if (this._isShown && !this.isBuffering) {
|
2307
2312
|
Marionette.triggerMethodOn(view, 'show');
|
2308
2313
|
}
|
2309
|
-
|
2314
|
+
|
2310
2315
|
this.triggerMethod('add:child', view);
|
2311
2316
|
},
|
2312
|
-
|
2317
|
+
|
2313
2318
|
// render the child view
|
2314
2319
|
renderChildView: function(view, index) {
|
2315
2320
|
view.render();
|
2316
2321
|
this.attachHtml(this, view, index);
|
2317
2322
|
return view;
|
2318
2323
|
},
|
2319
|
-
|
2324
|
+
|
2320
2325
|
// Build a `childView` for a model in the collection.
|
2321
2326
|
buildChildView: function(child, ChildViewClass, childViewOptions) {
|
2322
2327
|
var options = _.extend({model: child}, childViewOptions);
|
2323
2328
|
return new ChildViewClass(options);
|
2324
2329
|
},
|
2325
|
-
|
2330
|
+
|
2326
2331
|
// Remove the child view and destroy it.
|
2327
2332
|
// This function also updates the indices of
|
2328
2333
|
// later views in the collection in order to keep
|
2329
2334
|
// the children in sync with the collection.
|
2330
2335
|
removeChildView: function(view) {
|
2331
|
-
|
2336
|
+
|
2332
2337
|
if (view) {
|
2333
2338
|
this.triggerMethod('before:remove:child', view);
|
2334
2339
|
// call 'destroy' or 'remove', depending on which is found
|
2335
2340
|
if (view.destroy) { view.destroy(); }
|
2336
2341
|
else if (view.remove) { view.remove(); }
|
2337
|
-
|
2342
|
+
|
2338
2343
|
this.stopListening(view);
|
2339
2344
|
this.children.remove(view);
|
2340
2345
|
this.triggerMethod('remove:child', view);
|
2341
|
-
|
2346
|
+
|
2342
2347
|
// decrement the index of views after this one
|
2343
2348
|
this._updateIndices(view, false);
|
2344
2349
|
}
|
2345
|
-
|
2350
|
+
|
2346
2351
|
return view;
|
2347
2352
|
},
|
2348
|
-
|
2353
|
+
|
2349
2354
|
// check if the collection is empty
|
2350
2355
|
isEmpty: function() {
|
2351
2356
|
return !this.collection || this.collection.length === 0;
|
2352
2357
|
},
|
2353
|
-
|
2358
|
+
|
2354
2359
|
// If empty, show the empty view
|
2355
2360
|
checkEmpty: function() {
|
2356
2361
|
if (this.isEmpty(this.collection)) {
|
2357
2362
|
this.showEmptyView();
|
2358
2363
|
}
|
2359
2364
|
},
|
2360
|
-
|
2365
|
+
|
2361
2366
|
// You might need to override this if you've overridden attachHtml
|
2362
2367
|
attachBuffer: function(collectionView, buffer) {
|
2363
2368
|
collectionView.$el.append(buffer);
|
2364
2369
|
},
|
2365
|
-
|
2370
|
+
|
2366
2371
|
// Append the HTML to the collection's `el`.
|
2367
2372
|
// Override this method to do something other
|
2368
2373
|
// than `.append`.
|
@@ -2383,7 +2388,7 @@
|
|
2383
2388
|
}
|
2384
2389
|
}
|
2385
2390
|
},
|
2386
|
-
|
2391
|
+
|
2387
2392
|
// Internal method. Check whether we need to insert the view into
|
2388
2393
|
// the correct position.
|
2389
2394
|
_insertBefore: function(childView, index) {
|
@@ -2395,37 +2400,37 @@
|
|
2395
2400
|
return view._index === index + 1;
|
2396
2401
|
});
|
2397
2402
|
}
|
2398
|
-
|
2403
|
+
|
2399
2404
|
if (currentView) {
|
2400
2405
|
currentView.$el.before(childView.el);
|
2401
2406
|
return true;
|
2402
2407
|
}
|
2403
|
-
|
2408
|
+
|
2404
2409
|
return false;
|
2405
2410
|
},
|
2406
|
-
|
2411
|
+
|
2407
2412
|
// Internal method. Append a view to the end of the $el
|
2408
2413
|
_insertAfter: function(childView) {
|
2409
2414
|
this.$el.append(childView.el);
|
2410
2415
|
},
|
2411
|
-
|
2416
|
+
|
2412
2417
|
// Internal method to set up the `children` object for
|
2413
2418
|
// storing all of the child views
|
2414
2419
|
_initChildViewStorage: function() {
|
2415
2420
|
this.children = new Backbone.ChildViewContainer();
|
2416
2421
|
},
|
2417
|
-
|
2422
|
+
|
2418
2423
|
// Handle cleanup and other destroying needs for the collection of views
|
2419
2424
|
destroy: function() {
|
2420
2425
|
if (this.isDestroyed) { return; }
|
2421
|
-
|
2426
|
+
|
2422
2427
|
this.triggerMethod('before:destroy:collection');
|
2423
2428
|
this.destroyChildren();
|
2424
2429
|
this.triggerMethod('destroy:collection');
|
2425
|
-
|
2430
|
+
|
2426
2431
|
return Marionette.View.prototype.destroy.apply(this, arguments);
|
2427
2432
|
},
|
2428
|
-
|
2433
|
+
|
2429
2434
|
// Destroy the child views that this collection view
|
2430
2435
|
// is holding on to, if any
|
2431
2436
|
destroyChildren: function() {
|
@@ -2434,42 +2439,42 @@
|
|
2434
2439
|
this.checkEmpty();
|
2435
2440
|
return childViews;
|
2436
2441
|
},
|
2437
|
-
|
2442
|
+
|
2438
2443
|
// Set up the child view event forwarding. Uses a "childview:"
|
2439
2444
|
// prefix in front of all forwarded events.
|
2440
2445
|
proxyChildEvents: function(view) {
|
2441
2446
|
var prefix = this.getOption('childViewEventPrefix');
|
2442
|
-
|
2447
|
+
|
2443
2448
|
// Forward all child view events through the parent,
|
2444
2449
|
// prepending "childview:" to the event name
|
2445
2450
|
this.listenTo(view, 'all', function() {
|
2446
2451
|
var args = slice.call(arguments);
|
2447
2452
|
var rootEvent = args[0];
|
2448
2453
|
var childEvents = this.normalizeMethods(_.result(this, 'childEvents'));
|
2449
|
-
|
2454
|
+
|
2450
2455
|
args[0] = prefix + ':' + rootEvent;
|
2451
2456
|
args.splice(1, 0, view);
|
2452
|
-
|
2457
|
+
|
2453
2458
|
// call collectionView childEvent if defined
|
2454
2459
|
if (typeof childEvents !== 'undefined' && _.isFunction(childEvents[rootEvent])) {
|
2455
2460
|
childEvents[rootEvent].apply(this, args.slice(1));
|
2456
2461
|
}
|
2457
|
-
|
2462
|
+
|
2458
2463
|
this.triggerMethod.apply(this, args);
|
2459
2464
|
}, this);
|
2460
2465
|
}
|
2461
2466
|
});
|
2462
|
-
|
2467
|
+
|
2463
2468
|
/* jshint maxstatements: 17, maxlen: 117 */
|
2464
|
-
|
2469
|
+
|
2465
2470
|
// Composite View
|
2466
2471
|
// --------------
|
2467
|
-
|
2472
|
+
|
2468
2473
|
// Used for rendering a branch-leaf, hierarchical structure.
|
2469
2474
|
// Extends directly from CollectionView and also renders an
|
2470
2475
|
// a child view as `modelView`, for the top leaf
|
2471
2476
|
Marionette.CompositeView = Marionette.CollectionView.extend({
|
2472
|
-
|
2477
|
+
|
2473
2478
|
// Setting up the inheritance chain which allows changes to
|
2474
2479
|
// Marionette.CollectionView.prototype.constructor which allows overriding
|
2475
2480
|
// option to pass '{sort: false}' to prevent the CompositeView from
|
@@ -2478,56 +2483,56 @@
|
|
2478
2483
|
constructor: function() {
|
2479
2484
|
Marionette.CollectionView.apply(this, arguments);
|
2480
2485
|
},
|
2481
|
-
|
2486
|
+
|
2482
2487
|
// Configured the initial events that the composite view
|
2483
2488
|
// binds to. Override this method to prevent the initial
|
2484
2489
|
// events, or to add your own initial events.
|
2485
2490
|
_initialEvents: function() {
|
2486
|
-
|
2491
|
+
|
2487
2492
|
// Bind only after composite view is rendered to avoid adding child views
|
2488
2493
|
// to nonexistent childViewContainer
|
2489
|
-
|
2494
|
+
|
2490
2495
|
if (this.collection) {
|
2491
2496
|
this.listenTo(this.collection, 'add', this._onCollectionAdd);
|
2492
2497
|
this.listenTo(this.collection, 'remove', this._onCollectionRemove);
|
2493
2498
|
this.listenTo(this.collection, 'reset', this._renderChildren);
|
2494
|
-
|
2499
|
+
|
2495
2500
|
if (this.sort) {
|
2496
2501
|
this.listenTo(this.collection, 'sort', this._sortViews);
|
2497
2502
|
}
|
2498
2503
|
}
|
2499
2504
|
},
|
2500
|
-
|
2505
|
+
|
2501
2506
|
// Retrieve the `childView` to be used when rendering each of
|
2502
2507
|
// the items in the collection. The default is to return
|
2503
2508
|
// `this.childView` or Marionette.CompositeView if no `childView`
|
2504
2509
|
// has been defined
|
2505
2510
|
getChildView: function(child) {
|
2506
2511
|
var childView = this.getOption('childView') || this.constructor;
|
2507
|
-
|
2512
|
+
|
2508
2513
|
if (!childView) {
|
2509
2514
|
throw new Marionette.Error({
|
2510
2515
|
name: 'NoChildViewError',
|
2511
2516
|
message: 'A "childView" must be specified'
|
2512
2517
|
});
|
2513
2518
|
}
|
2514
|
-
|
2519
|
+
|
2515
2520
|
return childView;
|
2516
2521
|
},
|
2517
|
-
|
2522
|
+
|
2518
2523
|
// Serialize the collection for the view.
|
2519
2524
|
// You can override the `serializeData` method in your own view
|
2520
2525
|
// definition, to provide custom serialization for your view's data.
|
2521
2526
|
serializeData: function() {
|
2522
2527
|
var data = {};
|
2523
|
-
|
2528
|
+
|
2524
2529
|
if (this.model){
|
2525
2530
|
data = _.partial(this.serializeModel, this.model).apply(this, arguments);
|
2526
2531
|
}
|
2527
|
-
|
2532
|
+
|
2528
2533
|
return data;
|
2529
2534
|
},
|
2530
|
-
|
2535
|
+
|
2531
2536
|
// Renders the model once, and the collection once. Calling
|
2532
2537
|
// this again will tell the model's view to re-render itself
|
2533
2538
|
// but the collection will not re-render.
|
@@ -2535,42 +2540,42 @@
|
|
2535
2540
|
this._ensureViewIsIntact();
|
2536
2541
|
this.isRendered = true;
|
2537
2542
|
this.resetChildViewContainer();
|
2538
|
-
|
2543
|
+
|
2539
2544
|
this.triggerMethod('before:render', this);
|
2540
|
-
|
2545
|
+
|
2541
2546
|
this._renderTemplate();
|
2542
2547
|
this._renderChildren();
|
2543
|
-
|
2548
|
+
|
2544
2549
|
this.triggerMethod('render', this);
|
2545
2550
|
return this;
|
2546
2551
|
},
|
2547
|
-
|
2552
|
+
|
2548
2553
|
_renderChildren: function() {
|
2549
2554
|
if (this.isRendered) {
|
2550
2555
|
Marionette.CollectionView.prototype._renderChildren.call(this);
|
2551
2556
|
}
|
2552
2557
|
},
|
2553
|
-
|
2558
|
+
|
2554
2559
|
// Render the root template that the children
|
2555
2560
|
// views are appended to
|
2556
2561
|
_renderTemplate: function() {
|
2557
2562
|
var data = {};
|
2558
2563
|
data = this.serializeData();
|
2559
2564
|
data = this.mixinTemplateHelpers(data);
|
2560
|
-
|
2565
|
+
|
2561
2566
|
this.triggerMethod('before:render:template');
|
2562
|
-
|
2567
|
+
|
2563
2568
|
var template = this.getTemplate();
|
2564
2569
|
var html = Marionette.Renderer.render(template, data, this);
|
2565
2570
|
this.attachElContent(html);
|
2566
|
-
|
2571
|
+
|
2567
2572
|
// the ui bindings is done here and not at the end of render since they
|
2568
2573
|
// will not be available until after the model is rendered, but should be
|
2569
2574
|
// available before the collection is rendered.
|
2570
2575
|
this.bindUIElements();
|
2571
2576
|
this.triggerMethod('render:template');
|
2572
2577
|
},
|
2573
|
-
|
2578
|
+
|
2574
2579
|
// Attaches the content of the root.
|
2575
2580
|
// This method can be overridden to optimize rendering,
|
2576
2581
|
// or to render in a non standard way.
|
@@ -2585,16 +2590,16 @@
|
|
2585
2590
|
// ```
|
2586
2591
|
attachElContent: function(html) {
|
2587
2592
|
this.$el.html(html);
|
2588
|
-
|
2593
|
+
|
2589
2594
|
return this;
|
2590
2595
|
},
|
2591
|
-
|
2596
|
+
|
2592
2597
|
// You might need to override this if you've overridden attachHtml
|
2593
2598
|
attachBuffer: function(compositeView, buffer) {
|
2594
2599
|
var $container = this.getChildViewContainer(compositeView);
|
2595
2600
|
$container.append(buffer);
|
2596
2601
|
},
|
2597
|
-
|
2602
|
+
|
2598
2603
|
// Internal method. Append a view to the end of the $el.
|
2599
2604
|
// Overidden from CollectionView to ensure view is appended to
|
2600
2605
|
// childViewContainer
|
@@ -2602,41 +2607,41 @@
|
|
2602
2607
|
var $container = this.getChildViewContainer(this);
|
2603
2608
|
$container.append(childView.el);
|
2604
2609
|
},
|
2605
|
-
|
2610
|
+
|
2606
2611
|
// Internal method to ensure an `$childViewContainer` exists, for the
|
2607
2612
|
// `attachHtml` method to use.
|
2608
2613
|
getChildViewContainer: function(containerView) {
|
2609
2614
|
if ('$childViewContainer' in containerView) {
|
2610
2615
|
return containerView.$childViewContainer;
|
2611
2616
|
}
|
2612
|
-
|
2617
|
+
|
2613
2618
|
var container;
|
2614
2619
|
var childViewContainer = Marionette.getOption(containerView, 'childViewContainer');
|
2615
2620
|
if (childViewContainer) {
|
2616
|
-
|
2621
|
+
|
2617
2622
|
var selector = _.isFunction(childViewContainer) ? childViewContainer.call(containerView) : childViewContainer;
|
2618
|
-
|
2623
|
+
|
2619
2624
|
if (selector.charAt(0) === '@' && containerView.ui) {
|
2620
2625
|
container = containerView.ui[selector.substr(4)];
|
2621
2626
|
} else {
|
2622
2627
|
container = containerView.$(selector);
|
2623
2628
|
}
|
2624
|
-
|
2629
|
+
|
2625
2630
|
if (container.length <= 0) {
|
2626
2631
|
throw new Marionette.Error({
|
2627
2632
|
name: 'ChildViewContainerMissingError',
|
2628
2633
|
message: 'The specified "childViewContainer" was not found: ' + containerView.childViewContainer
|
2629
2634
|
});
|
2630
2635
|
}
|
2631
|
-
|
2636
|
+
|
2632
2637
|
} else {
|
2633
2638
|
container = containerView.$el;
|
2634
2639
|
}
|
2635
|
-
|
2640
|
+
|
2636
2641
|
containerView.$childViewContainer = container;
|
2637
2642
|
return container;
|
2638
2643
|
},
|
2639
|
-
|
2644
|
+
|
2640
2645
|
// Internal method to reset the `$childViewContainer` on render
|
2641
2646
|
resetChildViewContainer: function() {
|
2642
2647
|
if (this.$childViewContainer) {
|
@@ -2644,10 +2649,10 @@
|
|
2644
2649
|
}
|
2645
2650
|
}
|
2646
2651
|
});
|
2647
|
-
|
2652
|
+
|
2648
2653
|
// LayoutView
|
2649
2654
|
// ----------
|
2650
|
-
|
2655
|
+
|
2651
2656
|
// Used for managing application layoutViews, nested layoutViews and
|
2652
2657
|
// multiple regions within an application or sub-application.
|
2653
2658
|
//
|
@@ -2656,25 +2661,25 @@
|
|
2656
2661
|
// Used for composite view management and sub-application areas.
|
2657
2662
|
Marionette.LayoutView = Marionette.ItemView.extend({
|
2658
2663
|
regionClass: Marionette.Region,
|
2659
|
-
|
2664
|
+
|
2660
2665
|
// Ensure the regions are available when the `initialize` method
|
2661
2666
|
// is called.
|
2662
2667
|
constructor: function(options) {
|
2663
2668
|
options = options || {};
|
2664
|
-
|
2669
|
+
|
2665
2670
|
this._firstRender = true;
|
2666
2671
|
this._initializeRegions(options);
|
2667
|
-
|
2672
|
+
|
2668
2673
|
Marionette.ItemView.call(this, options);
|
2669
2674
|
},
|
2670
|
-
|
2675
|
+
|
2671
2676
|
// LayoutView's render will use the existing region objects the
|
2672
2677
|
// first time it is called. Subsequent calls will destroy the
|
2673
2678
|
// views that the regions are showing and then reset the `el`
|
2674
2679
|
// for the regions to the newly rendered DOM elements.
|
2675
2680
|
render: function() {
|
2676
2681
|
this._ensureViewIsIntact();
|
2677
|
-
|
2682
|
+
|
2678
2683
|
if (this._firstRender) {
|
2679
2684
|
// if this is the first render, don't do anything to
|
2680
2685
|
// reset the regions
|
@@ -2684,90 +2689,90 @@
|
|
2684
2689
|
// re-initialize the `el` for each region
|
2685
2690
|
this._reInitializeRegions();
|
2686
2691
|
}
|
2687
|
-
|
2692
|
+
|
2688
2693
|
return Marionette.ItemView.prototype.render.apply(this, arguments);
|
2689
2694
|
},
|
2690
|
-
|
2695
|
+
|
2691
2696
|
// Handle destroying regions, and then destroy the view itself.
|
2692
2697
|
destroy: function() {
|
2693
2698
|
if (this.isDestroyed) { return this; }
|
2694
|
-
|
2699
|
+
|
2695
2700
|
this.regionManager.destroy();
|
2696
2701
|
return Marionette.ItemView.prototype.destroy.apply(this, arguments);
|
2697
2702
|
},
|
2698
|
-
|
2703
|
+
|
2699
2704
|
// Add a single region, by name, to the layoutView
|
2700
2705
|
addRegion: function(name, definition) {
|
2701
2706
|
var regions = {};
|
2702
2707
|
regions[name] = definition;
|
2703
2708
|
return this._buildRegions(regions)[name];
|
2704
2709
|
},
|
2705
|
-
|
2710
|
+
|
2706
2711
|
// Add multiple regions as a {name: definition, name2: def2} object literal
|
2707
2712
|
addRegions: function(regions) {
|
2708
2713
|
this.regions = _.extend({}, this.regions, regions);
|
2709
2714
|
return this._buildRegions(regions);
|
2710
2715
|
},
|
2711
|
-
|
2716
|
+
|
2712
2717
|
// Remove a single region from the LayoutView, by name
|
2713
2718
|
removeRegion: function(name) {
|
2714
2719
|
delete this.regions[name];
|
2715
2720
|
return this.regionManager.removeRegion(name);
|
2716
2721
|
},
|
2717
|
-
|
2722
|
+
|
2718
2723
|
// Provides alternative access to regions
|
2719
2724
|
// Accepts the region name
|
2720
2725
|
// getRegion('main')
|
2721
2726
|
getRegion: function(region) {
|
2722
2727
|
return this.regionManager.get(region);
|
2723
2728
|
},
|
2724
|
-
|
2729
|
+
|
2725
2730
|
// Get all regions
|
2726
2731
|
getRegions: function(){
|
2727
2732
|
return this.regionManager.getRegions();
|
2728
2733
|
},
|
2729
|
-
|
2734
|
+
|
2730
2735
|
// internal method to build regions
|
2731
2736
|
_buildRegions: function(regions) {
|
2732
2737
|
var that = this;
|
2733
|
-
|
2738
|
+
|
2734
2739
|
var defaults = {
|
2735
2740
|
regionClass: this.getOption('regionClass'),
|
2736
2741
|
parentEl: function() { return that.$el; }
|
2737
2742
|
};
|
2738
|
-
|
2743
|
+
|
2739
2744
|
return this.regionManager.addRegions(regions, defaults);
|
2740
2745
|
},
|
2741
|
-
|
2746
|
+
|
2742
2747
|
// Internal method to initialize the regions that have been defined in a
|
2743
2748
|
// `regions` attribute on this layoutView.
|
2744
2749
|
_initializeRegions: function(options) {
|
2745
2750
|
var regions;
|
2746
2751
|
this._initRegionManager();
|
2747
|
-
|
2752
|
+
|
2748
2753
|
if (_.isFunction(this.regions)) {
|
2749
2754
|
regions = this.regions(options);
|
2750
2755
|
} else {
|
2751
2756
|
regions = this.regions || {};
|
2752
2757
|
}
|
2753
|
-
|
2758
|
+
|
2754
2759
|
// Enable users to define `regions` as instance options.
|
2755
2760
|
var regionOptions = this.getOption.call(options, 'regions');
|
2756
|
-
|
2761
|
+
|
2757
2762
|
// enable region options to be a function
|
2758
2763
|
if (_.isFunction(regionOptions)) {
|
2759
2764
|
regionOptions = regionOptions.call(this, options);
|
2760
2765
|
}
|
2761
|
-
|
2766
|
+
|
2762
2767
|
_.extend(regions, regionOptions);
|
2763
|
-
|
2768
|
+
|
2764
2769
|
// Normalize region selectors hash to allow
|
2765
2770
|
// a user to use the @ui. syntax.
|
2766
2771
|
regions = this.normalizeUIValues(regions);
|
2767
|
-
|
2772
|
+
|
2768
2773
|
this.addRegions(regions);
|
2769
2774
|
},
|
2770
|
-
|
2775
|
+
|
2771
2776
|
// Internal method to re-initialize all of the regions by updating the `el` that
|
2772
2777
|
// they point to
|
2773
2778
|
_reInitializeRegions: function() {
|
@@ -2776,48 +2781,48 @@
|
|
2776
2781
|
region.reset();
|
2777
2782
|
});
|
2778
2783
|
},
|
2779
|
-
|
2784
|
+
|
2780
2785
|
// Enable easy overriding of the default `RegionManager`
|
2781
2786
|
// for customized region interactions and business specific
|
2782
2787
|
// view logic for better control over single regions.
|
2783
2788
|
getRegionManager: function() {
|
2784
2789
|
return new Marionette.RegionManager();
|
2785
2790
|
},
|
2786
|
-
|
2791
|
+
|
2787
2792
|
// Internal method to initialize the region manager
|
2788
2793
|
// and all regions in it
|
2789
2794
|
_initRegionManager: function() {
|
2790
2795
|
this.regionManager = this.getRegionManager();
|
2791
|
-
|
2796
|
+
|
2792
2797
|
this.listenTo(this.regionManager, 'before:add:region', function(name) {
|
2793
2798
|
this.triggerMethod('before:add:region', name);
|
2794
2799
|
});
|
2795
|
-
|
2800
|
+
|
2796
2801
|
this.listenTo(this.regionManager, 'add:region', function(name, region) {
|
2797
2802
|
this[name] = region;
|
2798
2803
|
this.triggerMethod('add:region', name, region);
|
2799
2804
|
});
|
2800
|
-
|
2805
|
+
|
2801
2806
|
this.listenTo(this.regionManager, 'before:remove:region', function(name) {
|
2802
2807
|
this.triggerMethod('before:remove:region', name);
|
2803
2808
|
});
|
2804
|
-
|
2809
|
+
|
2805
2810
|
this.listenTo(this.regionManager, 'remove:region', function(name, region) {
|
2806
2811
|
delete this[name];
|
2807
2812
|
this.triggerMethod('remove:region', name, region);
|
2808
2813
|
});
|
2809
2814
|
}
|
2810
2815
|
});
|
2811
|
-
|
2816
|
+
|
2812
2817
|
|
2813
2818
|
// Behavior
|
2814
2819
|
// -----------
|
2815
|
-
|
2820
|
+
|
2816
2821
|
// A Behavior is an isolated set of DOM /
|
2817
2822
|
// user interactions that can be mixed into any View.
|
2818
2823
|
// Behaviors allow you to blackbox View specific interactions
|
2819
2824
|
// into portable logical chunks, keeping your views simple and your code DRY.
|
2820
|
-
|
2825
|
+
|
2821
2826
|
Marionette.Behavior = (function(_, Backbone) {
|
2822
2827
|
function Behavior(options, view) {
|
2823
2828
|
// Setup reference to the view.
|
@@ -2827,132 +2832,132 @@
|
|
2827
2832
|
this.view = view;
|
2828
2833
|
this.defaults = _.result(this, 'defaults') || {};
|
2829
2834
|
this.options = _.extend({}, this.defaults, options);
|
2830
|
-
|
2835
|
+
|
2831
2836
|
// proxy behavior $ method to the view
|
2832
2837
|
// this is useful for doing jquery DOM lookups
|
2833
2838
|
// scoped to behaviors view.
|
2834
2839
|
this.$ = function() {
|
2835
2840
|
return this.view.$.apply(this.view, arguments);
|
2836
2841
|
};
|
2837
|
-
|
2842
|
+
|
2838
2843
|
// Call the initialize method passing
|
2839
2844
|
// the arguments from the instance constructor
|
2840
2845
|
this.initialize.apply(this, arguments);
|
2841
2846
|
}
|
2842
|
-
|
2847
|
+
|
2843
2848
|
_.extend(Behavior.prototype, Backbone.Events, {
|
2844
2849
|
initialize: function() {},
|
2845
|
-
|
2850
|
+
|
2846
2851
|
// stopListening to behavior `onListen` events.
|
2847
2852
|
destroy: function() {
|
2848
2853
|
this.stopListening();
|
2849
2854
|
},
|
2850
|
-
|
2855
|
+
|
2851
2856
|
proxyViewProperties: function (view) {
|
2852
2857
|
this.$el = view.$el;
|
2853
2858
|
this.el = view.el;
|
2854
2859
|
},
|
2855
|
-
|
2860
|
+
|
2856
2861
|
// import the `triggerMethod` to trigger events with corresponding
|
2857
2862
|
// methods if the method exists
|
2858
2863
|
triggerMethod: Marionette.triggerMethod,
|
2859
|
-
|
2864
|
+
|
2860
2865
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
2861
2866
|
getOption: Marionette.proxyGetOption,
|
2862
|
-
|
2867
|
+
|
2863
2868
|
// Proxy `unbindEntityEvents` to enable binding view's events from another entity.
|
2864
2869
|
bindEntityEvents: Marionette.proxyBindEntityEvents,
|
2865
|
-
|
2870
|
+
|
2866
2871
|
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
|
2867
2872
|
unbindEntityEvents: Marionette.proxyUnbindEntityEvents
|
2868
2873
|
});
|
2869
|
-
|
2874
|
+
|
2870
2875
|
// Borrow Backbones extend implementation
|
2871
2876
|
// this allows us to setup a proper
|
2872
2877
|
// inheritance pattern that follows suit
|
2873
2878
|
// with the rest of Marionette views.
|
2874
2879
|
Behavior.extend = Marionette.extend;
|
2875
|
-
|
2880
|
+
|
2876
2881
|
return Behavior;
|
2877
2882
|
})(_, Backbone);
|
2878
|
-
|
2883
|
+
|
2879
2884
|
/* jshint maxlen: 143 */
|
2880
2885
|
// Marionette.Behaviors
|
2881
2886
|
// --------
|
2882
|
-
|
2887
|
+
|
2883
2888
|
// Behaviors is a utility class that takes care of
|
2884
2889
|
// gluing your behavior instances to their given View.
|
2885
2890
|
// The most important part of this class is that you
|
2886
2891
|
// **MUST** override the class level behaviorsLookup
|
2887
2892
|
// method for things to work properly.
|
2888
|
-
|
2893
|
+
|
2889
2894
|
Marionette.Behaviors = (function(Marionette, _) {
|
2890
|
-
|
2895
|
+
|
2891
2896
|
function Behaviors(view, behaviors) {
|
2892
|
-
|
2897
|
+
|
2893
2898
|
if (!_.isObject(view.behaviors)) {
|
2894
2899
|
return {};
|
2895
2900
|
}
|
2896
|
-
|
2901
|
+
|
2897
2902
|
// Behaviors defined on a view can be a flat object literal
|
2898
2903
|
// or it can be a function that returns an object.
|
2899
2904
|
behaviors = Behaviors.parseBehaviors(view, behaviors || _.result(view, 'behaviors'));
|
2900
|
-
|
2905
|
+
|
2901
2906
|
// Wraps several of the view's methods
|
2902
2907
|
// calling the methods first on each behavior
|
2903
2908
|
// and then eventually calling the method on the view.
|
2904
2909
|
Behaviors.wrap(view, behaviors, _.keys(methods));
|
2905
2910
|
return behaviors;
|
2906
2911
|
}
|
2907
|
-
|
2912
|
+
|
2908
2913
|
var methods = {
|
2909
2914
|
behaviorTriggers: function(behaviorTriggers, behaviors) {
|
2910
2915
|
var triggerBuilder = new BehaviorTriggersBuilder(this, behaviors);
|
2911
2916
|
return triggerBuilder.buildBehaviorTriggers();
|
2912
2917
|
},
|
2913
|
-
|
2918
|
+
|
2914
2919
|
behaviorEvents: function(behaviorEvents, behaviors) {
|
2915
2920
|
var _behaviorsEvents = {};
|
2916
2921
|
var viewUI = _.result(this, 'ui');
|
2917
|
-
|
2922
|
+
|
2918
2923
|
_.each(behaviors, function(b, i) {
|
2919
2924
|
var _events = {};
|
2920
2925
|
var behaviorEvents = _.clone(_.result(b, 'events')) || {};
|
2921
2926
|
var behaviorUI = _.result(b, 'ui');
|
2922
|
-
|
2927
|
+
|
2923
2928
|
// Construct an internal UI hash first using
|
2924
2929
|
// the views UI hash and then the behaviors UI hash.
|
2925
2930
|
// This allows the user to use UI hash elements
|
2926
2931
|
// defined in the parent view as well as those
|
2927
2932
|
// defined in the given behavior.
|
2928
2933
|
var ui = _.extend({}, viewUI, behaviorUI);
|
2929
|
-
|
2934
|
+
|
2930
2935
|
// Normalize behavior events hash to allow
|
2931
2936
|
// a user to use the @ui. syntax.
|
2932
2937
|
behaviorEvents = Marionette.normalizeUIKeys(behaviorEvents, ui);
|
2933
|
-
|
2938
|
+
|
2934
2939
|
_.each(_.keys(behaviorEvents), function(key) {
|
2935
2940
|
// Append white-space at the end of each key to prevent behavior key collisions.
|
2936
2941
|
// This is relying on the fact that backbone events considers "click .foo" the same as
|
2937
2942
|
// "click .foo ".
|
2938
|
-
|
2943
|
+
|
2939
2944
|
// +2 is used because new Array(1) or 0 is "" and not " "
|
2940
2945
|
var whitespace = (new Array(i + 2)).join(' ');
|
2941
2946
|
var eventKey = key + whitespace;
|
2942
2947
|
var handler = _.isFunction(behaviorEvents[key]) ? behaviorEvents[key] : b[behaviorEvents[key]];
|
2943
|
-
|
2948
|
+
|
2944
2949
|
_events[eventKey] = _.bind(handler, b);
|
2945
2950
|
});
|
2946
|
-
|
2951
|
+
|
2947
2952
|
_behaviorsEvents = _.extend(_behaviorsEvents, _events);
|
2948
2953
|
});
|
2949
|
-
|
2954
|
+
|
2950
2955
|
return _behaviorsEvents;
|
2951
2956
|
}
|
2952
2957
|
};
|
2953
|
-
|
2958
|
+
|
2954
2959
|
_.extend(Behaviors, {
|
2955
|
-
|
2960
|
+
|
2956
2961
|
// Placeholder method to be extended by the user.
|
2957
2962
|
// The method should define the object that stores the behaviors.
|
2958
2963
|
// i.e.
|
@@ -2968,7 +2973,7 @@
|
|
2968
2973
|
url: 'marionette.behaviors.html#behaviorslookup'
|
2969
2974
|
});
|
2970
2975
|
},
|
2971
|
-
|
2976
|
+
|
2972
2977
|
// Takes care of getting the behavior class
|
2973
2978
|
// given options and a key.
|
2974
2979
|
// If a user passes in options.behaviorClass
|
@@ -2978,24 +2983,24 @@
|
|
2978
2983
|
if (options.behaviorClass) {
|
2979
2984
|
return options.behaviorClass;
|
2980
2985
|
}
|
2981
|
-
|
2986
|
+
|
2982
2987
|
// Get behavior class can be either a flat object or a method
|
2983
2988
|
return _.isFunction(Behaviors.behaviorsLookup) ? Behaviors.behaviorsLookup.apply(this, arguments)[key] : Behaviors.behaviorsLookup[key];
|
2984
2989
|
},
|
2985
|
-
|
2990
|
+
|
2986
2991
|
// Iterate over the behaviors object, for each behavior
|
2987
2992
|
// instantiate it and get its grouped behaviors.
|
2988
2993
|
parseBehaviors: function(view, behaviors) {
|
2989
2994
|
return _.chain(behaviors).map(function(options, key) {
|
2990
2995
|
var BehaviorClass = Behaviors.getBehaviorClass(options, key);
|
2991
|
-
|
2996
|
+
|
2992
2997
|
var behavior = new BehaviorClass(options, view);
|
2993
2998
|
var nestedBehaviors = Behaviors.parseBehaviors(view, _.result(behavior, 'behaviors'));
|
2994
|
-
|
2999
|
+
|
2995
3000
|
return [behavior].concat(nestedBehaviors);
|
2996
3001
|
}).flatten().value();
|
2997
3002
|
},
|
2998
|
-
|
3003
|
+
|
2999
3004
|
// Wrap view internal methods so that they delegate to behaviors. For example,
|
3000
3005
|
// `onDestroy` should trigger destroy on all of the behaviors and then destroy itself.
|
3001
3006
|
// i.e.
|
@@ -3007,7 +3012,7 @@
|
|
3007
3012
|
});
|
3008
3013
|
}
|
3009
3014
|
});
|
3010
|
-
|
3015
|
+
|
3011
3016
|
// Class to build handlers for `triggers` on behaviors
|
3012
3017
|
// for views
|
3013
3018
|
function BehaviorTriggersBuilder(view, behaviors) {
|
@@ -3016,24 +3021,24 @@
|
|
3016
3021
|
this._behaviors = behaviors;
|
3017
3022
|
this._triggers = {};
|
3018
3023
|
}
|
3019
|
-
|
3024
|
+
|
3020
3025
|
_.extend(BehaviorTriggersBuilder.prototype, {
|
3021
3026
|
// Main method to build the triggers hash with event keys and handlers
|
3022
3027
|
buildBehaviorTriggers: function() {
|
3023
3028
|
_.each(this._behaviors, this._buildTriggerHandlersForBehavior, this);
|
3024
3029
|
return this._triggers;
|
3025
3030
|
},
|
3026
|
-
|
3031
|
+
|
3027
3032
|
// Internal method to build all trigger handlers for a given behavior
|
3028
3033
|
_buildTriggerHandlersForBehavior: function(behavior, i) {
|
3029
3034
|
var ui = _.extend({}, this._viewUI, _.result(behavior, 'ui'));
|
3030
3035
|
var triggersHash = _.clone(_.result(behavior, 'triggers')) || {};
|
3031
|
-
|
3036
|
+
|
3032
3037
|
triggersHash = Marionette.normalizeUIKeys(triggersHash, ui);
|
3033
|
-
|
3038
|
+
|
3034
3039
|
_.each(triggersHash, _.partial(this._setHandlerForBehavior, behavior, i), this);
|
3035
3040
|
},
|
3036
|
-
|
3041
|
+
|
3037
3042
|
// Internal method to create and assign the trigger handler for a given
|
3038
3043
|
// behavior
|
3039
3044
|
_setHandlerForBehavior: function(behavior, i, eventName, trigger) {
|
@@ -3041,19 +3046,19 @@
|
|
3041
3046
|
var triggerKey = trigger.replace(/^\S+/, function(triggerName) {
|
3042
3047
|
return triggerName + '.' + 'behaviortriggers' + i;
|
3043
3048
|
});
|
3044
|
-
|
3049
|
+
|
3045
3050
|
this._triggers[triggerKey] = this._view._buildViewTrigger(eventName);
|
3046
3051
|
}
|
3047
3052
|
});
|
3048
|
-
|
3053
|
+
|
3049
3054
|
return Behaviors;
|
3050
|
-
|
3055
|
+
|
3051
3056
|
})(Marionette, _);
|
3052
|
-
|
3057
|
+
|
3053
3058
|
|
3054
3059
|
// AppRouter
|
3055
3060
|
// ---------
|
3056
|
-
|
3061
|
+
|
3057
3062
|
// Reduce the boilerplate code of handling route events
|
3058
3063
|
// and then calling a single method on another object.
|
3059
3064
|
// Have your routers configured to call the method on
|
@@ -3068,73 +3073,73 @@
|
|
3068
3073
|
// just one giant router and controller.
|
3069
3074
|
//
|
3070
3075
|
// You can also add standard routes to an AppRouter.
|
3071
|
-
|
3076
|
+
|
3072
3077
|
Marionette.AppRouter = Backbone.Router.extend({
|
3073
|
-
|
3078
|
+
|
3074
3079
|
constructor: function(options) {
|
3075
3080
|
Backbone.Router.apply(this, arguments);
|
3076
|
-
|
3081
|
+
|
3077
3082
|
this.options = options || {};
|
3078
|
-
|
3083
|
+
|
3079
3084
|
var appRoutes = this.getOption('appRoutes');
|
3080
3085
|
var controller = this._getController();
|
3081
3086
|
this.processAppRoutes(controller, appRoutes);
|
3082
3087
|
this.on('route', this._processOnRoute, this);
|
3083
3088
|
},
|
3084
|
-
|
3089
|
+
|
3085
3090
|
// Similar to route method on a Backbone Router but
|
3086
3091
|
// method is called on the controller
|
3087
3092
|
appRoute: function(route, methodName) {
|
3088
3093
|
var controller = this._getController();
|
3089
3094
|
this._addAppRoute(controller, route, methodName);
|
3090
3095
|
},
|
3091
|
-
|
3096
|
+
|
3092
3097
|
// process the route event and trigger the onRoute
|
3093
3098
|
// method call, if it exists
|
3094
3099
|
_processOnRoute: function(routeName, routeArgs) {
|
3095
3100
|
// find the path that matched
|
3096
3101
|
var routePath = _.invert(this.getOption('appRoutes'))[routeName];
|
3097
|
-
|
3102
|
+
|
3098
3103
|
// make sure an onRoute is there, and call it
|
3099
3104
|
if (_.isFunction(this.onRoute)) {
|
3100
3105
|
this.onRoute(routeName, routePath, routeArgs);
|
3101
3106
|
}
|
3102
3107
|
},
|
3103
|
-
|
3108
|
+
|
3104
3109
|
// Internal method to process the `appRoutes` for the
|
3105
3110
|
// router, and turn them in to routes that trigger the
|
3106
3111
|
// specified method on the specified `controller`.
|
3107
3112
|
processAppRoutes: function(controller, appRoutes) {
|
3108
3113
|
if (!appRoutes) { return; }
|
3109
|
-
|
3114
|
+
|
3110
3115
|
var routeNames = _.keys(appRoutes).reverse(); // Backbone requires reverted order of routes
|
3111
|
-
|
3116
|
+
|
3112
3117
|
_.each(routeNames, function(route) {
|
3113
3118
|
this._addAppRoute(controller, route, appRoutes[route]);
|
3114
3119
|
}, this);
|
3115
3120
|
},
|
3116
|
-
|
3121
|
+
|
3117
3122
|
_getController: function() {
|
3118
3123
|
return this.getOption('controller');
|
3119
3124
|
},
|
3120
|
-
|
3125
|
+
|
3121
3126
|
_addAppRoute: function(controller, route, methodName) {
|
3122
3127
|
var method = controller[methodName];
|
3123
|
-
|
3128
|
+
|
3124
3129
|
if (!method) {
|
3125
3130
|
throw new Marionette.Error('Method "' + methodName + '" was not found on the controller');
|
3126
3131
|
}
|
3127
|
-
|
3132
|
+
|
3128
3133
|
this.route(route, methodName, _.bind(method, controller));
|
3129
3134
|
},
|
3130
|
-
|
3135
|
+
|
3131
3136
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
3132
3137
|
getOption: Marionette.proxyGetOption
|
3133
3138
|
});
|
3134
|
-
|
3139
|
+
|
3135
3140
|
// Application
|
3136
3141
|
// -----------
|
3137
|
-
|
3142
|
+
|
3138
3143
|
// Contain and manage the composite application as a whole.
|
3139
3144
|
// Stores and starts up `Region` objects, includes an
|
3140
3145
|
// event aggregator as `app.vent`
|
@@ -3147,29 +3152,29 @@
|
|
3147
3152
|
this._initChannel();
|
3148
3153
|
this.initialize.apply(this, arguments);
|
3149
3154
|
};
|
3150
|
-
|
3155
|
+
|
3151
3156
|
_.extend(Marionette.Application.prototype, Backbone.Events, {
|
3152
3157
|
// Initialize is an empty function by default. Override it with your own
|
3153
3158
|
// initialization logic.
|
3154
3159
|
initialize: function() {},
|
3155
|
-
|
3160
|
+
|
3156
3161
|
// Command execution, facilitated by Backbone.Wreqr.Commands
|
3157
3162
|
execute: function() {
|
3158
3163
|
this.commands.execute.apply(this.commands, arguments);
|
3159
3164
|
},
|
3160
|
-
|
3165
|
+
|
3161
3166
|
// Request/response, facilitated by Backbone.Wreqr.RequestResponse
|
3162
3167
|
request: function() {
|
3163
3168
|
return this.reqres.request.apply(this.reqres, arguments);
|
3164
3169
|
},
|
3165
|
-
|
3170
|
+
|
3166
3171
|
// Add an initializer that is either run at when the `start`
|
3167
3172
|
// method is called, or run immediately if added after `start`
|
3168
3173
|
// has already been called.
|
3169
3174
|
addInitializer: function(initializer) {
|
3170
3175
|
this._initCallbacks.add(initializer);
|
3171
3176
|
},
|
3172
|
-
|
3177
|
+
|
3173
3178
|
// kick off all of the application's processes.
|
3174
3179
|
// initializes all of the regions that have been added
|
3175
3180
|
// to the app, and runs all of the initializer functions
|
@@ -3178,7 +3183,7 @@
|
|
3178
3183
|
this._initCallbacks.run(options, this);
|
3179
3184
|
this.triggerMethod('start', options);
|
3180
3185
|
},
|
3181
|
-
|
3186
|
+
|
3182
3187
|
// Add regions to your app.
|
3183
3188
|
// Accepts a hash of named strings or Region objects
|
3184
3189
|
// addRegions({something: "#someRegion"})
|
@@ -3186,99 +3191,99 @@
|
|
3186
3191
|
addRegions: function(regions) {
|
3187
3192
|
return this._regionManager.addRegions(regions);
|
3188
3193
|
},
|
3189
|
-
|
3194
|
+
|
3190
3195
|
// Empty all regions in the app, without removing them
|
3191
3196
|
emptyRegions: function() {
|
3192
3197
|
return this._regionManager.emptyRegions();
|
3193
3198
|
},
|
3194
|
-
|
3199
|
+
|
3195
3200
|
// Removes a region from your app, by name
|
3196
3201
|
// Accepts the regions name
|
3197
3202
|
// removeRegion('myRegion')
|
3198
3203
|
removeRegion: function(region) {
|
3199
3204
|
return this._regionManager.removeRegion(region);
|
3200
3205
|
},
|
3201
|
-
|
3206
|
+
|
3202
3207
|
// Provides alternative access to regions
|
3203
3208
|
// Accepts the region name
|
3204
3209
|
// getRegion('main')
|
3205
3210
|
getRegion: function(region) {
|
3206
3211
|
return this._regionManager.get(region);
|
3207
3212
|
},
|
3208
|
-
|
3213
|
+
|
3209
3214
|
// Get all the regions from the region manager
|
3210
3215
|
getRegions: function(){
|
3211
3216
|
return this._regionManager.getRegions();
|
3212
3217
|
},
|
3213
|
-
|
3218
|
+
|
3214
3219
|
// Create a module, attached to the application
|
3215
3220
|
module: function(moduleNames, moduleDefinition) {
|
3216
|
-
|
3221
|
+
|
3217
3222
|
// Overwrite the module class if the user specifies one
|
3218
3223
|
var ModuleClass = Marionette.Module.getClass(moduleDefinition);
|
3219
|
-
|
3224
|
+
|
3220
3225
|
// slice the args, and add this application object as the
|
3221
3226
|
// first argument of the array
|
3222
3227
|
var args = slice.call(arguments);
|
3223
3228
|
args.unshift(this);
|
3224
|
-
|
3229
|
+
|
3225
3230
|
// see the Marionette.Module object for more information
|
3226
3231
|
return ModuleClass.create.apply(ModuleClass, args);
|
3227
3232
|
},
|
3228
|
-
|
3233
|
+
|
3229
3234
|
// Enable easy overriding of the default `RegionManager`
|
3230
3235
|
// for customized region interactions and business-specific
|
3231
3236
|
// view logic for better control over single regions.
|
3232
3237
|
getRegionManager: function() {
|
3233
3238
|
return new Marionette.RegionManager();
|
3234
3239
|
},
|
3235
|
-
|
3240
|
+
|
3236
3241
|
// Internal method to initialize the regions that have been defined in a
|
3237
3242
|
// `regions` attribute on the application instance
|
3238
3243
|
_initializeRegions: function(options) {
|
3239
3244
|
var regions = _.isFunction(this.regions) ? this.regions(options) : this.regions || {};
|
3240
|
-
|
3245
|
+
|
3241
3246
|
this._initRegionManager();
|
3242
|
-
|
3247
|
+
|
3243
3248
|
// Enable users to define `regions` in instance options.
|
3244
3249
|
var optionRegions = Marionette.getOption(options, 'regions');
|
3245
|
-
|
3250
|
+
|
3246
3251
|
// Enable region options to be a function
|
3247
3252
|
if (_.isFunction(optionRegions)) {
|
3248
3253
|
optionRegions = optionRegions.call(this, options);
|
3249
3254
|
}
|
3250
|
-
|
3255
|
+
|
3251
3256
|
// Overwrite current regions with those passed in options
|
3252
3257
|
_.extend(regions, optionRegions);
|
3253
|
-
|
3258
|
+
|
3254
3259
|
this.addRegions(regions);
|
3255
|
-
|
3260
|
+
|
3256
3261
|
return this;
|
3257
3262
|
},
|
3258
|
-
|
3263
|
+
|
3259
3264
|
// Internal method to set up the region manager
|
3260
3265
|
_initRegionManager: function() {
|
3261
3266
|
this._regionManager = this.getRegionManager();
|
3262
|
-
|
3267
|
+
|
3263
3268
|
this.listenTo(this._regionManager, 'before:add:region', function(name) {
|
3264
3269
|
this.triggerMethod('before:add:region', name);
|
3265
3270
|
});
|
3266
|
-
|
3271
|
+
|
3267
3272
|
this.listenTo(this._regionManager, 'add:region', function(name, region) {
|
3268
3273
|
this[name] = region;
|
3269
3274
|
this.triggerMethod('add:region', name, region);
|
3270
3275
|
});
|
3271
|
-
|
3276
|
+
|
3272
3277
|
this.listenTo(this._regionManager, 'before:remove:region', function(name) {
|
3273
3278
|
this.triggerMethod('before:remove:region', name);
|
3274
3279
|
});
|
3275
|
-
|
3280
|
+
|
3276
3281
|
this.listenTo(this._regionManager, 'remove:region', function(name, region) {
|
3277
3282
|
delete this[name];
|
3278
3283
|
this.triggerMethod('remove:region', name, region);
|
3279
3284
|
});
|
3280
3285
|
},
|
3281
|
-
|
3286
|
+
|
3282
3287
|
// Internal method to setup the Wreqr.radio channel
|
3283
3288
|
_initChannel: function() {
|
3284
3289
|
this.channelName = _.result(this, 'channelName') || 'global';
|
@@ -3287,23 +3292,23 @@
|
|
3287
3292
|
this.commands = _.result(this, 'commands') || this.channel.commands;
|
3288
3293
|
this.reqres = _.result(this, 'reqres') || this.channel.reqres;
|
3289
3294
|
},
|
3290
|
-
|
3295
|
+
|
3291
3296
|
// import the `triggerMethod` to trigger events with corresponding
|
3292
3297
|
// methods if the method exists
|
3293
3298
|
triggerMethod: Marionette.triggerMethod,
|
3294
|
-
|
3299
|
+
|
3295
3300
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
3296
3301
|
getOption: Marionette.proxyGetOption
|
3297
3302
|
});
|
3298
|
-
|
3303
|
+
|
3299
3304
|
// Copy the `extend` function used by Backbone's classes
|
3300
3305
|
Marionette.Application.extend = Marionette.extend;
|
3301
|
-
|
3306
|
+
|
3302
3307
|
/* jshint maxparams: 9 */
|
3303
|
-
|
3308
|
+
|
3304
3309
|
// Module
|
3305
3310
|
// ------
|
3306
|
-
|
3311
|
+
|
3307
3312
|
// A simple module system, used to create privacy and encapsulation in
|
3308
3313
|
// Marionette applications
|
3309
3314
|
Marionette.Module = function(moduleName, app, options) {
|
@@ -3312,52 +3317,52 @@
|
|
3312
3317
|
// Allow for a user to overide the initialize
|
3313
3318
|
// for a given module instance.
|
3314
3319
|
this.initialize = options.initialize || this.initialize;
|
3315
|
-
|
3320
|
+
|
3316
3321
|
// Set up an internal store for sub-modules.
|
3317
3322
|
this.submodules = {};
|
3318
|
-
|
3323
|
+
|
3319
3324
|
this._setupInitializersAndFinalizers();
|
3320
|
-
|
3325
|
+
|
3321
3326
|
// Set an internal reference to the app
|
3322
3327
|
// within a module.
|
3323
3328
|
this.app = app;
|
3324
|
-
|
3329
|
+
|
3325
3330
|
if (_.isFunction(this.initialize)) {
|
3326
3331
|
this.initialize(moduleName, app, this.options);
|
3327
3332
|
}
|
3328
3333
|
};
|
3329
|
-
|
3334
|
+
|
3330
3335
|
Marionette.Module.extend = Marionette.extend;
|
3331
|
-
|
3336
|
+
|
3332
3337
|
// Extend the Module prototype with events / listenTo, so that the module
|
3333
3338
|
// can be used as an event aggregator or pub/sub.
|
3334
3339
|
_.extend(Marionette.Module.prototype, Backbone.Events, {
|
3335
|
-
|
3340
|
+
|
3336
3341
|
// By default modules start with their parents.
|
3337
3342
|
startWithParent: true,
|
3338
|
-
|
3343
|
+
|
3339
3344
|
// Initialize is an empty function by default. Override it with your own
|
3340
3345
|
// initialization logic when extending Marionette.Module.
|
3341
3346
|
initialize: function() {},
|
3342
|
-
|
3347
|
+
|
3343
3348
|
// Initializer for a specific module. Initializers are run when the
|
3344
3349
|
// module's `start` method is called.
|
3345
3350
|
addInitializer: function(callback) {
|
3346
3351
|
this._initializerCallbacks.add(callback);
|
3347
3352
|
},
|
3348
|
-
|
3353
|
+
|
3349
3354
|
// Finalizers are run when a module is stopped. They are used to teardown
|
3350
3355
|
// and finalize any variables, references, events and other code that the
|
3351
3356
|
// module had set up.
|
3352
3357
|
addFinalizer: function(callback) {
|
3353
3358
|
this._finalizerCallbacks.add(callback);
|
3354
3359
|
},
|
3355
|
-
|
3360
|
+
|
3356
3361
|
// Start the module, and run all of its initializers
|
3357
3362
|
start: function(options) {
|
3358
3363
|
// Prevent re-starting a module that is already started
|
3359
3364
|
if (this._isInitialized) { return; }
|
3360
|
-
|
3365
|
+
|
3361
3366
|
// start the sub-modules (depth-first hierarchy)
|
3362
3367
|
_.each(this.submodules, function(mod) {
|
3363
3368
|
// check to see if we should start the sub-module with this parent
|
@@ -3365,51 +3370,51 @@
|
|
3365
3370
|
mod.start(options);
|
3366
3371
|
}
|
3367
3372
|
});
|
3368
|
-
|
3373
|
+
|
3369
3374
|
// run the callbacks to "start" the current module
|
3370
3375
|
this.triggerMethod('before:start', options);
|
3371
|
-
|
3376
|
+
|
3372
3377
|
this._initializerCallbacks.run(options, this);
|
3373
3378
|
this._isInitialized = true;
|
3374
|
-
|
3379
|
+
|
3375
3380
|
this.triggerMethod('start', options);
|
3376
3381
|
},
|
3377
|
-
|
3382
|
+
|
3378
3383
|
// Stop this module by running its finalizers and then stop all of
|
3379
3384
|
// the sub-modules for this module
|
3380
3385
|
stop: function() {
|
3381
3386
|
// if we are not initialized, don't bother finalizing
|
3382
3387
|
if (!this._isInitialized) { return; }
|
3383
3388
|
this._isInitialized = false;
|
3384
|
-
|
3389
|
+
|
3385
3390
|
this.triggerMethod('before:stop');
|
3386
|
-
|
3391
|
+
|
3387
3392
|
// stop the sub-modules; depth-first, to make sure the
|
3388
3393
|
// sub-modules are stopped / finalized before parents
|
3389
3394
|
_.each(this.submodules, function(mod) { mod.stop(); });
|
3390
|
-
|
3395
|
+
|
3391
3396
|
// run the finalizers
|
3392
3397
|
this._finalizerCallbacks.run(undefined, this);
|
3393
|
-
|
3398
|
+
|
3394
3399
|
// reset the initializers and finalizers
|
3395
3400
|
this._initializerCallbacks.reset();
|
3396
3401
|
this._finalizerCallbacks.reset();
|
3397
|
-
|
3402
|
+
|
3398
3403
|
this.triggerMethod('stop');
|
3399
3404
|
},
|
3400
|
-
|
3405
|
+
|
3401
3406
|
// Configure the module with a definition function and any custom args
|
3402
3407
|
// that are to be passed in to the definition function
|
3403
3408
|
addDefinition: function(moduleDefinition, customArgs) {
|
3404
3409
|
this._runModuleDefinition(moduleDefinition, customArgs);
|
3405
3410
|
},
|
3406
|
-
|
3411
|
+
|
3407
3412
|
// Internal method: run the module definition function with the correct
|
3408
3413
|
// arguments
|
3409
3414
|
_runModuleDefinition: function(definition, customArgs) {
|
3410
3415
|
// If there is no definition short circut the method.
|
3411
3416
|
if (!definition) { return; }
|
3412
|
-
|
3417
|
+
|
3413
3418
|
// build the correct list of arguments for the module definition
|
3414
3419
|
var args = _.flatten([
|
3415
3420
|
this,
|
@@ -3419,10 +3424,10 @@
|
|
3419
3424
|
Backbone.$, _,
|
3420
3425
|
customArgs
|
3421
3426
|
]);
|
3422
|
-
|
3427
|
+
|
3423
3428
|
definition.apply(this, args);
|
3424
3429
|
},
|
3425
|
-
|
3430
|
+
|
3426
3431
|
// Internal method: set up new copies of initializers and finalizers.
|
3427
3432
|
// Calling this method will wipe out all existing initializers and
|
3428
3433
|
// finalizers.
|
@@ -3430,52 +3435,52 @@
|
|
3430
3435
|
this._initializerCallbacks = new Marionette.Callbacks();
|
3431
3436
|
this._finalizerCallbacks = new Marionette.Callbacks();
|
3432
3437
|
},
|
3433
|
-
|
3438
|
+
|
3434
3439
|
// import the `triggerMethod` to trigger events with corresponding
|
3435
3440
|
// methods if the method exists
|
3436
3441
|
triggerMethod: Marionette.triggerMethod
|
3437
3442
|
});
|
3438
|
-
|
3443
|
+
|
3439
3444
|
// Class methods to create modules
|
3440
3445
|
_.extend(Marionette.Module, {
|
3441
|
-
|
3446
|
+
|
3442
3447
|
// Create a module, hanging off the app parameter as the parent object.
|
3443
3448
|
create: function(app, moduleNames, moduleDefinition) {
|
3444
3449
|
var module = app;
|
3445
|
-
|
3450
|
+
|
3446
3451
|
// get the custom args passed in after the module definition and
|
3447
3452
|
// get rid of the module name and definition function
|
3448
3453
|
var customArgs = slice.call(arguments);
|
3449
3454
|
customArgs.splice(0, 3);
|
3450
|
-
|
3455
|
+
|
3451
3456
|
// Split the module names and get the number of submodules.
|
3452
3457
|
// i.e. an example module name of `Doge.Wow.Amaze` would
|
3453
3458
|
// then have the potential for 3 module definitions.
|
3454
3459
|
moduleNames = moduleNames.split('.');
|
3455
3460
|
var length = moduleNames.length;
|
3456
|
-
|
3461
|
+
|
3457
3462
|
// store the module definition for the last module in the chain
|
3458
3463
|
var moduleDefinitions = [];
|
3459
3464
|
moduleDefinitions[length - 1] = moduleDefinition;
|
3460
|
-
|
3465
|
+
|
3461
3466
|
// Loop through all the parts of the module definition
|
3462
3467
|
_.each(moduleNames, function(moduleName, i) {
|
3463
3468
|
var parentModule = module;
|
3464
3469
|
module = this._getModule(parentModule, moduleName, app, moduleDefinition);
|
3465
3470
|
this._addModuleDefinition(parentModule, module, moduleDefinitions[i], customArgs);
|
3466
3471
|
}, this);
|
3467
|
-
|
3472
|
+
|
3468
3473
|
// Return the last module in the definition chain
|
3469
3474
|
return module;
|
3470
3475
|
},
|
3471
|
-
|
3476
|
+
|
3472
3477
|
_getModule: function(parentModule, moduleName, app, def, args) {
|
3473
3478
|
var options = _.extend({}, def);
|
3474
3479
|
var ModuleClass = this.getClass(def);
|
3475
|
-
|
3480
|
+
|
3476
3481
|
// Get an existing module of this name if we have one
|
3477
3482
|
var module = parentModule[moduleName];
|
3478
|
-
|
3483
|
+
|
3479
3484
|
if (!module) {
|
3480
3485
|
// Create a new module if we don't have one
|
3481
3486
|
module = new ModuleClass(moduleName, app, options);
|
@@ -3483,10 +3488,10 @@
|
|
3483
3488
|
// store the module on the parent
|
3484
3489
|
parentModule.submodules[moduleName] = module;
|
3485
3490
|
}
|
3486
|
-
|
3491
|
+
|
3487
3492
|
return module;
|
3488
3493
|
},
|
3489
|
-
|
3494
|
+
|
3490
3495
|
// ## Module Classes
|
3491
3496
|
//
|
3492
3497
|
// Module classes can be used as an alternative to the define pattern.
|
@@ -3495,71 +3500,71 @@
|
|
3495
3500
|
// This allows module lifecyle events like `onStart` and `onStop` to be called directly.
|
3496
3501
|
getClass: function(moduleDefinition) {
|
3497
3502
|
var ModuleClass = Marionette.Module;
|
3498
|
-
|
3503
|
+
|
3499
3504
|
if (!moduleDefinition) {
|
3500
3505
|
return ModuleClass;
|
3501
3506
|
}
|
3502
|
-
|
3507
|
+
|
3503
3508
|
// If all of the module's functionality is defined inside its class,
|
3504
3509
|
// then the class can be passed in directly. `MyApp.module("Foo", FooModule)`.
|
3505
3510
|
if (moduleDefinition.prototype instanceof ModuleClass) {
|
3506
3511
|
return moduleDefinition;
|
3507
3512
|
}
|
3508
|
-
|
3513
|
+
|
3509
3514
|
return moduleDefinition.moduleClass || ModuleClass;
|
3510
3515
|
},
|
3511
|
-
|
3516
|
+
|
3512
3517
|
// Add the module definition and add a startWithParent initializer function.
|
3513
3518
|
// This is complicated because module definitions are heavily overloaded
|
3514
3519
|
// and support an anonymous function, module class, or options object
|
3515
3520
|
_addModuleDefinition: function(parentModule, module, def, args) {
|
3516
3521
|
var fn = this._getDefine(def);
|
3517
3522
|
var startWithParent = this._getStartWithParent(def, module);
|
3518
|
-
|
3523
|
+
|
3519
3524
|
if (fn) {
|
3520
3525
|
module.addDefinition(fn, args);
|
3521
3526
|
}
|
3522
|
-
|
3527
|
+
|
3523
3528
|
this._addStartWithParent(parentModule, module, startWithParent);
|
3524
3529
|
},
|
3525
|
-
|
3530
|
+
|
3526
3531
|
_getStartWithParent: function(def, module) {
|
3527
3532
|
var swp;
|
3528
|
-
|
3533
|
+
|
3529
3534
|
if (_.isFunction(def) && (def.prototype instanceof Marionette.Module)) {
|
3530
3535
|
swp = module.constructor.prototype.startWithParent;
|
3531
3536
|
return _.isUndefined(swp) ? true : swp;
|
3532
3537
|
}
|
3533
|
-
|
3538
|
+
|
3534
3539
|
if (_.isObject(def)) {
|
3535
3540
|
swp = def.startWithParent;
|
3536
3541
|
return _.isUndefined(swp) ? true : swp;
|
3537
3542
|
}
|
3538
|
-
|
3543
|
+
|
3539
3544
|
return true;
|
3540
3545
|
},
|
3541
|
-
|
3546
|
+
|
3542
3547
|
_getDefine: function(def) {
|
3543
3548
|
if (_.isFunction(def) && !(def.prototype instanceof Marionette.Module)) {
|
3544
3549
|
return def;
|
3545
3550
|
}
|
3546
|
-
|
3551
|
+
|
3547
3552
|
if (_.isObject(def)) {
|
3548
3553
|
return def.define;
|
3549
3554
|
}
|
3550
|
-
|
3555
|
+
|
3551
3556
|
return null;
|
3552
3557
|
},
|
3553
|
-
|
3558
|
+
|
3554
3559
|
_addStartWithParent: function(parentModule, module, startWithParent) {
|
3555
3560
|
module.startWithParent = module.startWithParent && startWithParent;
|
3556
|
-
|
3561
|
+
|
3557
3562
|
if (!module.startWithParent || !!module.startWithParentIsConfigured) {
|
3558
3563
|
return;
|
3559
3564
|
}
|
3560
|
-
|
3565
|
+
|
3561
3566
|
module.startWithParentIsConfigured = true;
|
3562
|
-
|
3567
|
+
|
3563
3568
|
parentModule.addInitializer(function(options) {
|
3564
3569
|
if (module.startWithParent) {
|
3565
3570
|
module.start(options);
|
@@ -3567,7 +3572,7 @@
|
|
3567
3572
|
});
|
3568
3573
|
}
|
3569
3574
|
});
|
3570
|
-
|
3575
|
+
|
3571
3576
|
|
3572
3577
|
return Marionette;
|
3573
3578
|
}));
|