marionette-rails 1.0.0.beta3 → 1.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Backbone.Marionette, v1.0.0-beta3
2
+ * Backbone.Marionette, v1.0.0-beta4
3
3
  * Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
4
4
  * Distributed under MIT license
5
5
  * http://github.com/marionettejs/backbone.marionette
@@ -244,9 +244,79 @@ Backbone.Marionette = Marionette = (function(Backbone, _, $){
244
244
  // For slicing `arguments` in functions
245
245
  var slice = Array.prototype.slice;
246
246
 
247
+ // Marionette.extend
248
+ // -----------------
249
+
247
250
  // Borrow the Backbone `extend` method so we can use it as needed
248
251
  Marionette.extend = Backbone.Model.extend;
249
252
 
253
+ // Marionette.getOption
254
+ // --------------------
255
+
256
+ // Retrieve an object, function or other value from a target
257
+ // object or it's `options`, with `options` taking precedence.
258
+ Marionette.getOption = function(target, optionName){
259
+ if (!target || !optionName){ return; }
260
+ var value;
261
+
262
+ if (target.options && target.options[optionName]){
263
+ value = target.options[optionName];
264
+ } else {
265
+ value = target[optionName];
266
+ }
267
+
268
+ return value;
269
+ };
270
+
271
+ // Mairionette.createObject
272
+ // ------------------------
273
+
274
+ // A wrapper / shim for `Object.create`. Uses native `Object.create`
275
+ // if available, otherwise shims it in place for Marionette to use.
276
+ Marionette.createObject = (function(){
277
+ var createObject;
278
+
279
+ // Define this once, and just replace the .prototype on it as needed,
280
+ // to improve performance in older / less optimized JS engines
281
+ function F() {}
282
+
283
+
284
+ // Check for existing native / shimmed Object.create
285
+ if (typeof Object.create === "function"){
286
+
287
+ // found native/shim, so use it
288
+ createObject = Object.create;
289
+
290
+ } else {
291
+
292
+ // An implementation of the Boodman/Crockford delegation
293
+ // w/ Cornford optimization, as suggested by @unscriptable
294
+ // https://gist.github.com/3959151
295
+
296
+ // native/shim not found, so shim it ourself
297
+ createObject = function (o) {
298
+
299
+ // set the prototype of the function
300
+ // so we will get `o` as the prototype
301
+ // of the new object instance
302
+ F.prototype = o;
303
+
304
+ // create a new object that inherits from
305
+ // the `o` parameter
306
+ var child = new F();
307
+
308
+ // clean up just in case o is really large
309
+ F.prototype = null;
310
+
311
+ // send it back
312
+ return child;
313
+ };
314
+
315
+ }
316
+
317
+ return createObject;
318
+ })();
319
+
250
320
  // Trigger an event and a corresponding method name. Examples:
251
321
  //
252
322
  // `this.triggerMethod("foo")` will trigger the "foo" event and
@@ -274,11 +344,22 @@ Marionette.triggerMethod = function(){
274
344
  }
275
345
  };
276
346
 
347
+
277
348
  // EventBinder
278
349
  // -----------
279
350
  // Import the event binder from it's new home
280
351
  // https://github.com/marionettejs/backbone.eventbinder
281
- Marionette.EventBinder = Backbone.EventBinder;
352
+ Marionette.EventBinder = Backbone.EventBinder.extend({
353
+
354
+ augment: function(target){
355
+ var eventBinder = new Marionette.EventBinder();
356
+ target.eventBinder = eventBinder;
357
+ target.bindTo = _.bind(eventBinder.bindTo, eventBinder);
358
+ target.unbindFrom = _.bind(eventBinder.unbindFrom, eventBinder);
359
+ target.unbindAll = _.bind(eventBinder.unbindAll, eventBinder);
360
+ }
361
+
362
+ });
282
363
 
283
364
  // Add the EventBinder methods to the view directly,
284
365
  // but keep them bound to the EventBinder instance so they work properly.
@@ -310,6 +391,361 @@ Marionette.EventAggregator = Backbone.Wreqr.EventAggregator.extend({
310
391
 
311
392
  });
312
393
 
394
+ // Callbacks
395
+ // ---------
396
+
397
+ // A simple way of managing a collection of callbacks
398
+ // and executing them at a later point in time, using jQuery's
399
+ // `Deferred` object.
400
+ Marionette.Callbacks = function(){
401
+ this._deferred = $.Deferred();
402
+ this._callbacks = [];
403
+ };
404
+
405
+ _.extend(Marionette.Callbacks.prototype, {
406
+
407
+ // Add a callback to be executed. Callbacks added here are
408
+ // guaranteed to execute, even if they are added after the
409
+ // `run` method is called.
410
+ add: function(callback, contextOverride){
411
+ this._callbacks.push({cb: callback, ctx: contextOverride});
412
+
413
+ this._deferred.done(function(context, options){
414
+ if (contextOverride){ context = contextOverride; }
415
+ callback.call(context, options);
416
+ });
417
+ },
418
+
419
+ // Run all registered callbacks with the context specified.
420
+ // Additional callbacks can be added after this has been run
421
+ // and they will still be executed.
422
+ run: function(options, context){
423
+ this._deferred.resolve(context, options);
424
+ },
425
+
426
+ // Resets the list of callbacks to be run, allowing the same list
427
+ // to be run multiple times - whenever the `run` method is called.
428
+ reset: function(){
429
+ var that = this;
430
+ var callbacks = this._callbacks;
431
+ this._deferred = $.Deferred();
432
+ this._callbacks = [];
433
+ _.each(callbacks, function(cb){
434
+ that.add(cb.cb, cb.ctx);
435
+ });
436
+ }
437
+ });
438
+
439
+
440
+ // Template Cache
441
+ // --------------
442
+
443
+ // Manage templates stored in `<script>` blocks,
444
+ // caching them for faster access.
445
+ Marionette.TemplateCache = function(templateId){
446
+ this.templateId = templateId;
447
+ };
448
+
449
+ // TemplateCache object-level methods. Manage the template
450
+ // caches from these method calls instead of creating
451
+ // your own TemplateCache instances
452
+ _.extend(Marionette.TemplateCache, {
453
+ templateCaches: {},
454
+
455
+ // Get the specified template by id. Either
456
+ // retrieves the cached version, or loads it
457
+ // from the DOM.
458
+ get: function(templateId){
459
+ var that = this;
460
+ var cachedTemplate = this.templateCaches[templateId];
461
+
462
+ if (!cachedTemplate){
463
+ cachedTemplate = new Marionette.TemplateCache(templateId);
464
+ this.templateCaches[templateId] = cachedTemplate;
465
+ }
466
+
467
+ return cachedTemplate.load();
468
+ },
469
+
470
+ // Clear templates from the cache. If no arguments
471
+ // are specified, clears all templates:
472
+ // `clear()`
473
+ //
474
+ // If arguments are specified, clears each of the
475
+ // specified templates from the cache:
476
+ // `clear("#t1", "#t2", "...")`
477
+ clear: function(){
478
+ var i;
479
+ var length = arguments.length;
480
+
481
+ if (length > 0){
482
+ for(i=0; i<length; i++){
483
+ delete this.templateCaches[arguments[i]];
484
+ }
485
+ } else {
486
+ this.templateCaches = {};
487
+ }
488
+ }
489
+ });
490
+
491
+ // TemplateCache instance methods, allowing each
492
+ // template cache object to manage it's own state
493
+ // and know whether or not it has been loaded
494
+ _.extend(Marionette.TemplateCache.prototype, {
495
+
496
+ // Internal method to load the template asynchronously.
497
+ load: function(){
498
+ var that = this;
499
+
500
+ // Guard clause to prevent loading this template more than once
501
+ if (this.compiledTemplate){
502
+ return this.compiledTemplate;
503
+ }
504
+
505
+ // Load the template and compile it
506
+ var template = this.loadTemplate(this.templateId);
507
+ this.compiledTemplate = this.compileTemplate(template);
508
+
509
+ return this.compiledTemplate;
510
+ },
511
+
512
+ // Load a template from the DOM, by default. Override
513
+ // this method to provide your own template retrieval,
514
+ // such as asynchronous loading from a server.
515
+ loadTemplate: function(templateId){
516
+ var template = $(templateId).html();
517
+
518
+ if (!template || template.length === 0){
519
+ var msg = "Could not find template: '" + templateId + "'";
520
+ var err = new Error(msg);
521
+ err.name = "NoTemplateError";
522
+ throw err;
523
+ }
524
+
525
+ return template;
526
+ },
527
+
528
+ // Pre-compile the template before caching it. Override
529
+ // this method if you do not need to pre-compile a template
530
+ // (JST / RequireJS for example) or if you want to change
531
+ // the template engine used (Handebars, etc).
532
+ compileTemplate: function(rawTemplate){
533
+ return _.template(rawTemplate);
534
+ }
535
+ });
536
+
537
+
538
+ // Renderer
539
+ // --------
540
+
541
+ // Render a template with data by passing in the template
542
+ // selector and the data to render.
543
+ Marionette.Renderer = {
544
+
545
+ // Render a template with data. The `template` parameter is
546
+ // passed to the `TemplateCache` object to retrieve the
547
+ // template function. Override this method to provide your own
548
+ // custom rendering and template handling for all of Marionette.
549
+ render: function(template, data){
550
+ var templateFunc = typeof template === 'function' ? template : Marionette.TemplateCache.get(template);
551
+ var html = templateFunc(data);
552
+ return html;
553
+ }
554
+ };
555
+
556
+
557
+
558
+ // Marionette Controller
559
+ // ---------------------
560
+ //
561
+ // A multi-purpose object to use as a controller for
562
+ // modules and routers, and as a mediator for workflow
563
+ // and coordination of other objects, views, and more.
564
+ Marionette.Controller = function(options){
565
+ this.options = options || {};
566
+
567
+ Marionette.addEventBinder(this);
568
+
569
+ if (_.isFunction(this.initialize)){
570
+ this.initialize(options);
571
+ }
572
+ };
573
+
574
+ Marionette.Controller.extend = Marionette.extend;
575
+
576
+ // Controller Methods
577
+ // --------------
578
+
579
+ // Ensure it can trigger events with Backbone.Events
580
+ _.extend(Marionette.Controller.prototype, Backbone.Events);
581
+
582
+ // Region
583
+ // ------
584
+ //
585
+ // Manage the visual regions of your composite application. See
586
+ // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
587
+
588
+ Marionette.Region = function(options){
589
+ this.options = options || {};
590
+
591
+ Marionette.addEventBinder(this);
592
+
593
+ this.el = Marionette.getOption(this, "el");
594
+
595
+ if (!this.el){
596
+ var err = new Error("An 'el' must be specified for a region.");
597
+ err.name = "NoElError";
598
+ throw err;
599
+ }
600
+
601
+ if (this.initialize){
602
+ this.initialize.apply(this, arguments);
603
+ }
604
+ };
605
+
606
+
607
+ // Region Type methods
608
+ // -------------------
609
+
610
+ _.extend(Marionette.Region, {
611
+
612
+ // Build an instance of a region by passing in a configuration object
613
+ // and a default region type to use if none is specified in the config.
614
+ //
615
+ // The config object should either be a string as a jQuery DOM selector,
616
+ // a Region type directly, or an object literal that specifies both
617
+ // a selector and regionType:
618
+ //
619
+ // ```js
620
+ // {
621
+ // selector: "#foo",
622
+ // regionType: MyCustomRegion
623
+ // }
624
+ // ```
625
+ //
626
+ buildRegion: function(regionConfig, defaultRegionType){
627
+ var regionIsString = (typeof regionConfig === "string");
628
+ var regionSelectorIsString = (typeof regionConfig.selector === "string");
629
+ var regionTypeIsUndefined = (typeof regionConfig.regionType === "undefined");
630
+ var regionIsType = (typeof regionConfig === "function");
631
+
632
+ if (!regionIsType && !regionIsString && !regionSelectorIsString) {
633
+ throw new Error("Region must be specified as a Region type, a selector string or an object with selector property");
634
+ }
635
+
636
+ var selector, RegionType;
637
+
638
+ // get the selector for the region
639
+
640
+ if (regionIsString) {
641
+ selector = regionConfig;
642
+ }
643
+
644
+ if (regionConfig.selector) {
645
+ selector = regionConfig.selector;
646
+ }
647
+
648
+ // get the type for the region
649
+
650
+ if (regionIsType){
651
+ RegionType = regionConfig;
652
+ }
653
+
654
+ if (!regionIsType && regionTypeIsUndefined) {
655
+ RegionType = defaultRegionType;
656
+ }
657
+
658
+ if (regionConfig.regionType) {
659
+ RegionType = regionConfig.regionType;
660
+ }
661
+
662
+ // build the region instance
663
+
664
+ var regionManager = new RegionType({
665
+ el: selector
666
+ });
667
+
668
+ return regionManager;
669
+ }
670
+
671
+ });
672
+
673
+ // Region Instance Methods
674
+ // -----------------------
675
+
676
+ _.extend(Marionette.Region.prototype, Backbone.Events, {
677
+
678
+ // Displays a backbone view instance inside of the region.
679
+ // Handles calling the `render` method for you. Reads content
680
+ // directly from the `el` attribute. Also calls an optional
681
+ // `onShow` and `close` method on your view, just after showing
682
+ // or just before closing the view, respectively.
683
+ show: function(view){
684
+
685
+ this.ensureEl();
686
+ this.close();
687
+
688
+ view.render();
689
+ this.open(view);
690
+
691
+ Marionette.triggerMethod.call(view, "show");
692
+ Marionette.triggerMethod.call(this, "show", view);
693
+
694
+ this.currentView = view;
695
+ },
696
+
697
+ ensureEl: function(){
698
+ if (!this.$el || this.$el.length === 0){
699
+ this.$el = this.getEl(this.el);
700
+ }
701
+ },
702
+
703
+ // Override this method to change how the region finds the
704
+ // DOM element that it manages. Return a jQuery selector object.
705
+ getEl: function(selector){
706
+ return $(selector);
707
+ },
708
+
709
+ // Override this method to change how the new view is
710
+ // appended to the `$el` that the region is managing
711
+ open: function(view){
712
+ this.$el.empty().append(view.el);
713
+ },
714
+
715
+ // Close the current view, if there is one. If there is no
716
+ // current view, it does nothing and returns immediately.
717
+ close: function(){
718
+ var view = this.currentView;
719
+ if (!view || view.isClosed){ return; }
720
+
721
+ if (view.close) { view.close(); }
722
+ Marionette.triggerMethod.call(this, "close");
723
+
724
+ delete this.currentView;
725
+ },
726
+
727
+ // Attach an existing view to the region. This
728
+ // will not call `render` or `onShow` for the new view,
729
+ // and will not replace the current HTML for the `el`
730
+ // of the region.
731
+ attachView: function(view){
732
+ this.currentView = view;
733
+ },
734
+
735
+ // Reset the region by closing any existing view and
736
+ // clearing out the cached `$el`. The next time a view
737
+ // is shown via this region, the region will re-query the
738
+ // DOM for the region's `el`.
739
+ reset: function(){
740
+ this.close();
741
+ delete this.$el;
742
+ }
743
+ });
744
+
745
+ // Copy the `extend` function used by Backbone's classes
746
+ Marionette.Region.extend = Marionette.extend;
747
+
748
+
313
749
  // Marionette.View
314
750
  // ---------------
315
751
 
@@ -337,17 +773,7 @@ Marionette.View = Backbone.View.extend({
337
773
  // definition or pass a `template: "whatever"` parameter in
338
774
  // to the constructor options.
339
775
  getTemplate: function(){
340
- var template;
341
-
342
- // Get the template from `this.options.template` or
343
- // `this.template`. The `options` takes precedence.
344
- if (this.options && this.options.template){
345
- template = this.options.template;
346
- } else {
347
- template = this.template;
348
- }
349
-
350
- return template;
776
+ return Marionette.getOption(this, "template");
351
777
  },
352
778
 
353
779
  // Mix in template helper methods. Looks for a
@@ -628,7 +1054,8 @@ Marionette.CollectionView = Marionette.View.extend({
628
1054
  // a collection of item views, when the collection is
629
1055
  // empty
630
1056
  showEmptyView: function(){
631
- var EmptyView = this.options.emptyView || this.emptyView;
1057
+ var EmptyView = Marionette.getOption(this, "emptyView");
1058
+
632
1059
  if (EmptyView && !this._showingEmptyView){
633
1060
  this._showingEmptyView = true;
634
1061
  var model = new Backbone.Model();
@@ -650,7 +1077,7 @@ Marionette.CollectionView = Marionette.View.extend({
650
1077
  // or from the `itemView` in the object definition. The "options"
651
1078
  // takes precedence.
652
1079
  getItemView: function(item){
653
- var itemView = this.options.itemView || this.itemView;
1080
+ var itemView = Marionette.getOption(this, "itemView");
654
1081
 
655
1082
  if (!itemView){
656
1083
  var err = new Error("An `itemView` must be specified");
@@ -666,11 +1093,20 @@ Marionette.CollectionView = Marionette.View.extend({
666
1093
  addItemView: function(item, ItemView, index){
667
1094
  var that = this;
668
1095
 
669
- var view = this.buildItemView(item, ItemView);
1096
+ // get the itemViewOptions if any were specified
1097
+ var itemViewOptions;
1098
+ if (_.isFunction(this.itemViewOptions)){
1099
+ itemViewOptions = this.itemViewOptions(item);
1100
+ } else {
1101
+ itemViewOptions = this.itemViewOptions;
1102
+ }
1103
+
1104
+ // build the view
1105
+ var view = this.buildItemView(item, ItemView, itemViewOptions);
670
1106
 
671
1107
  // Store the child view itself so we can properly
672
1108
  // remove and/or close it later
673
- this.storeChild(view);
1109
+ this.storeChild(item, view);
674
1110
  this.triggerMethod("item:added", view);
675
1111
 
676
1112
  // Forward all child item view events through the parent,
@@ -706,17 +1142,9 @@ Marionette.CollectionView = Marionette.View.extend({
706
1142
  },
707
1143
 
708
1144
  // Build an `itemView` for every model in the collection.
709
- buildItemView: function(item, ItemView){
710
- var itemViewOptions;
711
-
712
- if (_.isFunction(this.itemViewOptions)){
713
- itemViewOptions = this.itemViewOptions(item);
714
- } else {
715
- itemViewOptions = this.itemViewOptions;
716
- }
717
-
1145
+ buildItemView: function(item, ItemViewType, itemViewOptions){
718
1146
  var options = _.extend({model: item}, itemViewOptions);
719
- var view = new ItemView(options);
1147
+ var view = new ItemViewType(options);
720
1148
  return view;
721
1149
  },
722
1150
 
@@ -749,8 +1177,8 @@ Marionette.CollectionView = Marionette.View.extend({
749
1177
 
750
1178
  // Store references to all of the child `itemView`
751
1179
  // instances so they can be managed and cleaned up, later.
752
- storeChild: function(view){
753
- this.children[view.model.cid] = view;
1180
+ storeChild: function(item, view){
1181
+ this.children[item.cid] = view;
754
1182
  },
755
1183
 
756
1184
  // Internal method to set up the `children` object for
@@ -811,7 +1239,7 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
811
1239
  // `this.itemView` or Marionette.CompositeView if no `itemView`
812
1240
  // has been defined
813
1241
  getItemView: function(item){
814
- var itemView = this.options.itemView || this.itemView || this.constructor;
1242
+ var itemView = Marionette.getOption(this, "itemView") || this.constructor;
815
1243
 
816
1244
  if (!itemView){
817
1245
  var err = new Error("An `itemView` must be specified");
@@ -832,8 +1260,6 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
832
1260
  data = this.model.toJSON();
833
1261
  }
834
1262
 
835
- data = this.mixinTemplateHelpers(data);
836
-
837
1263
  return data;
838
1264
  },
839
1265
 
@@ -872,6 +1298,7 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
872
1298
  renderModel: function(){
873
1299
  var data = {};
874
1300
  data = this.serializeData();
1301
+ data = this.mixinTemplateHelpers(data);
875
1302
 
876
1303
  var template = this.getTemplate();
877
1304
  return Marionette.Renderer.render(template, data);
@@ -921,177 +1348,6 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
921
1348
  });
922
1349
 
923
1350
 
924
- // Region
925
- // ------
926
- //
927
- // Manage the visual regions of your composite application. See
928
- // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
929
-
930
- Marionette.Region = function(options){
931
- this.options = options || {};
932
-
933
- var el = this.options.el;
934
- delete this.options.el;
935
-
936
- Marionette.addEventBinder(this);
937
-
938
- if (el){
939
- this.el = el;
940
- }
941
-
942
- if (!this.el){
943
- var err = new Error("An 'el' must be specified for a region.");
944
- err.name = "NoElError";
945
- throw err;
946
- }
947
-
948
- if (this.initialize){
949
- this.initialize.apply(this, arguments);
950
- }
951
- };
952
-
953
-
954
- // Region Type methods
955
- // -------------------
956
-
957
- _.extend(Marionette.Region, {
958
-
959
- // Build an instance of a region by passing in a configuration object
960
- // and a default region type to use if none is specified in the config.
961
- //
962
- // The config object should either be a string as a jQuery DOM selector,
963
- // a Region type directly, or an object literal that specifies both
964
- // a selector and regionType:
965
- //
966
- // ```js
967
- // {
968
- // selector: "#foo",
969
- // regionType: MyCustomRegion
970
- // }
971
- // ```
972
- //
973
- buildRegion: function(regionConfig, defaultRegionType){
974
- var regionIsString = (typeof regionConfig === "string");
975
- var regionSelectorIsString = (typeof regionConfig.selector === "string");
976
- var regionTypeIsUndefined = (typeof regionConfig.regionType === "undefined");
977
- var regionIsType = (typeof regionConfig === "function");
978
-
979
- if (!regionIsType && !regionIsString && !regionSelectorIsString) {
980
- throw new Error("Region must be specified as a Region type, a selector string or an object with selector property");
981
- }
982
-
983
- var selector, RegionType;
984
-
985
- // get the selector for the region
986
-
987
- if (regionIsString) {
988
- selector = regionConfig;
989
- }
990
-
991
- if (regionConfig.selector) {
992
- selector = regionConfig.selector;
993
- }
994
-
995
- // get the type for the region
996
-
997
- if (regionIsType){
998
- RegionType = regionConfig;
999
- }
1000
-
1001
- if (!regionIsType && regionTypeIsUndefined) {
1002
- RegionType = defaultRegionType;
1003
- }
1004
-
1005
- if (regionConfig.regionType) {
1006
- RegionType = regionConfig.regionType;
1007
- }
1008
-
1009
- // build the region instance
1010
-
1011
- var regionManager = new RegionType({
1012
- el: selector
1013
- });
1014
-
1015
- return regionManager;
1016
- }
1017
-
1018
- });
1019
-
1020
- // Region Instance Methods
1021
- // -----------------------
1022
-
1023
- _.extend(Marionette.Region.prototype, Backbone.Events, {
1024
-
1025
- // Displays a backbone view instance inside of the region.
1026
- // Handles calling the `render` method for you. Reads content
1027
- // directly from the `el` attribute. Also calls an optional
1028
- // `onShow` and `close` method on your view, just after showing
1029
- // or just before closing the view, respectively.
1030
- show: function(view){
1031
-
1032
- this.ensureEl();
1033
- this.close();
1034
-
1035
- view.render();
1036
- this.open(view);
1037
-
1038
- Marionette.triggerMethod.call(view, "show");
1039
- Marionette.triggerMethod.call(this, "show", view);
1040
-
1041
- this.currentView = view;
1042
- },
1043
-
1044
- ensureEl: function(){
1045
- if (!this.$el || this.$el.length === 0){
1046
- this.$el = this.getEl(this.el);
1047
- }
1048
- },
1049
-
1050
- // Override this method to change how the region finds the
1051
- // DOM element that it manages. Return a jQuery selector object.
1052
- getEl: function(selector){
1053
- return $(selector);
1054
- },
1055
-
1056
- // Override this method to change how the new view is
1057
- // appended to the `$el` that the region is managing
1058
- open: function(view){
1059
- this.$el.html(view.el);
1060
- },
1061
-
1062
- // Close the current view, if there is one. If there is no
1063
- // current view, it does nothing and returns immediately.
1064
- close: function(){
1065
- var view = this.currentView;
1066
- if (!view || view.isClosed){ return; }
1067
-
1068
- if (view.close) { view.close(); }
1069
- Marionette.triggerMethod.call(this, "close");
1070
-
1071
- delete this.currentView;
1072
- },
1073
-
1074
- // Attach an existing view to the region. This
1075
- // will not call `render` or `onShow` for the new view,
1076
- // and will not replace the current HTML for the `el`
1077
- // of the region.
1078
- attachView: function(view){
1079
- this.currentView = view;
1080
- },
1081
-
1082
- // Reset the region by closing any existing view and
1083
- // clearing out the cached `$el`. The next time a view
1084
- // is shown via this region, the region will re-query the
1085
- // DOM for the region's `el`.
1086
- reset: function(){
1087
- this.close();
1088
- delete this.$el;
1089
- }
1090
- });
1091
-
1092
- // Copy the `extend` function used by Backbone's classes
1093
- Marionette.Region.extend = Marionette.extend;
1094
-
1095
1351
  // Layout
1096
1352
  // ------
1097
1353
 
@@ -1180,24 +1436,92 @@ Marionette.Layout = Marionette.ItemView.extend({
1180
1436
  }
1181
1437
  },
1182
1438
 
1183
- // Close all of the regions that have been opened by
1184
- // this layout. This method is called when the layout
1185
- // itself is closed.
1186
- closeRegions: function () {
1187
- var that = this;
1188
- _.each(this.regionManagers, function (manager, name) {
1189
- manager.close();
1190
- });
1191
- },
1439
+ // Close all of the regions that have been opened by
1440
+ // this layout. This method is called when the layout
1441
+ // itself is closed.
1442
+ closeRegions: function () {
1443
+ var that = this;
1444
+ _.each(this.regionManagers, function (manager, name) {
1445
+ manager.close();
1446
+ });
1447
+ },
1448
+
1449
+ // Destroys all of the regions by removing references
1450
+ // from the Layout
1451
+ destroyRegions: function(){
1452
+ var that = this;
1453
+ _.each(this.regionManagers, function (manager, name) {
1454
+ delete that[name];
1455
+ });
1456
+ this.regionManagers = {};
1457
+ }
1458
+ });
1459
+
1460
+
1461
+
1462
+ // AppRouter
1463
+ // ---------
1464
+
1465
+ // Reduce the boilerplate code of handling route events
1466
+ // and then calling a single method on another object.
1467
+ // Have your routers configured to call the method on
1468
+ // your object, directly.
1469
+ //
1470
+ // Configure an AppRouter with `appRoutes`.
1471
+ //
1472
+ // App routers can only take one `controller` object.
1473
+ // It is recommended that you divide your controller
1474
+ // objects in to smaller peices of related functionality
1475
+ // and have multiple routers / controllers, instead of
1476
+ // just one giant router and controller.
1477
+ //
1478
+ // You can also add standard routes to an AppRouter.
1479
+
1480
+ Marionette.AppRouter = Backbone.Router.extend({
1481
+
1482
+ constructor: function(options){
1483
+ Backbone.Router.prototype.constructor.call(this, options);
1484
+
1485
+ if (this.appRoutes){
1486
+ var controller = this.controller;
1487
+ if (options && options.controller) {
1488
+ controller = options.controller;
1489
+ }
1490
+ this.processAppRoutes(controller, this.appRoutes);
1491
+ }
1492
+ },
1493
+
1494
+ // Internal method to process the `appRoutes` for the
1495
+ // router, and turn them in to routes that trigger the
1496
+ // specified method on the specified `controller`.
1497
+ processAppRoutes: function(controller, appRoutes){
1498
+ var method, methodName;
1499
+ var route, routesLength, i;
1500
+ var routes = [];
1501
+ var router = this;
1502
+
1503
+ for(route in appRoutes){
1504
+ if (appRoutes.hasOwnProperty(route)){
1505
+ routes.unshift([route, appRoutes[route]]);
1506
+ }
1507
+ }
1508
+
1509
+ routesLength = routes.length;
1510
+ for (i = 0; i < routesLength; i++){
1511
+ route = routes[i][0];
1512
+ methodName = routes[i][1];
1513
+ method = controller[methodName];
1514
+
1515
+ if (!method){
1516
+ var msg = "Method '" + methodName + "' was not found on the controller";
1517
+ var err = new Error(msg);
1518
+ err.name = "NoMethodError";
1519
+ throw err;
1520
+ }
1192
1521
 
1193
- // Destroys all of the regions by removing references
1194
- // from the Layout
1195
- destroyRegions: function(){
1196
- var that = this;
1197
- _.each(this.regionManagers, function (manager, name) {
1198
- delete that[name];
1199
- });
1200
- this.regionManagers = {};
1522
+ method = _.bind(method, controller);
1523
+ router.route(route, methodName, method);
1524
+ }
1201
1525
  }
1202
1526
  });
1203
1527
 
@@ -1285,73 +1609,6 @@ _.extend(Marionette.Application.prototype, Backbone.Events, {
1285
1609
  // Copy the `extend` function used by Backbone's classes
1286
1610
  Marionette.Application.extend = Marionette.extend;
1287
1611
 
1288
- // AppRouter
1289
- // ---------
1290
-
1291
- // Reduce the boilerplate code of handling route events
1292
- // and then calling a single method on another object.
1293
- // Have your routers configured to call the method on
1294
- // your object, directly.
1295
- //
1296
- // Configure an AppRouter with `appRoutes`.
1297
- //
1298
- // App routers can only take one `controller` object.
1299
- // It is recommended that you divide your controller
1300
- // objects in to smaller peices of related functionality
1301
- // and have multiple routers / controllers, instead of
1302
- // just one giant router and controller.
1303
- //
1304
- // You can also add standard routes to an AppRouter.
1305
-
1306
- Marionette.AppRouter = Backbone.Router.extend({
1307
-
1308
- constructor: function(options){
1309
- Backbone.Router.prototype.constructor.call(this, options);
1310
-
1311
- if (this.appRoutes){
1312
- var controller = this.controller;
1313
- if (options && options.controller) {
1314
- controller = options.controller;
1315
- }
1316
- this.processAppRoutes(controller, this.appRoutes);
1317
- }
1318
- },
1319
-
1320
- // Internal method to process the `appRoutes` for the
1321
- // router, and turn them in to routes that trigger the
1322
- // specified method on the specified `controller`.
1323
- processAppRoutes: function(controller, appRoutes){
1324
- var method, methodName;
1325
- var route, routesLength, i;
1326
- var routes = [];
1327
- var router = this;
1328
-
1329
- for(route in appRoutes){
1330
- if (appRoutes.hasOwnProperty(route)){
1331
- routes.unshift([route, appRoutes[route]]);
1332
- }
1333
- }
1334
-
1335
- routesLength = routes.length;
1336
- for (i = 0; i < routesLength; i++){
1337
- route = routes[i][0];
1338
- methodName = routes[i][1];
1339
- method = controller[methodName];
1340
-
1341
- if (!method){
1342
- var msg = "Method '" + methodName + "' was not found on the controller";
1343
- var err = new Error(msg);
1344
- err.name = "NoMethodError";
1345
- throw err;
1346
- }
1347
-
1348
- method = _.bind(method, controller);
1349
- router.route(route, methodName, method);
1350
- }
1351
- }
1352
- });
1353
-
1354
-
1355
1612
  // Module
1356
1613
  // ------
1357
1614
 
@@ -1567,169 +1824,6 @@ _.extend(Marionette.Module, {
1567
1824
  }
1568
1825
  });
1569
1826
 
1570
- // Template Cache
1571
- // --------------
1572
-
1573
- // Manage templates stored in `<script>` blocks,
1574
- // caching them for faster access.
1575
- Marionette.TemplateCache = function(templateId){
1576
- this.templateId = templateId;
1577
- };
1578
-
1579
- // TemplateCache object-level methods. Manage the template
1580
- // caches from these method calls instead of creating
1581
- // your own TemplateCache instances
1582
- _.extend(Marionette.TemplateCache, {
1583
- templateCaches: {},
1584
-
1585
- // Get the specified template by id. Either
1586
- // retrieves the cached version, or loads it
1587
- // from the DOM.
1588
- get: function(templateId){
1589
- var that = this;
1590
- var cachedTemplate = this.templateCaches[templateId];
1591
-
1592
- if (!cachedTemplate){
1593
- cachedTemplate = new Marionette.TemplateCache(templateId);
1594
- this.templateCaches[templateId] = cachedTemplate;
1595
- }
1596
-
1597
- return cachedTemplate.load();
1598
- },
1599
-
1600
- // Clear templates from the cache. If no arguments
1601
- // are specified, clears all templates:
1602
- // `clear()`
1603
- //
1604
- // If arguments are specified, clears each of the
1605
- // specified templates from the cache:
1606
- // `clear("#t1", "#t2", "...")`
1607
- clear: function(){
1608
- var i;
1609
- var length = arguments.length;
1610
-
1611
- if (length > 0){
1612
- for(i=0; i<length; i++){
1613
- delete this.templateCaches[arguments[i]];
1614
- }
1615
- } else {
1616
- this.templateCaches = {};
1617
- }
1618
- }
1619
- });
1620
-
1621
- // TemplateCache instance methods, allowing each
1622
- // template cache object to manage it's own state
1623
- // and know whether or not it has been loaded
1624
- _.extend(Marionette.TemplateCache.prototype, {
1625
-
1626
- // Internal method to load the template asynchronously.
1627
- load: function(){
1628
- var that = this;
1629
-
1630
- // Guard clause to prevent loading this template more than once
1631
- if (this.compiledTemplate){
1632
- return this.compiledTemplate;
1633
- }
1634
-
1635
- // Load the template and compile it
1636
- var template = this.loadTemplate(this.templateId);
1637
- this.compiledTemplate = this.compileTemplate(template);
1638
-
1639
- return this.compiledTemplate;
1640
- },
1641
-
1642
- // Load a template from the DOM, by default. Override
1643
- // this method to provide your own template retrieval,
1644
- // such as asynchronous loading from a server.
1645
- loadTemplate: function(templateId){
1646
- var template = $(templateId).html();
1647
-
1648
- if (!template || template.length === 0){
1649
- var msg = "Could not find template: '" + templateId + "'";
1650
- var err = new Error(msg);
1651
- err.name = "NoTemplateError";
1652
- throw err;
1653
- }
1654
-
1655
- return template;
1656
- },
1657
-
1658
- // Pre-compile the template before caching it. Override
1659
- // this method if you do not need to pre-compile a template
1660
- // (JST / RequireJS for example) or if you want to change
1661
- // the template engine used (Handebars, etc).
1662
- compileTemplate: function(rawTemplate){
1663
- return _.template(rawTemplate);
1664
- }
1665
- });
1666
-
1667
-
1668
- // Renderer
1669
- // --------
1670
-
1671
- // Render a template with data by passing in the template
1672
- // selector and the data to render.
1673
- Marionette.Renderer = {
1674
-
1675
- // Render a template with data. The `template` parameter is
1676
- // passed to the `TemplateCache` object to retrieve the
1677
- // template function. Override this method to provide your own
1678
- // custom rendering and template handling for all of Marionette.
1679
- render: function(template, data){
1680
- var templateFunc = typeof template === 'function' ? template : Marionette.TemplateCache.get(template);
1681
- var html = templateFunc(data);
1682
- return html;
1683
- }
1684
- };
1685
-
1686
-
1687
- // Callbacks
1688
- // ---------
1689
-
1690
- // A simple way of managing a collection of callbacks
1691
- // and executing them at a later point in time, using jQuery's
1692
- // `Deferred` object.
1693
- Marionette.Callbacks = function(){
1694
- this._deferred = $.Deferred();
1695
- this._callbacks = [];
1696
- };
1697
-
1698
- _.extend(Marionette.Callbacks.prototype, {
1699
-
1700
- // Add a callback to be executed. Callbacks added here are
1701
- // guaranteed to execute, even if they are added after the
1702
- // `run` method is called.
1703
- add: function(callback, contextOverride){
1704
- this._callbacks.push({cb: callback, ctx: contextOverride});
1705
-
1706
- this._deferred.done(function(context, options){
1707
- if (contextOverride){ context = contextOverride; }
1708
- callback.call(context, options);
1709
- });
1710
- },
1711
-
1712
- // Run all registered callbacks with the context specified.
1713
- // Additional callbacks can be added after this has been run
1714
- // and they will still be executed.
1715
- run: function(options, context){
1716
- this._deferred.resolve(context, options);
1717
- },
1718
-
1719
- // Resets the list of callbacks to be run, allowing the same list
1720
- // to be run multiple times - whenever the `run` method is called.
1721
- reset: function(){
1722
- var that = this;
1723
- var callbacks = this._callbacks;
1724
- this._deferred = $.Deferred();
1725
- this._callbacks = [];
1726
- _.each(callbacks, function(cb){
1727
- that.add(cb.cb, cb.ctx);
1728
- });
1729
- }
1730
- });
1731
-
1732
-
1733
1827
 
1734
1828
  return Marionette;
1735
1829
  })(Backbone, _, $ || window.jQuery || window.Zepto || window.ender);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marionette-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta3
4
+ version: 1.0.0.beta4
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors: