PageRenderTime 22ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/backbone.marionette/0.7.2/amd/backbone.marionette.js

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