-
Notifications
You must be signed in to change notification settings - Fork 0
/
jquery.offline.js
217 lines (194 loc) · 7.06 KB
/
jquery.offline.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*!
* jQuery Offline
* Version 1.0.0
*
* http://github.com/wycats/jquery-offline
*
* Copyright 2010, Yehuda Katz
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Date: Fri Jul 9 10:20:00 2010 -0800
*/
(function($) {
var prefix = "offline.jquery:",
mostRecent = null,
requesting = {};
// Allow the user to explicitly turn off localStorage
// before loading this plugin
if (typeof $.support.localStorage === "undefined") {
$.support.localStorage = !!window.localStorage;
}
// modified getJSON which uses ifModified: true
function getJSON(url, data, fn) {
if ($.isFunction(data)) {
fn = data;
data = null;
}
var requestingKey = url + "?" + $.param(data || {});
if (requesting[requestingKey]) {
return false;
}
requesting[requestingKey] = true;
return $.ajax({
type: "GET",
url: url,
data: data,
success: function(responseData, text) {
delete requesting[requestingKey];
// handle lack of response (error callback isn't called in this case)
if (undefined === responseData) {
if (!window.navigator.onLine) {
// requeue the request for the next time we come online
mostRecent = function() {
getJSON(url, data, fn);
};
}
return;
}
fn(responseData, text);
},
error: function() {
delete requesting[requestingKey];
},
dataType: "json",
ifModified: true
});
}
if ($.support.localStorage) {
// If localStorage is available, define jQuery.retrieveJSON
// and jQuery.clearJSON to operate in terms of the offline
// cache
// If the user comes online, run the most recent request
// that was queued due to the user being offline
$(window).bind("online", function() {
if (mostRecent) {
mostRecent();
}
});
// If the user goes offline, hide any loading bar
// the user may have created
$(window).bind("offline", function() {
$.event.trigger("ajaxStop");
});
$.retrieveJSON = function(url, data, fn) {
// allow jQuery.retrieveJSON(url, fn)
if ($.isFunction(data)) {
fn = data;
data = {};
}
// remember when this request started so we can report
// the time when a follow-up Ajax request completes.
// this is especially important when the user comes
// back online, since retrieveDate may be minutes,
// hours or even days before the Ajax request finally
// completes
var retrieveDate = new Date;
// get a String value for the data passed in, and then
// use it to calculate a cache key
var param = $.param(data),
key = prefix + url + ":" + param,
text = localStorage[key],
dateString = localStorage[key + ":date"],
date = new Date(Date.parse(dateString));
function cleanupLocalStorage() {
// take all date keys and remove the oldest half
var dateKeys = [];
for (var i = 0; i < localStorage.length; ++i) {
var key = localStorage.key(i);
if (/:date$/.test(key)) {
dateKeys.push(key);
}
}
dateKeys.sort(function(a, b) {
var date_a = localStorage[a], date_b = localStorage[b];
return date_a < date_b ? -1 : (date_a > date_b ? +1 : 0);
});
for (var i = 0; i < dateKeys.length / 2; ++i) {
var key = dateKeys[i];
delete localStorage[key];
delete localStorage[key.substr(0, key.length - 5)]; // :date
}
}
// create a function that will make an Ajax request and
// store the result in the cache. This function will be
// deferred until later if the user is offline
function getData() {
return getJSON(url, data, function(json, status) {
if ( status == 'notmodified' ) {
// Just return if the response has a 304 status code
return false;
}
while (true) {
try {
localStorage[key] = JSON.stringify(json);
localStorage[key + ":date"] = new Date;
break;
} catch (e) {
if (e.name == "QUOTA_EXCEEDED_ERR" || e.name ==
"NS_ERROR_DOM_QUOTA_REACHED") {
cleanupLocalStorage();
}
}
}
// If this is a follow-up request, create an object
// containing both the original time of the cached
// data and the time that the data was originally
// retrieved from the cache. With this information,
// users of jQuery Offline can provide the user
// with improved feedback if the lag is large
var data = text && { cachedAt: date, retrievedAt: retrieveDate };
fn(json, status, data);
});
}
// If there is anything in the cache, call the callback
// right away, with the "cached" status string
if( text ) {
var obj = $.parseJSON(text);
var response = fn( obj, "cached", { cachedAt: date } );
if( response === false ) {
var dfd = $.Deferred().promise();
dfd.done = function(callback) { callback(obj) };
return dfd;
}
}
// If the user is online, make the Ajax request right away;
// otherwise, make it the most recent callback so it will
// get triggered when the user comes online
if (window.navigator.onLine) {
return getData();
} else {
mostRecent = getData;
}
return true;
};
// jQuery.clearJSON is simply a wrapper around deleting the
// localStorage for a URL/data pair
$.clearJSON = function(url, data) {
var param = $.param(data || {});
delete localStorage[prefix + url + ":" + param];
delete localStorage[prefix + url + ":" + param + ":date"];
};
} else {
// If localStorage is unavailable, just make all requests
// regular Ajax requests.
$.retrieveJSON = getJSON;
$.clearJSON = $.noop;
}
})(jQuery);