-
Notifications
You must be signed in to change notification settings - Fork 82
/
backbone.fetch-cache.js
140 lines (115 loc) · 4.67 KB
/
backbone.fetch-cache.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*!
backbone.fetch-cache v0.1.1
by Andy Appleton - https://github.com/mrappleton/backbone-fetch-cache.git
*/
(function() {
// Setup
var modelFetch = Backbone.Model.prototype.fetch,
collectionFetch = Backbone.Collection.prototype.fetch,
supportLocalStorage = typeof window.localStorage !== 'undefined';
Backbone.fetchCache = (Backbone.fetchCache || {});
Backbone.fetchCache._cache = (Backbone.fetchCache._cache || {});
if (typeof Backbone.fetchCache.localStorage === 'undefined') {
Backbone.fetchCache.localStorage = true;
}
// Shared methods
function setCache(instance, opts, attrs) {
opts = (opts || {});
var url = _.isFunction(instance.url) ? instance.url() : instance.url,
expires = false;
// need url to use as cache key so return if we can't get it
if (!url) { return; }
if (opts.expires !== false) {
expires = (new Date()).getTime() + ((opts.expires || 5 * 60) * 1000);
}
Backbone.fetchCache._cache[url] = {
expires: expires,
value: attrs
};
Backbone.fetchCache.setLocalStorage();
}
function setLocalStorage() {
if (!supportLocalStorage || !Backbone.fetchCache.localStorage) { return; }
localStorage.setItem('backboneCache', JSON.stringify(Backbone.fetchCache._cache));
}
function getLocalStorage() {
if (!supportLocalStorage || !Backbone.fetchCache.localStorage) { return; }
Backbone.fetchCache._cache = JSON.parse(localStorage.getItem('backboneCache')) || {};
}
// Instance methods
Backbone.Model.prototype.fetch = function(opts) {
opts = (opts || {});
var url = _.isFunction(this.url) ? this.url() : this.url,
data = Backbone.fetchCache._cache[url],
expired = false,
attributes = false,
promise = new $.Deferred();
if (data) {
expired = data.expires;
expired = expired && data.expires < (new Date()).getTime();
attributes = data.value;
}
if (!expired && (opts.cache || opts.prefill) && attributes) {
this.set(attributes, opts);
if (_.isFunction(opts.prefillSuccess)) { opts.prefillSuccess(this); }
// Notify progress if we're still waiting for an AJAX call to happen...
if (opts.prefill) { promise.notify(this); }
// ...finish and return if we're not
else {
if (_.isFunction(opts.success)) { opts.success(this); }
// Mimic actual fetch behaviour buy returning a fulfilled promise
return promise.resolve(this);
}
}
// Delegate to the actual fetch method and store the attributes in the cache
modelFetch.apply(this, arguments)
// resolve the returned promise when the AJAX call completes
.done( _.bind(promise.resolve, this, this) )
// Set the new data in the cache
.done( _.bind(Backbone.fetchCache.setCache, null, this, opts) );
// return a promise which provides the same methods as a jqXHR object
return promise;
};
Backbone.Collection.prototype.fetch = function(opts) {
opts = (opts || {});
var url = _.isFunction(this.url) ? this.url() : this.url,
data = Backbone.fetchCache._cache[url],
expired = false,
attributes = false,
promise = new $.Deferred();
if (data) {
expired = data.expires;
expired = expired && data.expires < (new Date()).getTime();
attributes = data.value;
}
if (!expired && (opts.cache || opts.prefill) && attributes) {
this[opts.add ? 'add' : 'reset'](this.parse(attributes), opts);
if (_.isFunction(opts.prefillSuccess)) { opts.prefillSuccess(this); }
// Notify progress if we're still waiting for an AJAX call to happen...
if (opts.prefill) { promise.notify(this); }
// ...finish and return if we're not
else {
if (_.isFunction(opts.success)) { opts.success(this); }
// Mimic actual fetch behaviour buy returning a fulfilled promise
return promise.resolve(this);
}
}
// Delegate to the actual fetch method and store the attributes in the cache
collectionFetch.apply(this, arguments)
// resolve the returned promise when the AJAX call completes
.done( _.bind(promise.resolve, this, this) )
// Set the new data in the cache
.done( _.bind(Backbone.fetchCache.setCache, null, this, opts) );
// return a promise which provides the same methods as a jqXHR object
return promise;
};
// Prime the cache from localStorage on initialization
getLocalStorage();
// Exports
Backbone.fetchCache.setCache = setCache;
Backbone.fetchCache.setLocalStorage = setLocalStorage;
Backbone.fetchCache.getLocalStorage = getLocalStorage;
if (typeof define === 'function' && define.amd) {
define(function(){ return Backbone; });
}
})();