marionette-rails 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 97731fd8838b5590ee15c0d9cb0fbabfe575d264
4
- data.tar.gz: fa19df0cc00e1a5887bbaf02ea6a348579b9afd2
3
+ metadata.gz: 5bb72c3e7ebd42ae9f6ff1cab755e4d75cbd33d7
4
+ data.tar.gz: 93bb3dd197d7c37ffc2698eebf39c93476d84246
5
5
  SHA512:
6
- metadata.gz: 3a8a8069c059b6ee0b4100a2e31b58c476ecda37aa9b1938c2573bf556917540ef750ecbe065bd45d08ed8db2df7bc1c818394d733272eca31284c81e6d83ed2
7
- data.tar.gz: 92f348ccd1500aef5677e420ecda8f0dd0537a38b765aee6f5513e0175a3fc85d6d20997993d256b51bff2992c44c285e01efe3a55a4b14fa2fb1a48e189861b
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 [@chancancode](https://github.com/chancancode/) and [@wingrunr21](https://github.com/wingrunr21).
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
- [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](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,5 +1,5 @@
1
1
  module Marionette
2
2
  module Rails
3
- VERSION = '2.2.1'
3
+ VERSION = '2.2.2'
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  // MarionetteJS (Backbone.Marionette)
2
2
  // ----------------------------------
3
- // v2.2.1
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.1';
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 = options || {};
1147
+
1148
+ var showOptions = options || {};
1149
1149
  var isDifferentView = view !== this.currentView;
1150
- var preventDestroy = !!showOptions.preventDestroy;
1151
- var forceShow = !!showOptions.forceShow;
1152
-
1153
- // we are only changing the view if there is a view to change to begin with
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
- // only destroy the view if we don't want to preventDestroy and the view is different
1157
- var _shouldDestroyView = !preventDestroy && isDifferentView;
1158
-
1159
- // show the view if the view is different or if you want to re-show the view
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', _.bind(this.empty, this));
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
  }));