-
Notifications
You must be signed in to change notification settings - Fork 0
/
vape.js
326 lines (232 loc) · 16.4 KB
/
vape.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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
* Vape is a lightweight plugin that automatically saves form data and restores it after browser
* crashes or users closing tabs by accident. The magic is done using HTML5 local storage and it
* fallbacks to cookies if local storage is not supported. Once the user submits the form all data
* is cleared and the process starts again. It's built to be non-intrusive with your code, just
* pass in the forms to protect and done!
*
* Vape requires jQuery to work and it also assumes each form has the html id attribute set.
*
*
* by Enrique Gonzalez (Enriikke)
* helloimenrique.com
*
* enjoy!
*
*/
(function($) {
$.fn.vape = function(options) {
// Constants to check for the storage method being used.
var STORAGE_METHOD_LOCAL = 'LOCAL_STORAGE';
var STORAGE_METHOD_COOKIES = 'COOKIE_STORAGE';
// Vape settings that can be customized.
var settings = $.extend({
ignore_fields: [':submit', ':reset', ':button', ':file', ':password'],
fallback_to_cookies: true,
cookie_expires: 7
}, options);
/****************************************************************************************************
READ AND WRITE FUNCTIONS FOR LOCAL STORAGE AND COOKIES
*****************************************************************************************************/
/*
* Creates a new entry in local storage if available. It also checks if we have reached
* the maximum data capacity allowed by HTML5 local storage. If the value is ommited
* then the function will delete the storage entry instead.
*
* name: refers to the unique identifier of the element we are trying to create.
* value: the value of the element to be created.
*
*/
var writeToLocalStorage = function(name, value) {
// Try to write to local storage and catch the quota exceeded error when it happens.
try {
if(value) localStorage.setItem(name, value);
else localStorage.removeItem(name);
}
catch(e) { console.log('VAPE ERROR: exceeded data quota'); }
};
/*
* Added a wrapper to the local storage built-in getItem function to maintain consistency.
* Allows vape to read from local storage.
*
* name: refers to the unique identifier of the element we are trying to read.
*
*/
var readFromLocalStorage = function(name) {
// Simple call to get the value of the given name (key).
return localStorage.getItem(name);
};
/*
* Creates a cookie on the current domain. It also allows to set some optional parameters.
* If the value is ommited then the function will delete the cookie instead.
*
* name: refers to the unique idenfifier of the cookie we are trying to write.
* value: the value of the cookie to be created.
* expires: [optional] sets an expiration date for the cookie in days.
* path: [optional] specifies the path of the cookie.
* domain: [optional] sets a domain for the cookie.
* secure: [optional] if true then the cookie will require a secure connection (https).
*
*/
var writeCookie = function(name, value, options) {
// Checks if the options dictionary was given, otherwise sets it to an empty dictionary.
options = options? options : {};
// Sets the expires parameter to a negative number if the user does not provide a value
// for the cookie so that it gets deleted instead.
var expires = value? options.expire : -1;
// Convert the expires parameter to an actual date to include in the cookie declaration.
if(typeof(expires) == 'number') {
var date = new Date();
date.setTime(date.getTime() + (expires * 8640000));
expires = '; expires=' + date.toUTCString();
} else expires = '';
// Checks if any of the optional parameters was given, otherwisw sets it to the default value.
var path = options.path? '; path=' + options.path : '';
var domain = options.domain? '; domain=' + options.domain : '';
var secure = options.secure? '; secure' : '';
// Finally create the cookie!!
document.cookie = [name + '=', encodeURIComponent(value), expires, path, domain, secure].join('');
};
/*
* Reads a cookie by iterating through all cookies for the current domain.
*
* name: refers to the unique identifier of the cookie we are trying to read.
*/
var readCookie = function(name) {
// Get all the stored cookies for the current domain.
var cookies = document.cookie.split(';');
// Iterate through every cookie until we find the one we are looking for (name).
for(var i = 0; i < cookies.length; i++) {
// Get the cookie name and value by parsing a standard cookie declaration.
var cookie_name = cookies[i].substr(0, cookies[i].indexOf('=')).replace(/^\s+|\s+$/g, '');
var cookie_value = cookies[i].substr(cookies[i].indexOf('=') + 1);
// If we find the cookie we are looking for then return its value.
if(cookie_name == name) return unescape(cookie_value);
}
// Return undefined if we couldn't find the cookie or if they are disabled.
return undefined;
};
/****************************************************************************************************
FUNCTIONS TO CHECK WHICH STORAGE METHOD CAN BE USED
*****************************************************************************************************/
/*
* Checks if the browser supports HTML5 local storage or not.
*
*/
var isLocalStorageSupported = function() {
if(typeof(Storage) !== 'undefined') return true;
else return false;
};
/*
* Checks if the browser has cookies enabled.
*
*/
var areCookiesEnabled = function() {
// Best way to know if cookies are enabled is to actually create a cookie.
writeCookie('vape_cookie_test', 'vape');
var vape_cookie_test = readCookie('vape_cookie_test');
if(vape_cookie_test) return true;
else return false;
};
/****************************************************************************************************
NICE UTIL FUNCTIONS FOR VAPE TO WORK
*****************************************************************************************************/
/*
* Generates a unique identifier for the given form. It requires the form element to have
* an html id attribute to ensure uniqness. It alse prefixes vape to avoid conflicts with
* other cookies or elements in local storage.
*
* form: the parent form of the field we are trying to generate a name for.
* field: the field that we are trying to generate a name for.
*
*/
var generateFiledName = function(form, field) {
return ['vape', form.attr('id'), field.attr('id'), field.attr('name')].join('~');
};
/*
* Gathers all the fields that need to be protected. It filters out all the elements that are part
* of the ignore_fields array defined by the user or using default settings.
*
* form: the form that we are trying to protect.
*/
var getFieldsToProtect = function(form) {
form_inputs = $.merge(form.find('input'), form.find('textarea'));
for(var i = 0; i < settings.ignore_fields.length; i++) form_inputs = form_inputs.not(settings.ignore_fields[i]);
return form_inputs;
};
/****************************************************************************************************
RESTORE, PROTECT, AND RELEASE FUNCTIONS
*****************************************************************************************************/
/*
* Restores the data if available when the page loads.
*
* form: the form that needs its data to be restored.
* fields: the fields that are part of the given form.
* method: the storage method that is being used.
*/
var restoreData = function(form, fields, method) {
fields.each(function() {
var field = $(this);
var restored_value = '';
var field_name = generateFiledName(form, field);
if(method == STORAGE_METHOD_LOCAL) restored_value = readFromLocalStorage(field_name) || field.val();
else restored_value = readCookie(field_name) || field.val();
field.val(restored_value);
});
};
/*
* Binds the data protection to each individual field keyup event. It will write to local storage
* or create cookies everytime the field changes.
*
* form: the form that needs its data to be protected.
* fields: the fields that are part of the given form.
* method: the storage method that is being used.
*/
var protectData = function(form, fields, method) {
fields.each(function() {
var field = $(this);
var field_name = generateFiledName(form, field);
if(method == STORAGE_METHOD_LOCAL) field.keyup(function() { writeToLocalStorage(field_name, field.val()); });
else field.keyup(function() { writeCookie(field_name, field.val(), {expires: settings.cookie_expires}); });
});
};
/*
* Binds the data release to form submit or form reset. It will clear out everything for the
* given form from local storage or cookies.
*
* form: the form that needs its data to be released.
* fields: the fields that are part of the given form.
* method: the storage method that is being used.
*/
var releaseData = function(form, fields, method) {
form.bind('submit reset', function() {
fields.each(function() {
if(method == STORAGE_METHOD_LOCAL) writeToLocalStorage(generateFiledName(form, $(this)));
else writeCookie(generateFiledName(form, $(this)));
});
});
};
/****************************************************************************************************
THE MAGIC HAPPENS HERE
*****************************************************************************************************/
return this.each(function() {
// Create an array with all the inputs of the current form.
var $this_form = $(this);
var protected_fields = getFieldsToProtect($this_form);
var storage_method = undefined;
// Figure out which storage method should be used. If none is available then vape can't be used.
if(isLocalStorageSupported()) storage_method = STORAGE_METHOD_LOCAL;
else if(settings.fallback_to_cookies && areCookiesEnabled()) storage_method = STORAGE_METHOD_COOKIES;
if(storage_method) {
// Restore data if available then bind data protection and data release.
restoreData($this_form, protected_fields, storage_method);
protectData($this_form, protected_fields, storage_method);
releaseData($this_form, protected_fields, storage_method);
} else {
// We can't use local storage or cookies :(
console.log('VAPE ERROR: we are sorry :( but neither HTML5 localStorage nor cookies can be used');
}
});
};
})(jQuery);