kraken-js 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ ;