Skip to content

Instantly share code, notes, and snippets.

@quinncomendant
Created September 3, 2019 07:55
Show Gist options
  • Save quinncomendant/19cd48840dee1ee5f2c5c3819ace4660 to your computer and use it in GitHub Desktop.
Save quinncomendant/19cd48840dee1ee5f2c5c3819ace4660 to your computer and use it in GitHub Desktop.
Autosave module makes it easy to save and load form values in localStorage.
//
// Maintain state of form values across page loads with localStorage.
//
// eslint-disable-next-line no-unused-vars
var Autosave = (function ($) {
'use strict';
//
// Options
//
var options = {
prefix: null, // Prefix of localStorage key names, e.g., 'myapp-', or use NULL to use default 'autosave-'.
context: '', // Selector of a parent container, e.g., '#form1'.
interval: 3e3, // Frequency of autosaves.
timeout: 86400e3, // 24 hours - time after which the user will be prompted before restoring saved data.
expiration: 2678400e3, // 31 days - time after which saved data will be deleted without prompt.
fields: null, // Array of form input names to save.
loaded: function () {} // Callback to run after form data has been loaded (restored from localStorage).
};
// Object for dynamic messaging.
var sc_msg = new Strangecode.Msg();
//
// Set up objects and event listeners.
// Run this after document.ready, and before running any other methods here.
//
var init = function (new_options) {
options = $.extend(options, new_options || {});
// Only execute on pages which contain the DOM elements specified in context.
if (options['context'] && !$(options['context']).length) {
return;
}
// iOS Safari in Private Browsing mode is unable to use localStorage. Tell the user they must use a normal browsing window.
try {
localStorage.setItem('localStorage-avaliable-test', null);
} catch (e) {
sc_msg.raise(_("It appears are in Private Browsing mode. You will need to <a href=\"https://support.apple.com/en-us/HT203036\">disable Private Browsing mode</a> before using this website."), 'alert');
Log.err('Client appears to be in Private Browsing mode', Log.ln());
}
if (typeof(Storage) === 'undefined') {
sc_msg.raise(_("Your browser does not appear to support localStorage, probably because it’s outdated. You will need to <a href=\"http://browsehappy.com/\">upgrade your browser</a> before using this website."), 'alert');
Log.err('Client does not support localStorage', Log.ln());
}
if (null === options['prefix']) {
options['prefix'] = 'autosave-';
}
};
//
// Begin autosaving.
//
var run = function () {
// Only execute on pages which contain the DOM elements specified in context.
if (options['context'] && !$(options['context']).length) {
return;
}
var now = Date.now();
if (_get('last-saved') && _get('last-saved') < now - options['expiration']) {
// Reset the form if the last saved timestamp exists and the timestamp is older than the expiration threshold.
reset();
} else if (_get('last-saved') && _get('last-saved') < now - options['timeout']) {
// Prompt to load the form if the last saved timestamp exists and the timestamp is older than the timeout threshold.
if (confirm(_("Would you like to continue editing the form that was autosaved {1}? Clicking ‘Cancel’ will erase the saved form data.".format(new Date(+_get('last-saved')).toLocaleString())))) {
_load();
} else {
reset();
}
} else {
// Just load the form.
_load();
}
// Regularly save the form fields at a set interval.
setInterval(function () {
save();
}, options['interval']);
// Instantly save the form fields when the user leaves the page.
$(window).on('beforeunload', function () {
save();
});
};
//
// Save all fields now.
//
var save = function (allowempty) {
// Optional function argument.
allowempty = typeof allowempty !== 'undefined' ? allowempty : false;
// Only execute on pages which contain the DOM elements specified in context.
if (options['context'] && !$(options['context']).length) {
return;
}
var saved = false;
// Loop through all the specified form fields.
for (var i = 0; i < options['fields'].length; i++) {
var f = options['fields'][i];
// Select each form field by its name.
$('input[name="' + f + '"]', $(options['context'])).each(function () {
// If there is a value and it is not an empty JSON string, then save the value to local storage.
if (allowempty || $(this).val() && $(this).val() !== '[]') {
_set(f, $(this).val());
saved = true;
}
});
}
if (saved) {
// Only save a last saved timestamp is some value was saved.
_set('last-saved', Date.now());
}
};
//
// Reset all form fields to empty.
//
var reset = function () {
// Only execute on pages which contain the DOM elements specified in context.
if (options['context'] && !$(options['context']).length) {
return;
}
for (var i = 0; i < options['fields'].length; i++) {
localStorage.removeItem(options['prefix'] + options['fields'][i]);
}
// Set the last saved timestamp to null so that the timeout prompt will not trigger.
_set('last-saved', null);
};
//
// Set a localStorage value
//
var _set = function (k, v) {
try {
localStorage.setItem(options['prefix'] + k, v);
} catch (e) {
sc_msg.raise(_("An error occurred while saving. Please try again, or restart your browser."), 'alert');
Log.err('localStorage quota exceeded or user in Private Browsing mode', Log.ln());
}
};
//
// Get a localStorage value
//
var _get = function (k) {
return localStorage.getItem(options['prefix'] + k);
};
//
// Load saved data into form fields.
//
var _load = function () {
// Loop through all the specified form fields.
for (var i = 0; i < options['fields'].length; i++) {
var f = options['fields'][i];
// Select each form field by its name.
$('input[name="' + f + '"]', $(options['context'])).each(function () {
// If we can get a value and the current field is empty or contains an empty JSON string, then set the form field to the saved localStorage value.
if (_get(f) && (!$(this).val() || $(this).val() === '[]')) {
$(this).val(_get(f));
}
});
}
options['loaded']();
};
//
// Reveal module functions.
//
return {
init: init,
run: run,
save: save,
reset: reset
};
}(jQuery));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment