couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject [2/2] git commit: updated refs/heads/master to c9532bb
Date Thu, 08 Aug 2013 13:46:45 GMT
Fauxton update to backbone.layoutmanager 0.9.1


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/c9532bb2
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/c9532bb2
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/c9532bb2

Branch: refs/heads/master
Commit: c9532bb236fa521a7901ae885e8187b5dc52ca2e
Parents: 82e76b9
Author: Garren Smith <garren.smith@gmail.com>
Authored: Thu Aug 8 15:45:33 2013 +0200
Committer: Garren Smith <garren.smith@gmail.com>
Committed: Thu Aug 8 15:46:30 2013 +0200

----------------------------------------------------------------------
 src/fauxton/app/api.js                          |   8 +-
 src/fauxton/app/app.js                          |   4 +-
 src/fauxton/app/config.js                       |  11 +-
 src/fauxton/app/resizeColumns.js                |   1 -
 .../assets/js/plugins/backbone.layoutmanager.js | 415 ++++++++++++-------
 5 files changed, 277 insertions(+), 162 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/c9532bb2/src/fauxton/app/api.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/api.js b/src/fauxton/app/api.js
index 57bbff4..fc98866 100644
--- a/src/fauxton/app/api.js
+++ b/src/fauxton/app/api.js
@@ -51,12 +51,12 @@ function(app, Fauxton) {
 
     disableLoader: false,
 
-    hasRendered: function () {
+    /*hasRendered: function () {
       return !!this.__manager__.hasRendered;
-    },
+    },*/
 
     forceRender: function () {
-      this.__manager__.hasRendered = false;
+      this.hasRendered = false;
     }
   });
 
@@ -297,7 +297,7 @@ function(app, Fauxton) {
 
       FauxtonAPI.when(this.establish()).done(function(resp) {
         _.each(routeObject.getViews(), function(view, selector) {
-          if(view.hasRendered()) { return; }
+          if(view.hasRendered) { return; }
 
           if (!routeObject.disableLoader) {
             routeObjectSpinner.stop();

http://git-wip-us.apache.org/repos/asf/couchdb/blob/c9532bb2/src/fauxton/app/app.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/app.js b/src/fauxton/app/app.js
index c638646..77c1b70 100644
--- a/src/fauxton/app/app.js
+++ b/src/fauxton/app/app.js
@@ -45,11 +45,11 @@ function($, _, Backbone, Helpers, Mixins) {
     prefix: "app/",
 
     // Inject app/helper.js for shared functionality across all html templates
-    render: function(template, context) {
+    renderTemplate: function(template, context) {
       return template(_.extend(Helpers, context));
     },
 
-    fetch: function(path) {
+    fetchTemplate: function(path) {
       // Initialize done for use in async-mode
       var done;
 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/c9532bb2/src/fauxton/app/config.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/config.js b/src/fauxton/app/config.js
index 6b9ac8a..cbbcb4d 100644
--- a/src/fauxton/app/config.js
+++ b/src/fauxton/app/config.js
@@ -13,6 +13,7 @@ require.config({
     jquery: "../assets/js/libs/jquery",
     lodash: "../assets/js/libs/lodash",
     backbone: "../assets/js/libs/backbone",
+    "backbone.layoutmanger": "../assets/js/plugins/backbone.layoutmanager",
     bootstrap: "../assets/js/libs/bootstrap",
     codemirror: "../assets/js/libs/codemirror",
     jshint: "../assets/js/libs/jshint",
@@ -23,6 +24,13 @@ require.config({
 
   baseUrl: '/',
 
+  map: {
+    "*": {
+      'underscore': 'lodash'
+    }
+
+  },
+
   shim: {
     // Backbone library depends on lodash and jQuery.
     backbone: {
@@ -45,9 +53,6 @@ require.config({
       exports: "JSHINT"
     },
 
-    // Backbone.LayoutManager depends on Backbone.
-    "plugins/backbone.layoutmanager": ["backbone"],
-
     "plugins/codemirror-javascript": ["codemirror"],
 
     "plugins/prettify": [],

http://git-wip-us.apache.org/repos/asf/couchdb/blob/c9532bb2/src/fauxton/app/resizeColumns.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/resizeColumns.js b/src/fauxton/app/resizeColumns.js
index d8bbacd..0073690 100644
--- a/src/fauxton/app/resizeColumns.js
+++ b/src/fauxton/app/resizeColumns.js
@@ -55,7 +55,6 @@ function(mixins) {
     },
     onResizeHandler: function (){
       //if there is an override, do that instead
-      console.log("onResizeHandler");
       if (this.options.onResizeHandler){
         this.options.onResizeHandler();
       } else {

http://git-wip-us.apache.org/repos/asf/couchdb/blob/c9532bb2/src/fauxton/assets/js/plugins/backbone.layoutmanager.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/plugins/backbone.layoutmanager.js b/src/fauxton/assets/js/plugins/backbone.layoutmanager.js
index aff39b3..b8296b4 100644
--- a/src/fauxton/assets/js/plugins/backbone.layoutmanager.js
+++ b/src/fauxton/assets/js/plugins/backbone.layoutmanager.js
@@ -1,29 +1,36 @@
 /*!
- * backbone.layoutmanager.js v0.8.8
+ * backbone.layoutmanager.js v0.9.1
  * Copyright 2013, Tim Branyen (@tbranyen)
  * backbone.layoutmanager.js may be freely distributed under the MIT license.
  */
-(function(window) {
+(function(window, factory) {
+  "use strict";
+  var Backbone = window.Backbone;
+
+  // AMD. Register as an anonymous module.  Wrap in function so we have access
+  // to root via `this`.
+  if (typeof define === "function" && define.amd) {
+    return define(["backbone", "underscore", "jquery"], function() {
+      return factory.apply(window, arguments);
+    });
+  }
 
+  // Browser globals.
+  Backbone.Layout = factory.call(window, Backbone, window._, Backbone.$);
+}(typeof global === "object" ? global : this, function (Backbone, _, $) {
 "use strict";
 
+// Create a reference to the global object. In browsers, it will map to the
+// `window` object; in Node, it will be `global`.
+var window = this;
+
 // Hoisted, referenced at the bottom of the source.  This caches a list of all
 // LayoutManager options at definition time.
 var keys;
 
-// Localize global dependency references.
-var Backbone = window.Backbone;
-var _ = window._;
-var $ = Backbone.$;
-
-// Used for issuing warnings and debugging.
-var warn = window.console && window.console.warn;
-var trace = window.console && window.console.trace;
-
 // Maintain references to the two `Backbone.View` functions that are
 // overwritten so that they can be proxied.
 var _configure = Backbone.View.prototype._configure;
-var render = Backbone.View.prototype.render;
 
 // Cache these methods for performance.
 var aPush = Array.prototype.push;
@@ -32,6 +39,50 @@ var aSplice = Array.prototype.splice;
 
 // LayoutManager is a wrapper around a `Backbone.View`.
 var LayoutManager = Backbone.View.extend({
+  _render: function(manage, options) {
+    // Keep the view consistent between callbacks and deferreds.
+    var view = this;
+    // Shorthand the manager.
+    var manager = view.__manager__;
+    // Cache these properties.
+    var beforeRender = options.beforeRender;
+    // Create a deferred instead of going off
+    var def = options.deferred();
+
+    // Ensure all nested Views are properly scrubbed if re-rendering.
+    if (view.hasRendered) {
+      view._removeViews();
+    }
+
+    // This continues the render flow after `beforeRender` has completed.
+    manager.callback = function() {
+      // Clean up asynchronous manager properties.
+      delete manager.isAsync;
+      delete manager.callback;
+
+      // Always emit a beforeRender event.
+      view.trigger("beforeRender", view);
+
+      // Render!
+      manage(view, options).render().then(function() {
+        // Complete this deferred once resolved.
+        def.resolve();
+      });
+    };
+
+    // If a beforeRender function is defined, call it.
+    if (beforeRender) {
+      beforeRender.call(view, view);
+    }
+
+    if (!manager.isAsync) {
+      manager.callback();
+    }
+
+    // Return this intermediary promise.
+    return def.promise();
+  },
+      
   // This named function allows for significantly easier debugging.
   constructor: function Layout(options) {
     // Options may not always be passed to the constructor, this ensures it is
@@ -45,6 +96,54 @@ var LayoutManager = Backbone.View.extend({
     Backbone.View.call(this, options);
   },
 
+  // This method is used within specific methods to indicate that they should
+  // be treated as asynchronous.  This method should only be used within the
+  // render chain, otherwise unexpected behavior may occur.
+  async: function() {
+    var manager = this.__manager__;
+
+    // Set this View's action to be asynchronous.
+    manager.isAsync = true;
+
+    // Return the callback.
+    return manager.callback;
+  },
+
+  promise: function() {
+    return this.__manager__.renderDeferred.promise();
+  },
+
+  // Sometimes it's desirable to only render the child views under the parent.
+  // This is typical for a layout that does not change.  This method will
+  // iterate over the child Views and aggregate all child render promises and
+  // return the parent View.  The internal `promise()` method will return the
+  // aggregate promise that resolves once all children have completed their
+  // render.
+  renderViews: function() {
+    var root = this;
+    var manager = root.__manager__;
+    var options = root.getAllOptions();
+    var newDeferred = options.deferred();
+
+    // Collect all promises from rendering the child views and wait till they
+    // all complete.
+    var promises = root.getViews().map(function(view) {
+      return view.render().__manager__.renderDeferred;
+    }).value();
+
+    // Simulate a parent render to remain consistent.
+    manager.renderDeferred = newDeferred.promise();
+
+    // Once all child views have completed rendering, resolve parent deferred
+    // with the correct context.
+    options.when(promises).then(function() {
+      newDeferred.resolveWith(root, [root]);
+    });
+
+    // Allow this method to be chained.
+    return root;
+  },
+
   // Shorthand to `setView` function with the `insert` flag set.
   insertView: function(selector, view) {
     // If the `view` argument exists, then a selector was passed in.  This code
@@ -97,7 +196,13 @@ var LayoutManager = Backbone.View.extend({
     // elements. The value at the specified filter may be undefined, a single
     // view, or an array of views; in all cases, chain on a flat array.
     if (typeof fn === "string") {
+      fn = this.sections[fn] || fn;
       views = this.views[fn] || [];
+
+      // If Views is undefined you are concatenating an `undefined` to an array
+      // resulting in a value being returned.  Defaulting to an array prevents
+      // this.
+      //return _.chain([].concat(views || []));
       return _.chain([].concat(views));
     }
 
@@ -134,7 +239,7 @@ var LayoutManager = Backbone.View.extend({
   // Must definitely wrap any render method passed in or defaults to a
   // typical render function `return layout(this).render()`.
   setView: function(name, view, insert) {
-    var manager, existing, options;
+    var manager, options, selector;
     // Parent view, the one you are setting a View on.
     var root = this;
 
@@ -145,20 +250,15 @@ var LayoutManager = Backbone.View.extend({
       name = "";
     }
 
-    // If the parent views object doesn't exist... create it.
-    this.views = this.views || {};
-
     // Shorthand the `__manager__` property.
     manager = view.__manager__;
 
-    // Shorthand the View that potentially already exists.
-    existing = this.views[name];
-
     // If the View has not been properly set up, throw an Error message
     // indicating that the View needs `manage: true` set.
     if (!manager) {
-      throw new Error("Please set `View#manage` property with selector '" +
-        name + "' to `true`.");
+      throw new Error("The argument associated with selector '" + name +
+        "' is defined and a View.  Set `manage` property to true for " +
+        "Backbone.View instances.");
     }
 
     // Assign options.
@@ -168,43 +268,34 @@ var LayoutManager = Backbone.View.extend({
     manager.parent = root;
 
     // Add reference to the placement selector used.
-    manager.selector = name;
+    selector = manager.selector = root.sections[name] || name;
 
-    // Set up event bubbling, inspired by Backbone.ViewMaster.  Do not bubble
-    // internal events that are triggered.
-    view.on("all", function(name) {
-      if (name !== "beforeRender" && name !== "afterRender") {
-        root.trigger.apply(root, arguments);
-      }
-    }, view);
+    // Call the `setup` method, since we now have a relationship created.
+    _.result(view, "setup");
 
     // Code path is less complex for Views that are not being inserted.  Simply
     // remove existing Views and bail out with the assignment.
     if (!insert) {
       // If the View we are adding has already been rendered, simply inject it
       // into the parent.
-      if (manager.hasRendered) {
+      if (view.hasRendered) {
         // Apply the partial.
         options.partial(root.$el, view.$el, root.__manager__, manager);
       }
 
       // Ensure remove is called when swapping View's.
-      if (existing) {
-        // If the views are an array, iterate and remove each individually.
-        _.each(aConcat.call([], existing), function(nestedView) {
-          nestedView.remove();
-        });
-      }
+      root.removeView(name);
 
       // Assign to main views object and return for chainability.
-      return this.views[name] = view;
+      return root.views[selector] = view;
     }
 
-    // Ensure this.views[name] is an array and push this View to the end.
-    this.views[name] = aConcat.call([], existing || [], view);
+    // Ensure this.views[selector] is an array and push this View to
+    // the end.
+    root.views[selector] = aConcat.call([], root.views[name] || [], view);
 
-    // Put the view into `insert` mode.
-    manager.insert = true;
+    // Put the parent view into `insert` mode.
+    root.__manager__.insert = true;
 
     return view;
   },
@@ -244,13 +335,23 @@ var LayoutManager = Backbone.View.extend({
 
     // Triggered once the render has succeeded.
     function resolve() {
-      var next, afterRender;
+      var next;
+
+      // Insert all subViews into the parent at once.
+      _.each(root.views, function(views, selector) {
+        // Fragments aren't used on arrays of subviews.
+        if (_.isArray(views)) {
+          options.htmlBatch(root, views, selector);
+        }
+      });
 
-      // If there is a parent, attach.
-      if (parent) {
+      // If there is a parent and we weren't attached to it via the previous
+      // method (single view), attach.
+      if (parent && !manager.insertedViaFragment) {
         if (!options.contains(parent.el, root.el)) {
-          // Apply the partial.
-          options.partial(parent.$el, root.$el, rentManager, manager);
+          // Apply the partial using parent's html() method.
+          parent.getAllOptions().partial(parent.$el, root.$el, rentManager,
+            manager);
         }
       }
 
@@ -258,7 +359,7 @@ var LayoutManager = Backbone.View.extend({
       root.delegateEvents();
 
       // Set this View as successfully rendered.
-      manager.hasRendered = true;
+      root.hasRendered = true;
 
       // Only process the queue if it exists.
       if (next = manager.queue.shift()) {
@@ -275,6 +376,7 @@ var LayoutManager = Backbone.View.extend({
       // Reusable function for triggering the afterRender callback and event
       // and setting the hasRendered flag.
       function completeRender() {
+        var console = window.console;
         var afterRender = options.afterRender;
 
         if (afterRender) {
@@ -289,12 +391,14 @@ var LayoutManager = Backbone.View.extend({
         if (manager.noel && root.$el.length > 1) {
           // Do not display a warning while testing or if warning suppression
           // is enabled.
-          if (warn && !options.suppressWarnings) { 
-            window.console.warn("Using `el: false` with multiple top level " +
-              "elements is not supported.");
+          if (_.isFunction(console.warn) && !options.suppressWarnings) {
+            console.warn("`el: false` with multiple top level elements is " +
+              "not supported.");
 
             // Provide a stack trace if available to aid with debugging.
-            if (trace) { window.console.trace(); }
+            if (_.isFunction(console.trace)) {
+              console.trace();
+            }
           }
         }
       }
@@ -317,9 +421,6 @@ var LayoutManager = Backbone.View.extend({
     // Actually facilitate a render.
     function actuallyRender() {
       var options = root.getAllOptions();
-      var manager = root.__manager__;
-      var parent = manager.parent;
-      var rentManager = parent && parent.__manager__;
 
       // The `_viewRender` method is broken out to abstract away from having
       // too much code in `actuallyRender`.
@@ -339,20 +440,18 @@ var LayoutManager = Backbone.View.extend({
           // If items are being inserted, they will be in a non-zero length
           // Array.
           if (insert && view.length) {
-            // Schedule each view to be rendered in order and return a promise
-            // representing the result of the final rendering.
-            return _.reduce(view.slice(1), function(prevRender, view) {
-              return prevRender.then(function() {
-                return view.render();
-              });
-            // The first view should be rendered immediately, and the resulting
-            // promise used to initialize the reduction.
-            }, view[0].render());
+            // Mark each subview's manager so they don't attempt to attach by
+            // themselves.  Return a single promise representing the entire
+            // render.
+            return options.when(_.map(view, function(subView) {
+              subView.__manager__.insertedViaFragment = true;
+              return subView.render().__manager__.renderDeferred;
+            }));
           }
 
           // Only return the fetch deferred, resolve the main deferred after
           // the element has been attached to it's parent.
-          return !insert ? view.render() : view;
+          return !insert ? view.render().__manager__.renderDeferred : view;
         });
 
         // Once all nested Views have been rendered, resolve this View's
@@ -373,13 +472,14 @@ var LayoutManager = Backbone.View.extend({
       actuallyRender(root, def);
     }
 
-    // Add the View to the deferred so that `view.render().view.el` is
-    // possible.
-    def.view = root;
+    // Put the deferred inside of the `__manager__` object, since we don't want
+    // end users accessing this directly anymore in favor of the `afterRender`
+    // event.  So instead of doing `render().then(...` do
+    // `render().once("afterRender", ...`.
+    root.__manager__.renderDeferred = def;
 
-    // This is the promise that determines if the `render` function has
-    // completed or not.
-    return def;
+    // Return the actual View for chainability purposes.
+    return root;
   },
 
   // Ensure the cleanup function is called whenever remove is called.
@@ -402,23 +502,10 @@ var LayoutManager = Backbone.View.extend({
   _cache: {},
 
   // Creates a deferred and returns a function to call when finished.
-  _makeAsync: function(options, done) {
-    var handler = options.deferred();
-
-    // Used to handle asynchronous renders.
-    handler.async = function() {
-      handler._isAsync = true;
-
-      return done;
-    };
-
-    return handler;
-  },
-
   // This gets passed to all _render methods.  The `root` value here is passed
   // from the `manage(this).render()` line in the `_render` function
   _viewRender: function(root, options) {
-    var url, contents, fetchAsync, renderedEl;
+    var url, contents, def, renderedEl;
     var manager = root.__manager__;
 
     // This function is responsible for pairing the rendered template into
@@ -450,7 +537,7 @@ var LayoutManager = Backbone.View.extend({
       }
 
       // Resolve only after fetch and render have succeeded.
-      fetchAsync.resolveWith(root, [root]);
+      def.resolveWith(root, [root]);
     }
 
     // Once the template is successfully fetched, use its contents to proceed.
@@ -459,21 +546,26 @@ var LayoutManager = Backbone.View.extend({
     function done(context, contents) {
       // Store the rendered template someplace so it can be re-assignable.
       var rendered;
-      // This allows the `render` method to be asynchronous as well as `fetch`.
-      var renderAsync = LayoutManager._makeAsync(options, function(rendered) {
+
+      // Trigger this once the render method has completed.
+      manager.callback = function(rendered) {
+        // Clean up asynchronous manager properties.
+        delete manager.isAsync;
+        delete manager.callback;
+
         applyTemplate(rendered);
-      });
+      };
 
       // Ensure the cache is up-to-date.
       LayoutManager.cache(url, contents);
 
       // Render the View into the el property.
       if (contents) {
-        rendered = options.render.call(renderAsync, contents, context);
+        rendered = options.renderTemplate.call(root, contents, context);
       }
 
       // If the function was synchronous, continue execution.
-      if (!renderAsync._isAsync) {
+      if (!manager.isAsync) {
         applyTemplate(rendered);
       }
     }
@@ -486,15 +578,23 @@ var LayoutManager = Backbone.View.extend({
         var context = root.serialize || options.serialize;
         var template = root.template || options.template;
 
+        // Create a deferred specifically for fetching.
+        def = options.deferred();
+
         // If data is a function, immediately call it.
         if (_.isFunction(context)) {
           context = context.call(root);
         }
 
-        // This allows for `var done = this.async()` and then `done(contents)`.
-        fetchAsync = LayoutManager._makeAsync(options, function(contents) {
+        // Set the internal callback to trigger once the asynchronous or
+        // synchronous behavior has completed.
+        manager.callback = function(contents) {
+          // Clean up asynchronous manager properties.
+          delete manager.isAsync;
+          delete manager.callback;
+
           done(context, contents);
-        });
+        };
 
         // Set the url to the prefix + the view's template property.
         if (typeof template === "string") {
@@ -506,34 +606,33 @@ var LayoutManager = Backbone.View.extend({
         if (contents = LayoutManager.cache(url)) {
           done(context, contents, url);
 
-          return fetchAsync;
+          return def;
         }
 
         // Fetch layout and template contents.
         if (typeof template === "string") {
-          contents = options.fetch.call(fetchAsync, options.prefix + template);
+          contents = options.fetchTemplate.call(root, options.prefix +
+            template);
         // If the template is already a function, simply call it.
         } else if (typeof template === "function") {
           contents = template;
         // If its not a string and not undefined, pass the value to `fetch`.
         } else if (template != null) {
-          contents = options.fetch.call(fetchAsync, template);
+          contents = options.fetchTemplate.call(root, template);
         }
 
         // If the function was synchronous, continue execution.
-        if (!fetchAsync._isAsync) {
+        if (!manager.isAsync) {
           done(context, contents);
         }
 
-        return fetchAsync;
+        return def;
       }
     };
   },
 
   // Remove all nested Views.
   _removeViews: function(root, force) {
-    var views;
-
     // Shift arguments around.
     if (typeof root === "boolean") {
       force = root;
@@ -546,7 +645,7 @@ var LayoutManager = Backbone.View.extend({
     // Iterate over all of the nested View's and remove.
     root.getViews().each(function(view) {
       // Force doesn't care about if a View has rendered or not.
-      if (view.__manager__.hasRendered || force) {
+      if (view.hasRendered || force) {
         LayoutManager._removeView(view, force);
       }
     });
@@ -555,14 +654,15 @@ var LayoutManager = Backbone.View.extend({
   // Remove a single nested View.
   _removeView: function(view, force) {
     var parentViews;
-    // Shorthand the manager for easier access.
+    // Shorthand the managers for easier access.
     var manager = view.__manager__;
+    var rentManager = manager.parent && manager.parent.__manager__;
     // Test for keep.
     var keep = typeof view.keep === "boolean" ? view.keep : view.options.keep;
 
-    // Only remove views that do not have `keep` attribute set, unless the
-    // View is in `insert` mode and the force flag is set.
-    if ((!keep && manager.insert === true) || force) {
+    // In insert mode, remove views that do not have `keep` attribute set,
+    // unless the force flag is set.
+    if ((!keep && rentManager && rentManager.insert === true) || force) {
       // Clean out the events.
       LayoutManager.cleanViews(view);
 
@@ -678,6 +778,9 @@ var LayoutManager = Backbone.View.extend({
         // Ensure a view always has a views object.
         views: {},
 
+        // Ensure a view always has a sections object.
+        sections: {},
+
         // Internal state object used to store whether or not a View has been
         // taken over by layout manager and if it has been rendered into the
         // DOM.
@@ -697,19 +800,12 @@ var LayoutManager = Backbone.View.extend({
         proto.options);
 
       // Ensure view events are properly copied over.
-      viewOptions = _.pick(options, aConcat.call(["events"],
+      viewOptions = _.pick(options, aConcat.call(["events", "sections"],
         _.values(options.events)));
 
       // Merge the View options into the View.
       _.extend(view, viewOptions);
 
-      // If the View still has the Backbone.View#render method, remove it.
-      // Don't want it accidentally overriding the LM render.
-      if (viewOverrides.render === LayoutManager.prototype.render ||
-        viewOverrides.render === Backbone.View.prototype.render) {
-        delete viewOverrides.render;
-      }
-
       // Pick out the specific properties that can be dynamically added at
       // runtime and ensure they are available on the view object.
       _.extend(options, viewOverrides);
@@ -717,32 +813,6 @@ var LayoutManager = Backbone.View.extend({
       // By default the original Remove function is the Backbone.View one.
       view._remove = Backbone.View.prototype.remove;
 
-      // Always use this render function when using LayoutManager.
-      view._render = function(manage, options) {
-        // Keep the view consistent between callbacks and deferreds.
-        var view = this;
-        // Shorthand the manager.
-        var manager = view.__manager__;
-        // Cache these properties.
-        var beforeRender = options.beforeRender;
-
-        // Ensure all nested Views are properly scrubbed if re-rendering.
-        if (manager.hasRendered) {
-          this._removeViews();
-        }
-
-        // If a beforeRender function is defined, call it.
-        if (beforeRender) {
-          beforeRender.call(this, this);
-        }
-
-        // Always emit a beforeRender event.
-        this.trigger("beforeRender", this);
-
-        // Render!
-        return manage(this, options).render();
-      };
-
       // Ensure the render is always set correctly.
       view.render = LayoutManager.prototype.render;
 
@@ -780,10 +850,10 @@ var LayoutManager = Backbone.View.extend({
   }
 });
 
-// Convenience assignment to make creating Layout's slightly shorter.
-Backbone.Layout = LayoutManager;
 // Tack on the version.
-LayoutManager.VERSION = "0.8.8";
+LayoutManager.VERSION = "0.9.1";
+
+Backbone.Layout = LayoutManager;
 
 // Override _configure to provide extra functionality that is necessary in
 // order for the render function reference to be bound during initialize.
@@ -827,25 +897,32 @@ LayoutManager.prototype.options = {
 
   // Fetch is passed a path and is expected to return template contents as a
   // function or string.
-  fetch: function(path) {
+  fetchTemplate: function(path) {
     return _.template($(path).html());
   },
 
+  // By default, render using underscore's templating.
+  renderTemplate: function(template, context) {
+    return template(context);
+  },
+
   // This is the most common way you will want to partially apply a view into
   // a layout.
   partial: function($root, $el, rentManager, manager) {
+    var $filtered;
+
     // If selector is specified, attempt to find it.
     if (manager.selector) {
       if (rentManager.noel) {
-        var $filtered = $root.filter(manager.selector);
+        $filtered = $root.filter(manager.selector);
         $root = $filtered.length ? $filtered : $root.find(manager.selector);
       } else {
         $root = $root.find(manager.selector);
       }
     }
 
-    // Use the insert method if insert argument is true.
-    if (manager.insert) {
+    // Use the insert method if the parent's `insert` argument is true.
+    if (rentManager.insert) {
       this.insert($root, $el);
     } else {
       this.html($root, $el);
@@ -858,6 +935,42 @@ LayoutManager.prototype.options = {
     $root.html(content);
   },
 
+  // Used for inserting subViews in a single batch.  This gives a small
+  // performance boost as we write to a disconnected fragment instead of to the
+  // DOM directly. Smarter browsers like Chrome will batch writes internally
+  // and layout as seldom as possible, but even in that case this provides a
+  // decent boost.  jQuery will use a DocumentFragment for the batch update,
+  // but Cheerio in Node will not.
+  htmlBatch: function(rootView, subViews, selector) {
+    // Shorthand the parent manager object.
+    var rentManager = rootView.__manager__;
+    // Create a simplified manager object that tells partial() where
+    // place the elements.
+    var manager = { selector: selector };
+
+    // Get the elements to be inserted into the root view.
+    var els = _.reduce(subViews, function(memo, sub) {
+      // Check if keep is present - do boolean check in case the user
+      // has created a `keep` function.
+      var keep = typeof sub.keep === "boolean" ? sub.keep : sub.options.keep;
+      // If a subView is present, don't push it.  This can only happen if
+      // `keep: true`.  We do the keep check for speed as $.contains is not
+      // cheap.
+      var exists = keep && $.contains(rootView.el, sub.el);
+
+      // If there is an element and it doesn't already exist in our structure
+      // attach it.
+      if (sub.el && !exists) {
+        memo.push(sub.el);
+      }
+
+      return memo;
+    }, []);
+
+    // Use partial to apply the elements. Wrap els in jQ obj for cheerio.
+    return this.partial(rootView.$el, $(els), rentManager, manager);
+  },
+
   // Very similar to HTML except this one will appendChild by default.
   insert: function($root, $el) {
     $root.append($el);
@@ -868,11 +981,6 @@ LayoutManager.prototype.options = {
     return $.when.apply(null, promises);
   },
 
-  // By default, render using underscore's templating.
-  render: function(template, context) {
-    return template(context);
-  },
-
   // A method to determine if a View contains another.
   contains: function(parent, child) {
     return $.contains(parent, child);
@@ -882,4 +990,7 @@ LayoutManager.prototype.options = {
 // Maintain a list of the keys at define time.
 keys = _.keys(LayoutManager.prototype.options);
 
-})(typeof global === "object" ? global : this);
+// Assign `LayoutManager` object for AMD loaders.
+return LayoutManager;
+
+}));


Mime
View raw message