define(['underscore', 'backbone', 'jquery'], function (_, Backbone, $) {
return (root.Backbone = factory(_, Backbone, $));
});
- } else if (typeof exports !== 'undefined') {
+ } else if (typeof exports !== 'undefined' && typeof require !== 'undefined') {
module.exports = factory(require('underscore'), require('backbone'), require('jquery'));
} else {
// Browser globals
}
// Shared methods
- function getCacheKey(instance, opts) {
- var url;
-
- if(opts && opts.url) {
- url = opts.url;
- } else {
- url = _.isFunction(instance.url) ? instance.url() : instance.url;
+ function getCacheKey(key, opts) {
+ if (key && _.isObject(key)) {
+ // If the model has its own, custom, cache key function, use it.
+ if (_.isFunction(key.getCacheKey)) {
+ return key.getCacheKey(opts);
+ }
+ // else, use the URL
+ if (opts && opts.url) {
+ key = opts.url;
+ } else {
+ key = _.isFunction(key.url) ? key.url() : key.url;
+ }
+ } else if (_.isFunction(key)) {
+ return key(opts);
}
-
- // Need url to use as cache key so return if we can't get it
- if(!url) { return; }
-
- if(opts && opts.data) {
+ if (opts && opts.data) {
if(typeof opts.data === 'string') {
- return url + '?' + opts.data;
+ return key + '?' + opts.data;
} else {
- return url + '?' + $.param(opts.data);
+ return key + '?' + $.param(opts.data);
}
}
- return url;
+ return key;
}
function setCache(instance, opts, attrs) {
opts = (opts || {});
var key = Backbone.fetchCache.getCacheKey(instance, opts),
- expires = false;
+ expires = false,
+ lastSync = (opts.lastSync || (new Date()).getTime()),
+ prefillExpires = false;
// Need url to use as cache key so return if we can't get it
if (!key) { return; }
expires = (new Date()).getTime() + ((opts.expires || 5 * 60) * 1000);
}
+ if (opts.prefillExpires !== false) {
+ prefillExpires = (new Date()).getTime() + ((opts.prefillExpires || 5 * 60) * 1000);
+ }
+
Backbone.fetchCache._cache[key] = {
expires: expires,
+ lastSync : lastSync,
+ prefillExpires: prefillExpires,
value: attrs
};
Backbone.fetchCache.setLocalStorage();
}
- function clearItem(key) {
- if (_.isFunction(key)) { key = key(); }
+ function getCache(key, opts) {
+ if (_.isFunction(key)) {
+ key = key();
+ } else if (key && _.isObject(key)) {
+ key = getCacheKey(key, opts);
+ }
+
+ return Backbone.fetchCache._cache[key];
+ }
+
+ function getLastSync(key, opts) {
+ return getCache(key).lastSync;
+ }
+
+ function clearItem(key, opts) {
+ if (_.isFunction(key)) {
+ key = key();
+ } else if (key && _.isObject(key)) {
+ key = getCacheKey(key, opts);
+ }
delete Backbone.fetchCache._cache[key];
Backbone.fetchCache.setLocalStorage();
}
+
+ function reset() {
+ // Clearing all cache items
+ Backbone.fetchCache._cache = {};
+ }
function setLocalStorage() {
if (!supportLocalStorage || !Backbone.fetchCache.localStorage) { return; }
localStorage.setItem(Backbone.fetchCache.getLocalStorageKey(), JSON.stringify(Backbone.fetchCache._cache));
} catch (err) {
var code = err.code || err.number || err.message;
- if (code === 22) {
+ if (code === 22 || code === 1014) {
this._deleteCacheWithPriority();
} else {
throw(err);
}
opts = _.defaults(opts || {}, { parse: true });
var key = Backbone.fetchCache.getCacheKey(this, opts),
- data = Backbone.fetchCache._cache[key],
+ data = getCache(key),
expired = false,
+ prefillExpired = false,
attributes = false,
deferred = new $.Deferred(),
self = this;
+ function isPrefilling() {
+ return opts.prefill && (!opts.prefillExpires || prefillExpired);
+ }
+
function setData() {
if (opts.parse) {
attributes = self.parse(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); }
+ if (isPrefilling()) { deferred.notify(self); }
// ...finish and return if we're not
else {
if (_.isFunction(opts.success)) { opts.success(self, attributes, opts); }
if (data) {
expired = data.expires;
expired = expired && data.expires < (new Date()).getTime();
+ prefillExpired = data.prefillExpires;
+ prefillExpired = prefillExpired && data.prefillExpires < (new Date()).getTime();
attributes = data.value;
}
setData();
}
- if (!opts.prefill) {
+ if (!isPrefilling()) {
return deferred;
}
}
opts = _.defaults(opts || {}, { parse: true });
var key = Backbone.fetchCache.getCacheKey(this, opts),
- data = Backbone.fetchCache._cache[key],
+ data = getCache(key),
expired = false,
+ prefillExpired = false,
attributes = false,
deferred = new $.Deferred(),
self = this;
+ function isPrefilling() {
+ return opts.prefill && (!opts.prefillExpires || prefillExpired);
+ }
+
function setData() {
self[opts.reset ? 'reset' : 'set'](attributes, opts);
if (_.isFunction(opts.prefillSuccess)) { opts.prefillSuccess(self); }
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); }
+ if (isPrefilling()) { deferred.notify(self); }
// ...finish and return if we're not
else {
if (_.isFunction(opts.success)) { opts.success(self, attributes, opts); }
if (data) {
expired = data.expires;
expired = expired && data.expires < (new Date()).getTime();
+ prefillExpired = data.prefillExpires;
+ prefillExpired = prefillExpired && data.prefillExpires < (new Date()).getTime();
attributes = data.value;
}
setData();
}
- if (!opts.prefill) {
+ if (!isPrefilling()) {
return deferred;
}
}
Backbone.fetchCache._superMethods = superMethods;
Backbone.fetchCache.setCache = setCache;
+ Backbone.fetchCache.getCache = getCache;
Backbone.fetchCache.getCacheKey = getCacheKey;
+ Backbone.fetchCache.getLastSync = getLastSync;
Backbone.fetchCache.clearItem = clearItem;
+ Backbone.fetchCache.reset = reset;
Backbone.fetchCache.setLocalStorage = setLocalStorage;
Backbone.fetchCache.getLocalStorage = getLocalStorage;