kraken-js 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,797 @@
1
+ // Backbone.Marionette v0.7.0
2
+ //
3
+ // Copyright (C)2011 Derick Bailey, Muted Solutions, LLC
4
+ // Distributed Under MIT License
5
+ //
6
+ // Documentation and Full License Available at:
7
+ // http://github.com/derickbailey/backbone.marionette
8
+ Backbone.Marionette = (function(Backbone, _, $){
9
+ var Marionette = {};
10
+
11
+ Marionette.version = "0.7.0";
12
+
13
+ // Marionette.View
14
+ // ---------------
15
+
16
+ // The core view type that other Marionette views extend from.
17
+ Marionette.View = Backbone.View.extend({
18
+ // Get the template or template id/selector for this view
19
+ // instance. You can set a `template` attribute in the view
20
+ // definition or pass a `template: "whatever"` parameter in
21
+ // to the constructor options. The `template` can also be
22
+ // a function that returns a selector string.
23
+ getTemplateSelector: function(){
24
+ var template;
25
+
26
+ // Get the template from `this.options.template` or
27
+ // `this.template`. The `options` takes precedence.
28
+ if (this.options && this.options.template){
29
+ template = this.options.template;
30
+ } else {
31
+ template = this.template;
32
+ }
33
+
34
+ // check if it's a function and execute it, if it is
35
+ if (_.isFunction(template)){
36
+ template = template.call(this);
37
+ }
38
+
39
+ return template;
40
+ },
41
+
42
+ // Default `close` implementation, for removing a view from the
43
+ // DOM and unbinding it. Regions will call this method
44
+ // for you. You can specify an `onClose` method in your view to
45
+ // add custom code that is called after the view is closed.
46
+ close: function(){
47
+ this.beforeClose && this.beforeClose();
48
+
49
+ this.unbindAll();
50
+ this.remove();
51
+
52
+ this.onClose && this.onClose();
53
+ this.trigger('close');
54
+ this.unbind();
55
+ }
56
+ });
57
+
58
+ // Item View
59
+ // ---------
60
+
61
+ // A single item view implementation that contains code for rendering
62
+ // with underscore.js templates, serializing the view's model or collection,
63
+ // and calling several methods on extended views, such as `onRender`.
64
+ Marionette.ItemView = Marionette.View.extend({
65
+ constructor: function(){
66
+ var args = slice.call(arguments);
67
+ Marionette.View.prototype.constructor.apply(this, args);
68
+
69
+ _.bindAll(this, "render");
70
+
71
+ this.initialEvents();
72
+ },
73
+
74
+ // Configured the initial events that the item view
75
+ // binds to. Override this method to prevent the initial
76
+ // events, or to add your own initial events.
77
+ initialEvents: function(){
78
+ if (this.collection){
79
+ this.bindTo(this.collection, "reset", this.render, this);
80
+ }
81
+ },
82
+
83
+ // Serialize the model or collection for the view. If a model is
84
+ // found, `.toJSON()` is called. If a collection is found, `.toJSON()`
85
+ // is also called, but is used to populate an `items` array in the
86
+ // resulting data. If both are found, defaults to the model.
87
+ // You can override the `serializeData` method in your own view
88
+ // definition, to provide custom serialization for your view's data.
89
+ serializeData: function(){
90
+ var data;
91
+
92
+ if (this.model) { data = this.model.toJSON(); }
93
+ else if (this.collection) {
94
+ data = { items: this.collection.toJSON() };
95
+ }
96
+
97
+ return data;
98
+ },
99
+
100
+ // Render the view, defaulting to underscore.js templates.
101
+ // You can override this in your view definition.
102
+ render: function(){
103
+ var that = this;
104
+
105
+ var deferredRender = $.Deferred();
106
+ var template = this.getTemplateSelector();
107
+ var deferredData = this.serializeData();
108
+
109
+ this.beforeRender && this.beforeRender();
110
+ this.trigger("item:before:render", that);
111
+
112
+ $.when(deferredData).then(function(data) {
113
+ var asyncRender = Marionette.Renderer.render(template, data);
114
+ $.when(asyncRender).then(function(html){
115
+ that.$el.html(html);
116
+ that.onRender && that.onRender();
117
+ that.trigger("item:rendered", that);
118
+ that.trigger("render", that);
119
+ deferredRender.resolve();
120
+ });
121
+ });
122
+
123
+ return deferredRender.promise();
124
+ },
125
+
126
+ // Override the default close event to add a few
127
+ // more events that are triggered.
128
+ close: function(){
129
+ this.trigger('item:before:close');
130
+ Marionette.View.prototype.close.apply(this, arguments);
131
+ this.trigger('item:closed');
132
+ }
133
+ });
134
+
135
+ // Collection View
136
+ // ---------------
137
+
138
+ // A view that iterates over a Backbone.Collection
139
+ // and renders an individual ItemView for each model.
140
+ Marionette.CollectionView = Marionette.View.extend({
141
+ constructor: function(){
142
+ Marionette.View.prototype.constructor.apply(this, arguments);
143
+
144
+ _.bindAll(this, "addItemView", "render");
145
+ this.initialEvents();
146
+ },
147
+
148
+ // Configured the initial events that the collection view
149
+ // binds to. Override this method to prevent the initial
150
+ // events, or to add your own initial events.
151
+ initialEvents: function(){
152
+ if (this.collection){
153
+ this.bindTo(this.collection, "add", this.addChildView, this);
154
+ this.bindTo(this.collection, "remove", this.removeItemView, this);
155
+ this.bindTo(this.collection, "reset", this.render, this);
156
+ }
157
+ },
158
+
159
+ // Handle a child item added to the collection
160
+ addChildView: function(item){
161
+ var ItemView = this.getItemView();
162
+ return this.addItemView(item, ItemView);
163
+ },
164
+
165
+ // Loop through all of the items and render
166
+ // each of them with the specified `itemView`.
167
+ render: function(){
168
+ var that = this;
169
+ var deferredRender = $.Deferred();
170
+ var promises = [];
171
+ var ItemView = this.getItemView();
172
+
173
+ this.beforeRender && this.beforeRender();
174
+ this.trigger("collection:before:render", this);
175
+
176
+ this.closeChildren();
177
+ this.collection && this.collection.each(function(item){
178
+ var promise = that.addItemView(item, ItemView);
179
+ promises.push(promise);
180
+ });
181
+
182
+ deferredRender.done(function(){
183
+ this.onRender && this.onRender();
184
+ this.trigger("collection:rendered", this);
185
+ });
186
+
187
+ $.when(promises).then(function(){
188
+ deferredRender.resolveWith(that);
189
+ });
190
+
191
+ return deferredRender.promise();
192
+ },
193
+
194
+ // Retrieve the itemView type, either from `this.options.itemView`
195
+ // or from the `itemView` in the object definition. The "options"
196
+ // takes precedence.
197
+ getItemView: function(){
198
+ var itemView = this.options.itemView || this.itemView;
199
+
200
+ if (!itemView){
201
+ var err = new Error("An `itemView` must be specified");
202
+ err.name = "NoItemViewError";
203
+ throw err;
204
+ }
205
+
206
+ return itemView;
207
+ },
208
+
209
+ // Render the child item's view and add it to the
210
+ // HTML for the collection view.
211
+ addItemView: function(item, ItemView){
212
+ var that = this;
213
+
214
+ var view = this.buildItemView(item, ItemView);
215
+ this.storeChild(view);
216
+ this.trigger("item:added", view);
217
+
218
+ var viewRendered = view.render();
219
+ $.when(viewRendered).then(function(){
220
+ that.appendHtml(that, view);
221
+ });
222
+
223
+ return viewRendered;
224
+ },
225
+
226
+ // Build an `itemView` for every model in the collection.
227
+ buildItemView: function(item, ItemView){
228
+ var view = new ItemView({
229
+ model: item
230
+ });
231
+ return view;
232
+ },
233
+
234
+ // Remove the child view and close it
235
+ removeItemView: function(item){
236
+ var view = this.children[item.cid];
237
+ if (view){
238
+ view.close();
239
+ delete this.children[item.cid];
240
+ }
241
+ this.trigger("item:removed", view);
242
+ },
243
+
244
+ // Append the HTML to the collection's `el`.
245
+ // Override this method to do something other
246
+ // then `.append`.
247
+ appendHtml: function(collectionView, itemView){
248
+ collectionView.$el.append(itemView.el);
249
+ },
250
+
251
+ // Store references to all of the child `itemView`
252
+ // instances so they can be managed and cleaned up, later.
253
+ storeChild: function(view){
254
+ if (!this.children){
255
+ this.children = {};
256
+ }
257
+ this.children[view.model.cid] = view;
258
+ },
259
+
260
+ // Handle cleanup and other closing needs for
261
+ // the collection of views.
262
+ close: function(){
263
+ this.trigger("collection:before:close");
264
+ this.closeChildren();
265
+ Marionette.View.prototype.close.apply(this, arguments);
266
+ this.trigger("collection:closed");
267
+ },
268
+
269
+ closeChildren: function(){
270
+ if (this.children){
271
+ _.each(this.children, function(childView){
272
+ childView.close();
273
+ });
274
+ }
275
+ }
276
+ });
277
+
278
+ // Composite View
279
+ // --------------
280
+
281
+ // Used for rendering a branch-leaf, hierarchical structure.
282
+ // Extends directly from CollectionView and also renders an
283
+ // an item view as `modelView`, for the top leaf
284
+ Marionette.CompositeView = Marionette.CollectionView.extend({
285
+ constructor: function(options){
286
+ Marionette.CollectionView.apply(this, arguments);
287
+ this.itemView = this.getItemView();
288
+ },
289
+
290
+ // Retrieve the `itemView` to be used when rendering each of
291
+ // the items in the collection. The default is to return
292
+ // `this.itemView` or Marionette.CompositeView if no `itemView`
293
+ // has been defined
294
+ getItemView: function(){
295
+ return this.itemView || this.constructor;
296
+ },
297
+
298
+ // Renders the model once, and the collection once. Calling
299
+ // this again will tell the model's view to re-render itself
300
+ // but the collection will not re-render.
301
+ render: function(){
302
+ var that = this;
303
+ var compositeRendered = $.Deferred();
304
+
305
+ var modelIsRendered = this.renderModel();
306
+ $.when(modelIsRendered).then(function(html){
307
+ that.$el.html(html);
308
+ that.trigger("composite:model:rendered");
309
+ that.trigger("render");
310
+
311
+ var collectionIsRendered = that.renderCollection();
312
+ $.when(collectionIsRendered).then(function(){
313
+ compositeRendered.resolve();
314
+ });
315
+ });
316
+
317
+ compositeRendered.done(function(){
318
+ that.trigger("composite:rendered");
319
+ });
320
+
321
+ return compositeRendered.promise();
322
+ },
323
+
324
+ // Render the collection for the composite view
325
+ renderCollection: function(){
326
+ var collectionDeferred = Marionette.CollectionView.prototype.render.apply(this, arguments);
327
+ collectionDeferred.done(function(){
328
+ this.trigger("composite:collection:rendered");
329
+ });
330
+ return collectionDeferred.promise();
331
+ },
332
+
333
+ // Render an individual model, if we have one, as
334
+ // part of a composite view (branch / leaf). For example:
335
+ // a treeview.
336
+ renderModel: function(){
337
+ var data = {};
338
+ if (this.model){
339
+ data = this.model.toJSON();
340
+ }
341
+
342
+ var template = this.getTemplateSelector();
343
+ return Marionette.Renderer.render(template, data);
344
+ }
345
+ });
346
+
347
+ // Region
348
+ // ------
349
+
350
+ // Manage the visual regions of your composite application. See
351
+ // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
352
+ Marionette.Region = function(options){
353
+ this.options = options || {};
354
+
355
+ _.extend(this, options);
356
+
357
+ if (!this.el){
358
+ var err = new Error("An 'el' must be specified");
359
+ err.name = "NoElError";
360
+ throw err;
361
+ }
362
+ };
363
+
364
+ _.extend(Marionette.Region.prototype, Backbone.Events, {
365
+
366
+ // Displays a backbone view instance inside of the region.
367
+ // Handles calling the `render` method for you. Reads content
368
+ // directly from the `el` attribute. Also calls an optional
369
+ // `onShow` and `close` method on your view, just after showing
370
+ // or just before closing the view, respectively.
371
+ show: function(view, appendMethod){
372
+ this.ensureEl();
373
+
374
+ this.close();
375
+ this.open(view, appendMethod);
376
+
377
+ this.currentView = view;
378
+ },
379
+
380
+ ensureEl: function(){
381
+ if (!this.$el || this.$el.length == 0){
382
+ this.$el = this.getEl(this.el);
383
+ }
384
+ },
385
+
386
+ // Override this method to change how the region finds the
387
+ // DOM element that it manages. Return a jQuery selector object.
388
+ getEl: function(selector){
389
+ return $(selector);
390
+ },
391
+
392
+ // Internal method to render and display a view. Not meant
393
+ // to be called from any external code.
394
+ open: function(view, appendMethod){
395
+ var that = this;
396
+ appendMethod = appendMethod || "html";
397
+
398
+ $.when(view.render()).then(function () {
399
+ that.$el[appendMethod](view.el);
400
+ view.onShow && view.onShow();
401
+ view.trigger("show");
402
+ that.trigger("view:show", view);
403
+ });
404
+ },
405
+
406
+ // Close the current view, if there is one. If there is no
407
+ // current view, it does nothing and returns immediately.
408
+ close: function(){
409
+ var view = this.currentView;
410
+ if (!view){ return; }
411
+
412
+ view.close && view.close();
413
+ this.trigger("view:closed", view);
414
+
415
+ delete this.currentView;
416
+ },
417
+
418
+ // Attach an existing view to the region. This
419
+ // will not call `render` or `onShow` for the new view,
420
+ // and will not replace the current HTML for the `el`
421
+ // of the region.
422
+ attachView: function(view){
423
+ this.currentView = view;
424
+ }
425
+ });
426
+
427
+ // Layout
428
+ // ------
429
+
430
+ // Formerly known as Composite Region.
431
+ //
432
+ // Used for managing application layouts, nested layouts and
433
+ // multiple regions within an application or sub-application.
434
+ //
435
+ // A specialized view type that renders an area of HTML and then
436
+ // attaches `Region` instances to the specified `regions`.
437
+ // Used for composite view management and sub-application areas.
438
+ Marionette.Layout = Marionette.ItemView.extend({
439
+ constructor: function () {
440
+ this.vent = new Backbone.Marionette.EventAggregator();
441
+ Backbone.Marionette.ItemView.apply(this, arguments);
442
+ this.regionManagers = {};
443
+ },
444
+
445
+ render: function () {
446
+ this.initializeRegions();
447
+ return Backbone.Marionette.ItemView.prototype.render.call(this, arguments);
448
+ },
449
+
450
+ close: function () {
451
+ this.closeRegions();
452
+ Backbone.Marionette.ItemView.prototype.close.call(this, arguments);
453
+ },
454
+
455
+ initializeRegions: function () {
456
+ var that = this;
457
+ _.each(this.regions, function (selector, name) {
458
+ var regionManager = new Backbone.Marionette.Region({
459
+ el: selector,
460
+
461
+ getEl: function(selector){
462
+ return that.$(selector);
463
+ }
464
+ });
465
+ that.regionManagers[name] = regionManager;
466
+ that[name] = regionManager;
467
+ });
468
+ },
469
+
470
+ closeRegions: function () {
471
+ var that = this;
472
+ _.each(this.regionManagers, function (manager, name) {
473
+ manager.close();
474
+ delete that[name];
475
+ });
476
+ this.regionManagers = {};
477
+ }
478
+ });
479
+
480
+ // AppRouter
481
+ // ---------
482
+
483
+ // Reduce the boilerplate code of handling route events
484
+ // and then calling a single method on another object.
485
+ // Have your routers configured to call the method on
486
+ // your object, directly.
487
+ //
488
+ // Configure an AppRouter with `appRoutes`.
489
+ //
490
+ // App routers can only take one `controller` object.
491
+ // It is reocmmended that you divide your controller
492
+ // objects in to smaller peices of related functionality
493
+ // and have multiple routers / controllers, instead of
494
+ // just one giant router and controller.
495
+ //
496
+ // You can also add standard routes to an AppRouter.
497
+
498
+ Marionette.AppRouter = Backbone.Router.extend({
499
+
500
+ constructor: function(options){
501
+ Backbone.Router.prototype.constructor.call(this, options);
502
+
503
+ if (this.appRoutes){
504
+ var controller = this.controller;
505
+ if (options && options.controller) {
506
+ controller = options.controller;
507
+ }
508
+ this.processAppRoutes(controller, this.appRoutes);
509
+ }
510
+ },
511
+
512
+ processAppRoutes: function(controller, appRoutes){
513
+ var method, methodName;
514
+ var route, routesLength;
515
+ var routes = [];
516
+ var router = this;
517
+
518
+ for(route in appRoutes){
519
+ routes.unshift([route, appRoutes[route]]);
520
+ }
521
+
522
+ routesLength = routes.length;
523
+ for (var i = 0; i < routesLength; i++){
524
+ route = routes[i][0];
525
+ methodName = routes[i][1];
526
+ method = _.bind(controller[methodName], controller);
527
+ router.route(route, methodName, method);
528
+ }
529
+ }
530
+ });
531
+
532
+ // Composite Application
533
+ // ---------------------
534
+
535
+ // Contain and manage the composite application as a whole.
536
+ // Stores and starts up `Region` objects, includes an
537
+ // event aggregator as `app.vent`
538
+ Marionette.Application = function(options){
539
+ this.initCallbacks = new Marionette.Callbacks();
540
+ this.vent = new Marionette.EventAggregator();
541
+ _.extend(this, options);
542
+ };
543
+
544
+ _.extend(Marionette.Application.prototype, Backbone.Events, {
545
+ // Add an initializer that is either run at when the `start`
546
+ // method is called, or run immediately if added after `start`
547
+ // has already been called.
548
+ addInitializer: function(initializer){
549
+ this.initCallbacks.add(initializer);
550
+ },
551
+
552
+ // kick off all of the application's processes.
553
+ // initializes all of the regions that have been added
554
+ // to the app, and runs all of the initializer functions
555
+ start: function(options){
556
+ this.trigger("initialize:before", options);
557
+ this.initCallbacks.run(this, options);
558
+ this.trigger("initialize:after", options);
559
+
560
+ this.trigger("start", options);
561
+ },
562
+
563
+ // Add regions to your app.
564
+ // Accepts a hash of named strings or Region objects
565
+ // addRegions({something: "#someRegion"})
566
+ // addRegions{{something: Region.extend({el: "#someRegion"}) });
567
+ addRegions: function(regions){
568
+ var regionValue, regionObj;
569
+
570
+ for(var region in regions){
571
+ if (regions.hasOwnProperty(region)){
572
+ regionValue = regions[region];
573
+
574
+ if (typeof regionValue === "string"){
575
+ regionObj = new Marionette.Region({
576
+ el: regionValue
577
+ });
578
+ } else {
579
+ regionObj = new regionValue;
580
+ }
581
+
582
+ this[region] = regionObj;
583
+ }
584
+ }
585
+ }
586
+ });
587
+
588
+ // BindTo: Event Binding
589
+ // ---------------------
590
+
591
+ // BindTo facilitates the binding and unbinding of events
592
+ // from objects that extend `Backbone.Events`. It makes
593
+ // unbinding events, even with anonymous callback functions,
594
+ // easy.
595
+ //
596
+ // Thanks to Johnny Oshika for this code.
597
+ // http://stackoverflow.com/questions/7567404/backbone-js-repopulate-or-recreate-the-view/7607853#7607853
598
+ Marionette.BindTo = {
599
+ // Store the event binding in array so it can be unbound
600
+ // easily, at a later point in time.
601
+ bindTo: function (obj, eventName, callback, context) {
602
+ context = context || this;
603
+ obj.on(eventName, callback, context);
604
+
605
+ if (!this.bindings) this.bindings = [];
606
+
607
+ this.bindings.push({
608
+ obj: obj,
609
+ eventName: eventName,
610
+ callback: callback,
611
+ context: context
612
+ });
613
+ },
614
+
615
+ // Unbind all of the events that we have stored.
616
+ unbindAll: function () {
617
+ _.each(this.bindings, function (binding) {
618
+ binding.obj.off(binding.eventName, binding.callback);
619
+ });
620
+
621
+ this.bindings = [];
622
+ }
623
+ };
624
+
625
+ // Callbacks
626
+ // ---------
627
+
628
+ // A simple way of managing a collection of callbacks
629
+ // and executing them at a later point in time, using jQuery's
630
+ // `Deferred` object.
631
+ Marionette.Callbacks = function(){
632
+ this.deferred = $.Deferred();
633
+ this.promise = this.deferred.promise();
634
+ };
635
+
636
+ _.extend(Marionette.Callbacks.prototype, {
637
+
638
+ // Add a callback to be executed. Callbacks added here are
639
+ // guaranteed to execute, even if they are added after the
640
+ // `run` method is called.
641
+ add: function(callback){
642
+ this.promise.done(function(context, options){
643
+ callback.call(context, options);
644
+ });
645
+ },
646
+
647
+ // Run all registered callbacks with the context specified.
648
+ // Additional callbacks can be added after this has been run
649
+ // and they will still be executed.
650
+ run: function(context, options){
651
+ this.deferred.resolve(context, options);
652
+ }
653
+ });
654
+
655
+ // Event Aggregator
656
+ // ----------------
657
+
658
+ // A pub-sub object that can be used to decouple various parts
659
+ // of an application through event-driven architecture.
660
+ Marionette.EventAggregator = function(options){
661
+ _.extend(this, options);
662
+ };
663
+
664
+ _.extend(Marionette.EventAggregator.prototype, Backbone.Events, Marionette.BindTo, {
665
+ // Assumes the event aggregator itself is the
666
+ // object being bound to.
667
+ bindTo: function(eventName, callback, context){
668
+ Marionette.BindTo.bindTo.call(this, this, eventName, callback, context);
669
+ }
670
+ });
671
+
672
+ // Template Cache
673
+ // --------------
674
+
675
+ // Manage templates stored in `<script>` blocks,
676
+ // caching them for faster access.
677
+ Marionette.TemplateCache = {
678
+ templates: {},
679
+ loaders: {},
680
+
681
+ // Get the specified template by id. Either
682
+ // retrieves the cached version, or loads it
683
+ // from the DOM.
684
+ get: function(templateId){
685
+ var that = this;
686
+ var templateRetrieval = $.Deferred();
687
+ var cachedTemplate = this.templates[templateId];
688
+
689
+ if (cachedTemplate){
690
+ templateRetrieval.resolve(cachedTemplate);
691
+ } else {
692
+ var loader = this.loaders[templateId];
693
+ if(loader) {
694
+ templateRetrieval = loader;
695
+ } else {
696
+ this.loaders[templateId] = templateRetrieval;
697
+
698
+ this.loadTemplate(templateId, function(template){
699
+ delete that.loaders[templateId];
700
+ that.templates[templateId] = template;
701
+ templateRetrieval.resolve(template);
702
+ });
703
+ }
704
+
705
+ }
706
+
707
+ return templateRetrieval.promise();
708
+ },
709
+
710
+ // Load a template from the DOM, by default. Override
711
+ // this method to provide your own template retrieval,
712
+ // such as asynchronous loading from a server.
713
+ loadTemplate: function(templateId, callback){
714
+ var template = $(templateId).html();
715
+ callback.call(this, template);
716
+ },
717
+
718
+ // Clear templates from the cache. If no arguments
719
+ // are specified, clears all templates:
720
+ // `clear()`
721
+ //
722
+ // If arguments are specified, clears each of the
723
+ // specified templates from the cache:
724
+ // `clear("#t1", "#t2", "...")`
725
+ clear: function(){
726
+ var length = arguments.length;
727
+ if (length > 0){
728
+ for(var i=0; i<length; i++){
729
+ delete this.templates[arguments[i]];
730
+ }
731
+ } else {
732
+ this.templates = {};
733
+ }
734
+ }
735
+ };
736
+
737
+ // Renderer
738
+ // --------
739
+
740
+ // Render a template with data by passing in the template
741
+ // selector and the data to render.
742
+ Marionette.Renderer = {
743
+
744
+ // Render a template with data. The `template` parameter is
745
+ // passed to the `TemplateCache` object to retrieve the
746
+ // actual template. Override this method to provide your own
747
+ // custom rendering and template handling for all of Marionette.
748
+ render: function(template, data){
749
+ var that = this;
750
+ var asyncRender = $.Deferred();
751
+
752
+ var templateRetrieval = Marionette.TemplateCache.get(template);
753
+
754
+ $.when(templateRetrieval).then(function(template){
755
+ var html = that.renderTemplate(template, data);
756
+ asyncRender.resolve(html);
757
+ });
758
+
759
+ return asyncRender.promise();
760
+ },
761
+
762
+ // Default implementation uses underscore.js templates. Override
763
+ // this method to use your own templating engine.
764
+ renderTemplate: function(template, data){
765
+ if (!template || template.length === 0){
766
+ var msg = "A template must be specified";
767
+ var err = new Error(msg);
768
+ err.name = "NoTemplateError";
769
+ throw err;
770
+ }
771
+
772
+ var html = _.template(template, data);
773
+ return html;
774
+ }
775
+
776
+ }
777
+
778
+ // Helpers
779
+ // -------
780
+
781
+ // For slicing `arguments` in functions
782
+ var slice = Array.prototype.slice;
783
+
784
+ // Copy the `extend` function used by Backbone's classes
785
+ var extend = Marionette.View.extend;
786
+ Marionette.Region.extend = extend;
787
+ Marionette.Application.extend = extend;
788
+
789
+ // Copy the features of `BindTo` on to these objects
790
+ _.extend(Marionette.View.prototype, Marionette.BindTo);
791
+ _.extend(Marionette.Application.prototype, Marionette.BindTo);
792
+ _.extend(Marionette.Region.prototype, Marionette.BindTo);
793
+
794
+ return Marionette;
795
+ })(Backbone, _, window.jQuery || window.Zepto || window.ender);
796
+
797
+ ;