couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject [05/50] [abbrv] couchdb commit: updated refs/heads/2041-update-ibrowse to 948e7d9
Date Fri, 07 Mar 2014 00:17:48 GMT
Add backbone.fetch-cache


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

Branch: refs/heads/2041-update-ibrowse
Commit: ed89f34020a10259344ded418785a4492159c23f
Parents: 34aabbf
Author: Garren Smith <garren.smith@gmail.com>
Authored: Tue Feb 4 16:47:54 2014 +0200
Committer: Garren Smith <garren.smith@gmail.com>
Committed: Tue Feb 4 16:47:54 2014 +0200

----------------------------------------------------------------------
 src/fauxton/app/addons/databases/resources.js   |   8 +-
 src/fauxton/app/addons/documents/resources.js   |  14 +-
 src/fauxton/app/addons/documents/routes.js      |   2 +-
 src/fauxton/app/addons/documents/views.js       |  22 +-
 src/fauxton/app/config.js                       |   3 +-
 src/fauxton/app/core/base.js                    |  27 +-
 .../assets/js/plugins/backbone.fetch-cache.js   | 311 +++++++++++++++++++
 7 files changed, 365 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/app/addons/databases/resources.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/databases/resources.js b/src/fauxton/app/addons/databases/resources.js
index 1b55f88..5fa931b 100644
--- a/src/fauxton/app/addons/databases/resources.js
+++ b/src/fauxton/app/addons/databases/resources.js
@@ -24,7 +24,7 @@ function(app, FauxtonAPI, Documents) {
 
   Databases.DocLimit = 20;
 
-  Databases.Model = Backbone.Model.extend({
+  Databases.Model = FauxtonAPI.Model.extend({
     initialize: function(options) {
       this.status = new Databases.Status({
         database: this
@@ -82,7 +82,7 @@ function(app, FauxtonAPI, Documents) {
     }
   });
 
-  Databases.Changes = Backbone.Collection.extend({
+  Databases.Changes = FauxtonAPI.Collection.extend({
 
     initialize: function(options) {
       this.database = options.database;
@@ -110,7 +110,7 @@ function(app, FauxtonAPI, Documents) {
     }
   });
 
-  Databases.Status = Backbone.Model.extend({
+  Databases.Status = FauxtonAPI.Model.extend({
     url: function() {
       return app.host + "/" + this.database.safeID();
     },
@@ -166,7 +166,7 @@ function(app, FauxtonAPI, Documents) {
   });
 
   // TODO: shared databases - read from the user doc
-  Databases.List = Backbone.Collection.extend({
+  Databases.List = FauxtonAPI.Collection.extend({
     model: Databases.Model,
     documentation: function(){
       return "all_dbs";

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/app/addons/documents/resources.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/documents/resources.js b/src/fauxton/app/addons/documents/resources.js
index 831d5e3..adfee1f 100644
--- a/src/fauxton/app/addons/documents/resources.js
+++ b/src/fauxton/app/addons/documents/resources.js
@@ -18,7 +18,7 @@ define([
 function(app, FauxtonAPI) {
   var Documents = FauxtonAPI.addon();
 
-  Documents.Doc = Backbone.Model.extend({
+  Documents.Doc = FauxtonAPI.Model.extend({
     idAttribute: "_id",
     documentation: function(){
       return "docs";
@@ -194,7 +194,7 @@ function(app, FauxtonAPI) {
     }
   });
 
-  Documents.DdocInfo = Backbone.Model.extend({
+  Documents.DdocInfo = FauxtonAPI.Model.extend({
     idAttribute: "_id",
     documentation: function(){
       return "docs";
@@ -224,7 +224,7 @@ function(app, FauxtonAPI) {
 
   });
 
-  Documents.ViewRow = Backbone.Model.extend({
+  Documents.ViewRow = FauxtonAPI.Model.extend({
     // this is a hack so that backbone.collections doesn't group 
     // these by id and reduce the number of items returned.
     idAttribute: "_id",
@@ -272,7 +272,7 @@ function(app, FauxtonAPI) {
 
   });
 
-  Documents.AllDocs = Backbone.Collection.extend({
+  Documents.AllDocs = FauxtonAPI.Collection.extend({
     model: Documents.Doc,
     documentation: function(){
       return "docs";
@@ -397,7 +397,7 @@ function(app, FauxtonAPI) {
     }
   });
 
-  Documents.IndexCollection = Backbone.Collection.extend({
+  Documents.IndexCollection = FauxtonAPI.Collection.extend({
     model: Documents.ViewRow,
     documentation: function(){
       return "docs";
@@ -527,7 +527,7 @@ function(app, FauxtonAPI) {
     // we can get the request duration
     fetch: function () {
       this.startTime = new Date().getTime();
-      return Backbone.Collection.prototype.fetch.call(this);
+      return FauxtonAPI.Collection.prototype.fetch.call(this);
     },
 
     allDocs: function(){
@@ -568,7 +568,7 @@ function(app, FauxtonAPI) {
   });
 
   
-  Documents.PouchIndexCollection = Backbone.Collection.extend({
+  Documents.PouchIndexCollection = FauxtonAPI.Collection.extend({
     model: Documents.ViewRow,
     documentation: function(){
       return "docs";

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/app/addons/documents/routes.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/documents/routes.js b/src/fauxton/app/addons/documents/routes.js
index 1510485..be9ce2f 100644
--- a/src/fauxton/app/addons/documents/routes.js
+++ b/src/fauxton/app/addons/documents/routes.js
@@ -182,7 +182,7 @@ function(app, FauxtonAPI, Documents, Databases) {
     },
 
     establish: function () {
-      return this.data.designDocs.fetch();
+      return this.data.designDocs.fetchOnce();
     },
 
     allDocs: function(databaseName, options) {

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/app/addons/documents/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/documents/views.js b/src/fauxton/app/addons/documents/views.js
index 298cfb4..5476203 100644
--- a/src/fauxton/app/addons/documents/views.js
+++ b/src/fauxton/app/addons/documents/views.js
@@ -1803,11 +1803,31 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
resizeColum
   Views.Changes = FauxtonAPI.View.extend({
     template: "addons/documents/templates/changes",
 
+    initialize: function () {
+      var that = this;
+      this.listenTo( this.model.changes, 'change', function () {
+        console.log('render on change'); 
+        that.render();
+      });
+      this.listenTo( this.model.changes, 'cachesync', function () {
+        console.log('render on cachesync'); 
+        that.render();
+      });
+    },
+
     establish: function() {
-      return [ this.model.changes.fetch()];
+      return [ this.model.changes.fetchOnce({prefill: true,
+        success: function () {
+          console.log('hi ajax success');
+        },
+        prefillSuccess: function () {
+          console.log('hi prefill success');
+        }
+      })];
     },
 
     serialize: function () {
+      console.log('ss');
       return {
         changes: this.model.changes.toJSON(),
         database: this.model

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/app/config.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/config.js b/src/fauxton/app/config.js
index 98be9c6..a5d764f 100644
--- a/src/fauxton/app/config.js
+++ b/src/fauxton/app/config.js
@@ -30,7 +30,8 @@ require.config({
     spin: "../assets/js/libs/spin.min",
     d3: "../assets/js/libs/d3",
     "nv.d3": "../assets/js/libs/nv.d3",
-    "ace":"../assets/js/libs/ace"
+    "ace":"../assets/js/libs/ace",
+    "backbone.fetch-cache": "../assets/js/plugins/backbone.fetch-cache"
   },
 
   baseUrl: '/',

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/app/core/base.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/core/base.js b/src/fauxton/app/core/base.js
index 53316bc..6fe3261 100644
--- a/src/fauxton/app/core/base.js
+++ b/src/fauxton/app/core/base.js
@@ -12,10 +12,12 @@
 
 define([
   "backbone",
-  "plugins/backbone.layoutmanager"
+  "plugins/backbone.layoutmanager",
+  "backbone.fetch-cache"
 ],
 
-function(Backbone) {
+function(Backbone, LayoutManager, BackboneCache) {
+  console.log(BackboneCache);
   var FauxtonAPI = {
     //add default objects
     router: {
@@ -67,16 +69,25 @@ function(Backbone) {
     }
   });
 
+
   FauxtonAPI.Model = Backbone.Model.extend({
-    fetchOnce: function (opt) {
-      var options = _.extend({}, opt);
 
-      if (!this._deferred || this._deferred.state() === "rejected" || options.forceFetch
) {
-        this._deferred = this.fetch();
-      }
+  });
+
+  FauxtonAPI.Collection = Backbone.Collection.extend({
 
-      return this._deferred;
+  });
+
+  var caching = {
+    fetchOnce: function (opts) {
+      var options = _.defaults(opts || {}, this.cache, {cache: true});
+      console.log('opts', options);
+      return this.fetch(options);
     }
+  };
+
+  _.each([FauxtonAPI.Collection, FauxtonAPI.Model], function (ctor) {
+    _.extend(ctor.prototype, caching);
   });
 
   var extensions = _.extend({}, Backbone.Events);

http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed89f340/src/fauxton/assets/js/plugins/backbone.fetch-cache.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/plugins/backbone.fetch-cache.js b/src/fauxton/assets/js/plugins/backbone.fetch-cache.js
new file mode 100644
index 0000000..c86a8b9
--- /dev/null
+++ b/src/fauxton/assets/js/plugins/backbone.fetch-cache.js
@@ -0,0 +1,311 @@
+/*!
+  backbone.fetch-cache v1.3.0
+  by Andy Appleton - https://github.com/mrappleton/backbone-fetch-cache.git
+ */
+
+// AMD wrapper from https://github.com/umdjs/umd/blob/master/amdWebGlobal.js
+
+(function (root, factory) {
+  if (typeof define === 'function' && define.amd) {
+    // AMD. Register as an anonymous module and set browser global
+    define(['underscore', 'backbone', 'jquery'], function (_, Backbone, $) {
+      return (root.Backbone = factory(_, Backbone, $));
+    });
+  } else {
+    // Browser globals
+    root.Backbone = factory(root._, root.Backbone, root.jQuery);
+  }
+}(this, function (_, Backbone, $) {
+
+  // Setup
+  var superMethods = {
+    modelFetch: Backbone.Model.prototype.fetch,
+    modelSync: Backbone.Model.prototype.sync,
+    collectionFetch: Backbone.Collection.prototype.fetch
+  },
+  supportLocalStorage = (function() {
+    var supported = typeof window.localStorage !== 'undefined';
+    if (supported) {
+      try {
+        // impossible to write on some platforms when private browsing is on and
+        // throws an exception = local storage not supported.
+        localStorage.setItem("test_support", "test_support");
+        localStorage.removeItem("test_support");
+      } catch (e) {
+        supported = false;
+      }
+    }
+    return supported;
+  })();
+
+  Backbone.fetchCache = (Backbone.fetchCache || {});
+  Backbone.fetchCache._cache = (Backbone.fetchCache._cache || {});
+
+  Backbone.fetchCache.priorityFn = function(a, b) {
+    if (!a || !a.expires || !b || !b.expires) {
+      return a;
+    }
+
+    return a.expires - b.expires;
+  };
+
+  Backbone.fetchCache._prioritize = function() {
+    var sorted = _.values(this._cache).sort(this.priorityFn);
+    var index = _.indexOf(_.values(this._cache), sorted[0]);
+    return _.keys(this._cache)[index];
+  };
+
+  Backbone.fetchCache._deleteCacheWithPriority = function() {
+    Backbone.fetchCache._cache[this._prioritize()] = null;
+    delete Backbone.fetchCache._cache[this._prioritize()];
+    Backbone.fetchCache.setLocalStorage();
+  };
+
+  Backbone.fetchCache.getLocalStorageKey = function() {
+    return 'backboneCache';
+  };
+
+  if (typeof Backbone.fetchCache.localStorage === 'undefined') {
+    Backbone.fetchCache.localStorage = true;
+  }
+
+  // Shared methods
+  function getCacheKey(instance, opts) {
+    var url;
+
+    if(opts && opts.url) {
+      url = opts.url;
+    } else {
+      url = _.isFunction(instance.url) ? instance.url() : instance.url;
+    }
+
+    // Need url to use as cache key so return if we can't get it
+    if(!url) { return; }
+
+    if(opts && opts.data) {
+      return url + "?" + $.param(opts.data);
+    }
+    return url;
+  }
+
+  function setCache(instance, opts, attrs) {
+    opts = (opts || {});
+    var key = Backbone.fetchCache.getCacheKey(instance, opts),
+        expires = false;
+
+    // Need url to use as cache key so return if we can't get it
+    if (!key) { return; }
+
+    // Never set the cache if user has explicitly said not to
+    if (opts.cache === false) { return; }
+
+    // Don't set the cache unless cache: true or prefill: true option is passed
+    if (!(opts.cache || opts.prefill)) { return; }
+
+    if (opts.expires !== false) {
+      expires = (new Date()).getTime() + ((opts.expires || 5 * 60) * 1000);
+    }
+
+    Backbone.fetchCache._cache[key] = {
+      expires: expires,
+      value: attrs
+    };
+
+    Backbone.fetchCache.setLocalStorage();
+  }
+
+  function clearItem(key) {
+    if (_.isFunction(key)) { key = key(); }
+    delete Backbone.fetchCache._cache[key];
+    Backbone.fetchCache.setLocalStorage();
+  }
+
+  function setLocalStorage() {
+    if (!supportLocalStorage || !Backbone.fetchCache.localStorage) { return; }
+    try {
+      localStorage.setItem(Backbone.fetchCache.getLocalStorageKey(), JSON.stringify(Backbone.fetchCache._cache));
+    } catch (err) {
+      var code = err.code || err.number || err.message;
+      if (code === 22) {
+        this._deleteCacheWithPriority();
+      } else {
+        throw(err);
+      }
+    }
+  }
+
+  function getLocalStorage() {
+    if (!supportLocalStorage || !Backbone.fetchCache.localStorage) { return; }
+    var json = localStorage.getItem(Backbone.fetchCache.getLocalStorageKey()) || '{}';
+    Backbone.fetchCache._cache = JSON.parse(json);
+  }
+
+  function nextTick(fn) {
+    return window.setTimeout(fn, 0);
+  }
+
+  // Instance methods
+  Backbone.Model.prototype.fetch = function(opts) {
+    opts = _.defaults(opts || {}, { parse: true });
+    var key = Backbone.fetchCache.getCacheKey(this, opts),
+        data = Backbone.fetchCache._cache[key],
+        expired = false,
+        attributes = false,
+        deferred = new $.Deferred(),
+        self = this;
+
+    function setData() {
+      if (opts.parse) {
+        attributes = self.parse(attributes, opts);
+      }
+
+      self.set(attributes, opts);
+      if (_.isFunction(opts.prefillSuccess)) { opts.prefillSuccess(self, attributes, opts);
}
+
+      // Trigger sync events
+      self.trigger('cachesync', self, attributes, opts);
+      self.trigger('sync', self, attributes, opts);
+
+      // Notify progress if we're still waiting for an AJAX call to happen...
+      if (opts.prefill) { deferred.notify(self); }
+      // ...finish and return if we're not
+      else {
+        if (_.isFunction(opts.success)) { opts.success(self, attributes, opts); }
+        deferred.resolve(self);
+      }
+    }
+
+    if (data) {
+      expired = data.expires;
+      expired = expired && data.expires < (new Date()).getTime();
+      attributes = data.value;
+    }
+
+    if (!expired && (opts.cache || opts.prefill) && attributes) {
+      // Ensure that cache resolution adhers to async option, defaults to true.
+      if (opts.async == null) { opts.async = true; }
+
+      if (opts.async) {
+        nextTick(setData);
+      } else {
+        setData();
+      }
+
+      if (!opts.prefill) {
+        return deferred.promise();
+      }
+    }
+
+    // Delegate to the actual fetch method and store the attributes in the cache
+    superMethods.modelFetch.apply(this, arguments)
+      // resolve the returned promise when the AJAX call completes
+      .done( _.bind(deferred.resolve, this, this) )
+      // Set the new data in the cache
+      .done( _.bind(Backbone.fetchCache.setCache, null, this, opts) )
+      // Reject the promise on fail
+      .fail( _.bind(deferred.reject, this, this) );
+
+    // return a promise which provides the same methods as a jqXHR object
+    return deferred.promise();
+  };
+
+  // Override Model.prototype.sync and try to clear cache items if it looks
+  // like they are being updated.
+  Backbone.Model.prototype.sync = function(method, model, options) {
+    // Only empty the cache if we're doing a create, update, patch or delete.
+    if (method === 'read') {
+      return superMethods.modelSync.apply(this, arguments);
+    }
+
+    var collection = model.collection,
+        keys = [],
+        i, len;
+
+    // Build up a list of keys to delete from the cache, starting with this
+    keys.push(Backbone.fetchCache.getCacheKey(model, options));
+
+    // If this model has a collection, also try to delete the cache for that
+    if (!!collection) {
+      keys.push(Backbone.fetchCache.getCacheKey(collection));
+    }
+
+    // Empty cache for all found keys
+    for (i = 0, len = keys.length; i < len; i++) { clearItem(keys[i]); }
+
+    return superMethods.modelSync.apply(this, arguments);
+  };
+
+  Backbone.Collection.prototype.fetch = function(opts) {
+    opts = _.defaults(opts || {}, { parse: true });
+    var key = Backbone.fetchCache.getCacheKey(this, opts),
+        data = Backbone.fetchCache._cache[key],
+        expired = false,
+        attributes = false,
+        deferred = new $.Deferred(),
+        self = this;
+
+    function setData() {
+      self[opts.reset ? 'reset' : 'set'](attributes, opts);
+      if (_.isFunction(opts.prefillSuccess)) { opts.prefillSuccess(self); }
+
+      // Trigger sync events
+      self.trigger('cachesync', self, attributes, opts);
+      self.trigger('sync', self, attributes, opts);
+
+      // Notify progress if we're still waiting for an AJAX call to happen...
+      if (opts.prefill) { deferred.notify(self); }
+      // ...finish and return if we're not
+      else {
+        if (_.isFunction(opts.success)) { opts.success(self, attributes, opts); }
+        deferred.resolve(self);
+      }
+    }
+
+    if (data) {
+      expired = data.expires;
+      expired = expired && data.expires < (new Date()).getTime();
+      attributes = data.value;
+    }
+
+    if (!expired && (opts.cache || opts.prefill) && attributes) {
+      // Ensure that cache resolution adhers to async option, defaults to true.
+      if (opts.async == null) { opts.async = true; }
+
+      if (opts.async) {
+        nextTick(setData);
+      } else {
+        setData();
+      }
+
+      if (!opts.prefill) {
+        return deferred.promise();
+      }
+    }
+
+    // Delegate to the actual fetch method and store the attributes in the cache
+    superMethods.collectionFetch.apply(this, arguments)
+      // resolve the returned promise when the AJAX call completes
+      .done( _.bind(deferred.resolve, this, this) )
+      // Set the new data in the cache
+      .done( _.bind(Backbone.fetchCache.setCache, null, this, opts) )
+      // Reject the promise on fail
+      .fail( _.bind(deferred.reject, this, this) );
+
+    // return a promise which provides the same methods as a jqXHR object
+    return deferred.promise();
+  };
+
+  // Prime the cache from localStorage on initialization
+  getLocalStorage();
+
+  // Exports
+
+  Backbone.fetchCache._superMethods = superMethods;
+  Backbone.fetchCache.setCache = setCache;
+  Backbone.fetchCache.getCacheKey = getCacheKey;
+  Backbone.fetchCache.clearItem = clearItem;
+  Backbone.fetchCache.setLocalStorage = setLocalStorage;
+  Backbone.fetchCache.getLocalStorage = getLocalStorage;
+
+  return Backbone;
+}));


Mime
View raw message