File: jquery.handleStorage.js

Recommend this page to a friend!
  Classes of Jason Gerfen   jQuery.handleStorage   jquery.handleStorage.js   Download  
File: jquery.handleStorage.js
Role: Class source
Content type: text/plain
Description: Class source
Class: jQuery.handleStorage
Save forms in cookies, local or session storage
Author: By
Last change: Tue Jan 29 10:51:36 MST 2013 - Improved key creation & strength for transparently encrypting form data
Mon Sep 3 19:33:37 MDT 2012 - Problem with key on encrypting form elements and array of radio or checkbox elements
Mon Sep 3 18:38:55 MDT 2012 - Working on resolving a bug within the form selector when multiple forms using the same storage key and adding support for radio and checkboxes
Date: 10 years ago
Size: 13,271 bytes
 

Contents

Class file image Download
/** * * jQuery plugin to impliment local storage with optional AES * encryption support via the Gibberish-AES libraries * * Fork me @ https://www.github.com/jas-/jQuery.handleStorage * * FEATURES: * - HTML5 localStorage support * - HTML5 sessionStorage support * - Cookie support * - AES encryption support * * REQUIREMENTS: * - jQuery libraries (required - http://www.jquery.com) * - jQuery cookie plugin (optional - http://plugins.jquery.com/files/jquery.cookie.js.txt) * - Gibberish-AES libraries (optional - https://github.com/mdp/gibberish-aes) * * OPTIONS: * - appID: Unique identifier used as storage object key * - interval: Amount of time betwen auto-saves (default 5sec) * - storage: HTML5 localStorage, sessionStorage and cookies supported * - aes: Use AES encryption for local storage * - uuid: Random RFC-4122 string used as AES password * * Author: Jason Gerfen * Email: jason.gerfen@gmail.com * Copyright: Jason Gerfen * * License: GPL * */ (function($){ /** * @function jQuery.handleStorage * @abstract Plug-in used to assist in client storage items * @param method string Method to employ for form ID DOM object * init (transparent getting and setting of * form elements) * @param options object options object for specific operations * appID, storage, aes */ $.fn.handleStorage = function(method){ /** * @object defaults * @abstract Default set of options for plug-in */ var defaults = { appID: 'jQuery.handleStorage', // Application ID, used as index storage: 'localStorage', // Storage type localStorage || sessionStorage || cookie (cookie storage requires jQuery cookie plugin) interval: 5000, // Amount of time between auto-saves (default is 5sec) aes: false, // Use AES encryption? (true or false) uuid: '', // Random RFC-4122 string form: '', // Place holder for form ID data: {}, // Place holder for storage objects callback: function(){}, // An on save callback preCallback: function(){}, // Process callback prior to save errCallback: function(){} // Callback to execute on error }; /** * @object methods * @abstract Plug-in methods */ var methods = { /** * @method init * @abstract Default plug-in method. Provides transparent client storage * of form data using HTML5 client storage or cookies with * optional AES encryption support */ init: function(o){ var opts = $.extend({}, defaults, o); opts.form = $(this).attr('id'); if (vO(opts)){ opts.data[opts.appID] = (_e(opts)) ? _e(opts) : {}; var orig = gStore(opts); if ((typeof orig==='object')&&(sChk(orig)>0)){ sF(opts, orig); } ((opts.preCallback)&&($.isFunction(opts.preCallback))) ? opts.preCallback($(this)) : false; $('#'+opts.form).delegate('input, input:radio:selected, input:checkbox:checked, select, textarea', 'change keyup blur submit', function(){ svF(opts); }); setInterval(function(){svF(opts);}, opts.interval); return true; } else { return false; } } }; /** * @function sChk * @abstract Performs a check on object sizes */ var sChk = function(obj) { var n = 0; $.each(obj, function(k, v){ if (obj.hasOwnProperty(k)) n++; }); return n; } /** * @function _l * @abstract Performs check on current value of local storage objects * Uses 5mb for HTML5 local/session storage & 4k for cookies */ var _l = function(type) { var lim = /local|session/.test(type) ? 1024 * 1025 * 5 : 1024 * 4; if (lim - unescape(encodeURIComponent(JSON.stringify(type))).length <= 0) { console.log('Maximum quota has been met using '+type); return false; } return true; } /** * @function sI * @abstract Proxy function for setting data with specified client storage * option */ var sI = function(type, k, v) { var x = false; type = (vStore(type)) ? type : 'cookie'; if (_l(type)) { switch(type) { case 'localStorage': x = sL(k, v); break; case 'sessionStorage': x = sS(k, v); break; case 'cookie': x = sC(k, v); break; default: x = sL(k, v); break; } } return x; } /** * @function gI * @abstract Proxy function for getting data with specified client storage * option */ var gI = function(type, k) { var x = false; type = (vStore(type)) ? type : 'cookie'; switch(type) { case 'localStorage': x = gL(k); break; case 'sessionStorage': x = gS(k); break; case 'cookie': x = gC(k); break; default: x = gL(k); break; } return x; } /** * @function sL * @abstract Function used to set localStorage items */ var sL = function(k, v) { return (localStorage.setItem(k, v)) ? false : true; } /** * @function sS * @abstract Function used to set sessionStorage items */ var sS = function(k, v) { return (sessionStorage.setItem(k, v)) ? false : true; } /** * @function sC * @abstract Function used to set cookie items */ var sC = function(k, v) { if (typeof $.cookie === 'function') { return ($.cookie(k, v, {expires: 7})) ? true : false; } else { return false; } } /** * @function gL * @abstract Function used to get localStorage items */ var gL = function(k) { return (localStorage.getItem(k)) ? localStorage.getItem(k) : false; } /** * @function gS * @abstract Function used to get sessionStorage items */ var gS = function(k) { return (sessionStorage.getItem(k)) ? sessionStorage.getItem(k) : false; } /** * @function sC * @abstract Function used to get cookie items */ var gC = function(name) { if (typeof $.cookie === 'function') { return ($.cookie(name)) ? $.cookie(name) : false; } else { return false; } } /** * @function _e * @abstract Function used to return configured storage items * as JSON object */ var _e = function(o) { return (gI(o.storage, o.appID)) ? JSON.parse(gI(o.storage, o.appID)) : false; } /** * @function gStore * @abstract Function to compare and decrypt if necessary, existing * storage items to configured form input elements */ var gStore = function(o) { var ret={}, x; if (typeof o.data[o.appID][o.form]==='object'){ $.each($('#'+o.form+' > :input'), function(k, v){ if ((vStr(v.name)!==false)&&(vStr(o.data[o.appID][o.form][v.name])!==false)){ if (typeof(o.data[o.appID][o.form][v.name])=='object') { var _x = []; var _i = 0; $.each(o.data[o.appID][o.form][v.name], function(a, b){ _x[_i] = ((o.aes)&&(o.data[o.appID][o.form]['uuid'])&&(x!==false)) ? GibberishAES.dec(b, _s(uid(), __strIV(o.data[o.appID][o.form]['uuid']))) : b; }); ret[v.name] = _x; __r(ret[v.name]); } else { ret[v.name] = ((o.aes)&&(o.data[o.appID][o.form]['uuid'])&&(x!==false)) ? GibberishAES.dec(o.data[o.appID][o.form][v.name], _s(uid(), __strIV(o.data[o.appID][o.form]['uuid']))) : o.data[o.appID][o.form][v.name]; } } }); } return ret; } /** * @function sF * @abstract Sets input values within configured form */ var sF = function(o, arg){ if (sChk(arg)>0){ $.each(arg, function(a, b){ if (($('#'+o.form+' > input[name='+a+']').attr('name')===a)||($('#'+o.form+' > select[name='+a+']').attr('name')===a)||($('#'+o.form+' > textarea[name='+a+']').attr('name')===a)&&(vStr(b)!==false)){ if ((/checkbox|radio/.test($('#'+o.form+' > input[name='+a+']').attr('type')))&&($('#'+o.form+' > input[name='+a+']').attr('value')==b)) { $('#'+o.form+' > input[name='+a+']').attr('checked', true); } else { $('#'+o.form+' > input[name='+a+'], #'+o.form+' > select[name='+a+'], #'+o.form+' > textarea[name='+a+']').val(b); } } }); } } /** * @function svF * @abstract Saves non-null form elements to configured client storage * mechanism, encrypting if configured as a nested JSON object */ var svF = function(o){ var x={}; x[o.form]={}; x[o.form]['uuid'] = ((o.aes)&&(!o.uuid)) ? hK(o) : o.uuid; $.each($('#'+o.form+' > :input'), function(k, v){ if ((vStr(v.value)!==false)&&(vStr(v.name)!==false)){ if (/checkbox|radio/.test(v.type)){ x[o.form][v.name]=gG(o,v,v.type,x[o.form]['uuid']); } else { x[o.form][v.name] = ((o.aes)&&(x[o.form]['uuid'])) ? GibberishAES.enc(v.value, _s(uid(), __strIV(x[o.form]['uuid']))) : v.value; } } }); o.data[o.appID] = (sChk(o.data[o.appID])>0) ? $.extend({}, o.data[o.appID], x) : x; if (sI(o.storage, o.appID, JSON.stringify(o.data[o.appID]))){ ((o.callback)&&($.isFunction(o.callback))) ? o.callback.call($(this)) : false; } else { ((o.errCallback)&&($.isFunction(o.errCallback))) ? o.errCallback.call($(this)) : false; } } /** * @function gG * @abstract Return array of checked checkboxes or selected radio elements */ var gG = function(o, obj, t, key){ return $('#'+o.form+' > input:'+t+':checked').map(function(){ return ((o.aes)&&(key)) ? GibberishAES.enc(this.value, _s(uid(), __strIV(key))) : this.value; }).get(); } /** * @function vStr * @abstract Verifies string integrity */ var vStr = function(string){ if (string){ return ((string===false)||(string.length===0)||(!string)||(string===null)||(string==='')||(typeof string==='undefined')) ? false : true; } else { return false; } } /** * @function vStore * @abstract Ensures configured storage mechanism is available for the * browser engine */ var vStore = function(type){ try { return ((type in window)&&(window[type])) ? true : false; } catch (e) { console.log('The '+type+' storage mechanism does not exist, please upgrade your browser'); return false; } } /** * @function vO * @abstract Tests configured o vs. available functionality */ var vO = function(opts){ var ret = true; if (opts.aes){ if (!$.isFunction(GibberishAES.enc)){ console.log('AES use specified but required libraries not available. Please include the Gibberish-AES libs...'); ret = false; } } if (opts.storage==='cookie'){ if (!$.isFunction($.cookie)){ console.log('Cookie use specified but required libraries not available. Please include the jQuery cookie plugin...'); ret = false; } } return ret; } /** * @function gUUID * @abstract Generates a valid RFC-4122 UUID */ var gUUID = function(len){ var chars = '0123456789abcdef'.split(''); var uuid = [], rnd = Math.random, r; uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; for (var i = 0; i < 36; i++){ if (!uuid[i]){ r = 0 | rnd()*16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf]; } } return (len!==null) ? uuid.join('').replace(/-/g, '').split('',len).join('') : uuid.join(''); } /** * @function uid * @abstract Generate uid */ var uid = function(){ return window.navigator.appName+ window.navigator.appCodeName+ window.navigator.product+ window.navigator.productSub+ window.navigator.appVersion+ window.navigator.buildID+ window.navigator.userAgent+ window.navigator.language+ window.navigator.platform+ window.navigator.oscpu; } /** * @function _s * @abstract Strengthen key */ var _s = function(str, slt){ var _h = []; _h[0] = GibberishAES.Hash.MD5(str); var _r = []; _r = _h[0]; var _d; for (i = 1; i < 3; i++){ _h[i] = GibberishAES.Hash.MD5(_h[i - 1].concat(slt)); _d = _r.concat(_h[i]); } return JSON.stringify(_d); } /** * @function hK * @abstract Performs key generation or retrieval */ var hK = function(o) { if (o.aes){ var x = (_e(o)) ? _e(o) : {}; x[o.form] = (x[o.form]) ? x[o.form] : {}; var y = (vStr(x[o.form]['uuid'])) ? x[o.form]['uuid'] : gUUID(null); return y; } return false; } /** * @function strIV * @abstract Generate IV from string */ var __strIV = function(s){ return (s) ? encodeURI(s.replace(/-/gi, '').substring(16,Math.ceil(16*s.length)%s.length)) : false; } /** * @function __r * @abstract Function used help debug objects recursively */ var __r = function(obj){ $.each(obj, function(x,y){ if (typeof y==='object'){ __r(y); } else { console.log(x+' => '+y); } }); } /* robot, do something */ if (methods[method]){ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if ((typeof method==='object')||(!method)){ return methods.init.apply(this, arguments); } else { $.error('Method '+method+' does not exist on '+opts.name); } }; })(jQuery);