Resumable Get Quote process, save/cache all answers until successful quote completion
FeaturedInsurance customers can get interrupted before they complete the Get Quote process.
They might have problems with their Internet connection, their computer may crash or someone offers them lunch! :)
Adding the following code below (via Admin > Website > Custom Javascript) will save your customers answers as they type, so when they resume their application later using the same device/computer their answers will all be restored and they can resume from where they left off !
(As soon as they successfully complete the questions page in Get Quote the answers cache is cleared so they can complete fresh applications in future.)
This plugin was built in response to the following and other feature requests...
- http://support.admnetwork.com/entries/25039978-Ability-to-save-a-part-complete-quotation
- http://support.admnetwork.com/entries/84377626-Save-Button
Let us know how you get on with this plugin!
Team SchemeServe
// Plugin for caching forms using HTML5 local storage // Originally based on https://github.com/marcuswestin/store.js (function ($, win) { // Exposes a simple API for cross browser local storage // Uses localStorage when available, and falls back on // the userData behavior in IE6 and IE7. // No cookies to fatten network requests. // Depends on JSON for serialization to disk. var store = {}, doc = win.document, localStorageName = 'localStorage', scriptTag = 'script', storage store.disabled = false store.set = function(key, value) {} store.get = function(key) {} store.remove = function(key) {} store.clear = function() {} store.transact = function(key, defaultVal, transactionFn) { var val = store.get(key) if (transactionFn == null) { transactionFn = defaultVal defaultVal = null } if (typeof val == 'undefined') { val = defaultVal || {} } transactionFn(val) store.set(key, val) } store.getAll = function() {} store.forEach = function() {} store.serialize = function(value) { return JSON.stringify(value) } store.deserialize = function(value) { if (typeof value != 'string') { return undefined } try { return JSON.parse(value) } catch(e) { return value || undefined } } // Functions to encapsulate questionable FireFox 3.6.13 behavior // when about.config::dom.storage.enabled === false // See https://github.com/marcuswestin/store.js/issues#issue/13 function isLocalStorageNameSupported() { try { return (localStorageName in win && win[localStorageName]) } catch(err) { return false } } if (isLocalStorageNameSupported()) { storage = win[localStorageName] store.set = function(key, val) { if (val === undefined) { return store.remove(key) } storage.setItem(key, store.serialize(val)) return val } store.get = function(key) { return store.deserialize(storage.getItem(key)) } store.remove = function(key) { storage.removeItem(key) } store.clear = function() { storage.clear() } store.getAll = function() { var ret = {} store.forEach(function(key, val) { ret[key] = val }) return ret } store.forEach = function(callback) { for (var i=0; i<storage.length; i++) { var key = storage.key(i) callback(key, store.get(key)) } } } else if (doc.documentElement.addBehavior) { var storageOwner, storageContainer // Since #userData storage applies only to specific paths, we need to // somehow link our data to a specific path. We choose /favicon.ico // as a pretty safe option, since all browsers already make a request to // this URL anyway and being a 404 will not hurt us here. We wrap an // iframe pointing to the favicon in an ActiveXObject(htmlfile) object // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx) // since the iframe access rules appear to allow direct access and // manipulation of the document element, even for a 404 page. This // document can be used instead of the current document (which would // have been limited to the current path) to perform #userData storage. try { storageContainer = new ActiveXObject('htmlfile') storageContainer.open() storageContainer.write('<'+scriptTag+'>document.w=window
') storageContainer.close() storageOwner = storageContainer.w.frames[0].document storage = storageOwner.createElement('div') } catch(e) { // somehow ActiveXObject instantiation failed (perhaps some special // security settings or otherwse), fall back to per-path storage storage = doc.createElement('div') storageOwner = doc.body } function withIEStorage(storeFunction) { return function() { var args = Array.prototype.slice.call(arguments, 0) args.unshift(storage) // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx storageOwner.appendChild(storage) storage.addBehavior('#default#userData') storage.load(localStorageName) var result = storeFunction.apply(store, args) storageOwner.removeChild(storage) return result } } // In IE7, keys cannot start with a digit or contain certain chars. // See https://github.com/marcuswestin/store.js/issues/40 // See https://github.com/marcuswestin/store.js/issues/83 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g") function ieKeyFix(key) { return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___') } store.set = withIEStorage(function(storage, key, val) { key = ieKeyFix(key) if (val === undefined) { return store.remove(key) } storage.setAttribute(key, store.serialize(val)) storage.save(localStorageName) return val }) store.get = withIEStorage(function(storage, key) { key = ieKeyFix(key) return store.deserialize(storage.getAttribute(key)) }) store.remove = withIEStorage(function(storage, key) { key = ieKeyFix(key) storage.removeAttribute(key) storage.save(localStorageName) }) store.clear = withIEStorage(function(storage) { var attributes = storage.XMLDocument.documentElement.attributes storage.load(localStorageName) for (var i=0, attr; attr=attributes[i]; i++) { storage.removeAttribute(attr.name) } storage.save(localStorageName) }) store.getAll = function(storage) { var ret = {} store.forEach(function(key, val) { ret[key] = val }) return ret } store.forEach = withIEStorage(function(storage, callback) { var attributes = storage.XMLDocument.documentElement.attributes for (var i=0, attr; attr=attributes[i]; ++i) { callback(attr.name, store.deserialize(storage.getAttribute(attr.name))) } }) } try { var testKey = '__storejs__' store.set(testKey, testKey) if (store.get(testKey) != testKey) { store.disabled = true } store.remove(testKey) } catch(e) { store.disabled = true } store.enabled = !store.disabled /** * @param $form * @constructor */ function FormCache($form){ var self = this; var form = $form.get(0); // use unique name based on url and form index var key = window.location.href.replace(/\W/g, "") + "_" + $form.index(); var data = store.get(key) || {}; this.onFieldChange = function(event) { var $target = $(event.currentTarget); var fieldName = $target.attr('name'); data[fieldName] = $target.val(); store.set(key, data); } // Restore data from cache $.each(data, function(key, value){ $form.find('[name="'+ key +'"]').val(value); }); $form.on('change', 'select', $.proxy(this.onFieldChange, this)); $form.on('keyup', 'input,textarea', $.proxy(this.onFieldChange, this)); $form.submit(function(){ store.remove(key); }); form.clearCache = function(){ store.remove(key); } $form.find("[data-reset='formCache']").click(function(){ form.clearCache(); }); } $(function(){ // only run on Get Quote page if ( !$('#ctl00_MainContent_PageTitle')[0] ) { return; } var title = $('#ctl00_MainContent_PageTitle').text(); if (title.indexOf('Quotation Request') == -1) { return; } $("form").each(function(el){ FormCache($(this)); }); }); }(jQuery, window)); jQuery(function(){ // add handler to the finish button in order clear the cache for all fields jQuery(".QuestionPage_Save").click(function(){ // reset the form jQuery("#aspnetForm").get(0).clearCache(); }); });
Please sign in to leave a comment.
Comments
0 comments