libjs-jstorage-0.3.1/0000755000000000000000000000000012064651222013130 5ustar rootrootlibjs-jstorage-0.3.1/.gitignore0000664000000000000000000000001212064636655015130 0ustar rootroot.DS_Store libjs-jstorage-0.3.1/jstorage.js0000664000000000000000000010750612064636655015334 0ustar rootroot/* * ----------------------------- JSTORAGE ------------------------------------- * Simple local storage wrapper to save data on the browser side, supporting * all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+ * * Copyright (c) 2010 - 2012 Andris Reinman, andris.reinman@gmail.com * Project homepage: www.jstorage.info * * Licensed under MIT-style license: * * 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 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. */ (function(){ var /* jStorage version */ JSTORAGE_VERSION = "0.3.1", /* detect a dollar object or create one if not found */ $ = window.jQuery || window.$ || (window.$ = {}), /* check for a JSON handling support */ JSON = { parse: window.JSON && (window.JSON.parse || window.JSON.decode) || String.prototype.evalJSON && function(str){return String(str).evalJSON();} || $.parseJSON || $.evalJSON, stringify: Object.toJSON || window.JSON && (window.JSON.stringify || window.JSON.encode) || $.toJSON }; // Break if no JSON support was found if(!JSON.parse || !JSON.stringify){ throw new Error("No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page"); } var /* This is the object, that holds the cached values */ _storage = {}, /* Actual browser storage (localStorage or globalStorage['domain']) */ _storage_service = {jStorage:"{}"}, /* DOM element for older IE versions, holds userData behavior */ _storage_elm = null, /* How much space does the storage take */ _storage_size = 0, /* which backend is currently used */ _backend = false, /* onchange observers */ _observers = {}, /* timeout to wait after onchange event */ _observer_timeout = false, /* last update time */ _observer_update = 0, /* pubsub observers */ _pubsub_observers = {}, /* skip published items older than current timestamp */ _pubsub_last = +new Date(), /* Next check for TTL */ _ttl_timeout, /** * XML encoding and decoding as XML nodes can't be JSON'ized * XML nodes are encoded and decoded if the node is the value to be saved * but not if it's as a property of another object * Eg. - * $.jStorage.set("key", xmlNode); // IS OK * $.jStorage.set("key", {xml: xmlNode}); // NOT OK */ _XMLService = { /** * Validates a XML node to be XML * based on jQuery.isXML function */ isXML: function(elm){ var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }, /** * Encodes a XML node to string * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/ */ encode: function(xmlNode) { if(!this.isXML(xmlNode)){ return false; } try{ // Mozilla, Webkit, Opera return new XMLSerializer().serializeToString(xmlNode); }catch(E1) { try { // IE return xmlNode.xml; }catch(E2){} } return false; }, /** * Decodes a XML node from string * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/ */ decode: function(xmlString){ var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) || (window.ActiveXObject && function(_xmlString) { var xml_doc = new ActiveXObject('Microsoft.XMLDOM'); xml_doc.async = 'false'; xml_doc.loadXML(_xmlString); return xml_doc; }), resultXML; if(!dom_parser){ return false; } resultXML = dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml'); return this.isXML(resultXML)?resultXML:false; } }, _localStoragePolyfillSetKey = function(){}; ////////////////////////// PRIVATE METHODS //////////////////////// /** * Initialization function. Detects if the browser supports DOM Storage * or userData behavior and behaves accordingly. */ function _init(){ /* Check if browser supports localStorage */ var localStorageReallyWorks = false; if("localStorage" in window){ try { window.localStorage.setItem('_tmptest', 'tmpval'); localStorageReallyWorks = true; window.localStorage.removeItem('_tmptest'); } catch(BogusQuotaExceededErrorOnIos5) { // Thanks be to iOS5 Private Browsing mode which throws // QUOTA_EXCEEDED_ERRROR DOM Exception 22. } } if(localStorageReallyWorks){ try { if(window.localStorage) { _storage_service = window.localStorage; _backend = "localStorage"; _observer_update = _storage_service.jStorage_update; } } catch(E3) {/* Firefox fails when touching localStorage and cookies are disabled */} } /* Check if browser supports globalStorage */ else if("globalStorage" in window){ try { if(window.globalStorage) { _storage_service = window.globalStorage[window.location.hostname]; _backend = "globalStorage"; _observer_update = _storage_service.jStorage_update; } } catch(E4) {/* Firefox fails when touching localStorage and cookies are disabled */} } /* Check if browser supports userData behavior */ else { _storage_elm = document.createElement('link'); if(_storage_elm.addBehavior){ /* Use a DOM element to act as userData storage */ _storage_elm.style.behavior = 'url(#default#userData)'; /* userData element needs to be inserted into the DOM! */ document.getElementsByTagName('head')[0].appendChild(_storage_elm); try{ _storage_elm.load("jStorage"); }catch(E){ // try to reset cache _storage_elm.setAttribute("jStorage", "{}"); _storage_elm.save("jStorage"); _storage_elm.load("jStorage"); } var data = "{}"; try{ data = _storage_elm.getAttribute("jStorage"); }catch(E5){} try{ _observer_update = _storage_elm.getAttribute("jStorage_update"); }catch(E6){} _storage_service.jStorage = data; _backend = "userDataBehavior"; }else{ _storage_elm = null; return; } } // Load data from storage _load_storage(); // remove dead keys _handleTTL(); // create localStorage and sessionStorage polyfills if needed _createPolyfillStorage("local"); _createPolyfillStorage("session"); // start listening for changes _setupObserver(); // initialize publish-subscribe service _handlePubSub(); // handle cached navigation if("addEventListener" in window){ window.addEventListener("pageshow", function(event){ if(event.persisted){ _storageObserver(); } }, false); } } /** * Create a polyfill for localStorage (type="local") or sessionStorage (type="session") * * @param {String} type Either "local" or "session" * @param {Boolean} forceCreate If set to true, recreate the polyfill (needed with flush) */ function _createPolyfillStorage(type, forceCreate){ var _skipSave = false, _length = 0, i, storage, storage_source = {}; var rand = Math.random(); if(!forceCreate && typeof window[type+"Storage"] != "undefined"){ return; } // Use globalStorage for localStorage if available if(type == "local" && window.globalStorage){ localStorage = window.globalStorage[window.location.hostname]; return; } // only IE6/7 from this point on if(_backend != "userDataBehavior"){ return; } // Remove existing storage element if available if(forceCreate && window[type+"Storage"] && window[type+"Storage"].parentNode){ window[type+"Storage"].parentNode.removeChild(window[type+"Storage"]); } storage = document.createElement("button"); document.getElementsByTagName('head')[0].appendChild(storage); if(type == "local"){ storage_source = _storage; }else if(type == "session"){ _sessionStoragePolyfillUpdate(); } for(i in storage_source){ if(storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i != "length" && typeof storage_source[i] != "undefined"){ if(!(i in storage)){ _length++; } storage[i] = storage_source[i]; } } // Polyfill API /** * Indicates how many keys are stored in the storage */ storage.length = _length; /** * Returns the key of the nth stored value * * @param {Number} n Index position * @return {String} Key name of the nth stored value */ storage.key = function(n){ var count = 0, i; _sessionStoragePolyfillUpdate(); for(i in storage_source){ if(storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i!="length" && typeof storage_source[i] != "undefined"){ if(count == n){ return i; } count++; } } } /** * Returns the current value associated with the given key * * @param {String} key key name * @return {Mixed} Stored value */ storage.getItem = function(key){ _sessionStoragePolyfillUpdate(); if(type == "session"){ return storage_source[key]; } return $.jStorage.get(key); } /** * Sets or updates value for a give key * * @param {String} key Key name to be updated * @param {String} value String value to be stored */ storage.setItem = function(key, value){ if(typeof value == "undefined"){ return; } storage[key] = (value || "").toString(); } /** * Removes key from the storage * * @param {String} key Key name to be removed */ storage.removeItem = function(key){ if(type == "local"){ return $.jStorage.deleteKey(key); } storage[key] = undefined; _skipSave = true; if(key in storage){ storage.removeAttribute(key); } _skipSave = false; } /** * Clear storage */ storage.clear = function(){ if(type == "session"){ window.name = ""; _createPolyfillStorage("session", true); return; } $.jStorage.flush(); } if(type == "local"){ _localStoragePolyfillSetKey = function(key, value){ if(key == "length"){ return; } _skipSave = true; if(typeof value == "undefined"){ if(key in storage){ _length--; storage.removeAttribute(key); } }else{ if(!(key in storage)){ _length++; } storage[key] = (value || "").toString(); } storage.length = _length; _skipSave = false; } } function _sessionStoragePolyfillUpdate(){ if(type != "session"){ return; } try{ storage_source = JSON.parse(window.name || "{}"); }catch(E){ storage_source = {}; } } function _sessionStoragePolyfillSave(){ if(type != "session"){ return; } window.name = JSON.stringify(storage_source); }; storage.attachEvent("onpropertychange", function(e){ if(e.propertyName == "length"){ return; } if(_skipSave || e.propertyName == "length"){ return; } if(type == "local"){ if(!(e.propertyName in storage_source) && typeof storage[e.propertyName] != "undefined"){ _length ++; } }else if(type == "session"){ _sessionStoragePolyfillUpdate(); if(typeof storage[e.propertyName] != "undefined" && !(e.propertyName in storage_source)){ storage_source[e.propertyName] = storage[e.propertyName]; _length++; }else if(typeof storage[e.propertyName] == "undefined" && e.propertyName in storage_source){ delete storage_source[e.propertyName]; _length--; }else{ storage_source[e.propertyName] = storage[e.propertyName]; } _sessionStoragePolyfillSave(); storage.length = _length; return; } $.jStorage.set(e.propertyName, storage[e.propertyName]); storage.length = _length; }); window[type+"Storage"] = storage; } /** * Reload data from storage when needed */ function _reloadData(){ var data = "{}"; if(_backend == "userDataBehavior"){ _storage_elm.load("jStorage"); try{ data = _storage_elm.getAttribute("jStorage"); }catch(E5){} try{ _observer_update = _storage_elm.getAttribute("jStorage_update"); }catch(E6){} _storage_service.jStorage = data; } _load_storage(); // remove dead keys _handleTTL(); _handlePubSub(); } /** * Sets up a storage change observer */ function _setupObserver(){ if(_backend == "localStorage" || _backend == "globalStorage"){ if("addEventListener" in window){ window.addEventListener("storage", _storageObserver, false); }else{ document.attachEvent("onstorage", _storageObserver); } }else if(_backend == "userDataBehavior"){ setInterval(_storageObserver, 1000); } } /** * Fired on any kind of data change, needs to check if anything has * really been changed */ function _storageObserver(){ var updateTime; // cumulate change notifications with timeout clearTimeout(_observer_timeout); _observer_timeout = setTimeout(function(){ if(_backend == "localStorage" || _backend == "globalStorage"){ updateTime = _storage_service.jStorage_update; }else if(_backend == "userDataBehavior"){ _storage_elm.load("jStorage"); try{ updateTime = _storage_elm.getAttribute("jStorage_update"); }catch(E5){} } if(updateTime && updateTime != _observer_update){ _observer_update = updateTime; _checkUpdatedKeys(); } }, 25); } /** * Reloads the data and checks if any keys are changed */ function _checkUpdatedKeys(){ var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)), newCrc32List; _reloadData(); newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)); var key, updated = [], removed = []; for(key in oldCrc32List){ if(oldCrc32List.hasOwnProperty(key)){ if(!newCrc32List[key]){ removed.push(key); continue; } if(oldCrc32List[key] != newCrc32List[key] && String(oldCrc32List[key]).substr(0,2) == "2."){ updated.push(key); } } } for(key in newCrc32List){ if(newCrc32List.hasOwnProperty(key)){ if(!oldCrc32List[key]){ updated.push(key); } } } _fireObservers(updated, "updated"); _fireObservers(removed, "deleted"); } /** * Fires observers for updated keys * * @param {Array|String} keys Array of key names or a key * @param {String} action What happened with the value (updated, deleted, flushed) */ function _fireObservers(keys, action){ keys = [].concat(keys || []); if(action == "flushed"){ keys = []; for(var key in _observers){ if(_observers.hasOwnProperty(key)){ keys.push(key); } } action = "deleted"; } for(var i=0, len = keys.length; i=0; i--){ pubelm = _storage.__jstorage_meta.PubSub[i]; if(pubelm[0] > _pubsub_last){ _pubsubCurrent = pubelm[0]; _fireSubscribers(pubelm[1], pubelm[2]); } } _pubsub_last = _pubsubCurrent; } /** * Fires all subscriber listeners for a pubsub channel * * @param {String} channel Channel name * @param {Mixed} payload Payload data to deliver */ function _fireSubscribers(channel, payload){ if(_pubsub_observers[channel]){ for(var i=0, len = _pubsub_observers[channel].length; iGary Court * @see http://github.com/garycourt/murmurhash-js * @author Austin Appleby * @see http://sites.google.com/site/murmurhash/ * * @param {string} str ASCII only * @param {number} seed Positive integer only * @return {number} 32-bit positive integer hash */ function murmurhash2_32_gc(str, seed) { var l = str.length, h = seed ^ l, i = 0, k; while (l >= 4) { k = ((str.charCodeAt(i) & 0xff)) | ((str.charCodeAt(++i) & 0xff) << 8) | ((str.charCodeAt(++i) & 0xff) << 16) | ((str.charCodeAt(++i) & 0xff) << 24); k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16)); k ^= k >>> 24; k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16)); h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k; l -= 4; ++i; } switch (l) { case 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16; case 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8; case 1: h ^= (str.charCodeAt(i) & 0xff); h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)); } h ^= h >>> 13; h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)); h ^= h >>> 15; return h >>> 0; } ////////////////////////// PUBLIC INTERFACE ///////////////////////// $.jStorage = { /* Version number */ version: JSTORAGE_VERSION, /** * Sets a key's value. * * @param {String} key Key to set. If this value is not set or not * a string an exception is raised. * @param {Mixed} value Value to set. This can be any value that is JSON * compatible (Numbers, Strings, Objects etc.). * @param {Object} [options] - possible options to use * @param {Number} [options.TTL] - optional TTL value * @return {Mixed} the used value */ set: function(key, value, options){ _checkKey(key); options = options || {}; // undefined values are deleted automatically if(typeof value == "undefined"){ this.deleteKey(key); return value; } if(_XMLService.isXML(value)){ value = {_is_xml:true,xml:_XMLService.encode(value)}; }else if(typeof value == "function"){ return undefined; // functions can't be saved! }else if(value && typeof value == "object"){ // clone the object before saving to _storage tree value = JSON.parse(JSON.stringify(value)); } _storage[key] = value; _storage.__jstorage_meta.CRC32[key] = "2."+murmurhash2_32_gc(JSON.stringify(value), 0x9747b28c); this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange _localStoragePolyfillSetKey(key, value); _fireObservers(key, "updated"); return value; }, /** * Looks up a key in cache * * @param {String} key - Key to look up. * @param {mixed} def - Default value to return, if key didn't exist. * @return {Mixed} the key value, default value or null */ get: function(key, def){ _checkKey(key); if(key in _storage){ if(_storage[key] && typeof _storage[key] == "object" && _storage[key]._is_xml && _storage[key]._is_xml){ return _XMLService.decode(_storage[key].xml); }else{ return _storage[key]; } } return typeof(def) == 'undefined' ? null : def; }, /** * Deletes a key from cache. * * @param {String} key - Key to delete. * @return {Boolean} true if key existed or false if it didn't */ deleteKey: function(key){ _checkKey(key); if(key in _storage){ delete _storage[key]; // remove from TTL list if(typeof _storage.__jstorage_meta.TTL == "object" && key in _storage.__jstorage_meta.TTL){ delete _storage.__jstorage_meta.TTL[key]; } delete _storage.__jstorage_meta.CRC32[key]; _localStoragePolyfillSetKey(key, undefined); _save(); _publishChange(); _fireObservers(key, "deleted"); return true; } return false; }, /** * Sets a TTL for a key, or remove it if ttl value is 0 or below * * @param {String} key - key to set the TTL for * @param {Number} ttl - TTL timeout in milliseconds * @return {Boolean} true if key existed or false if it didn't */ setTTL: function(key, ttl){ var curtime = +new Date(); _checkKey(key); ttl = Number(ttl) || 0; if(key in _storage){ if(!_storage.__jstorage_meta.TTL){ _storage.__jstorage_meta.TTL = {}; } // Set TTL value for the key if(ttl>0){ _storage.__jstorage_meta.TTL[key] = curtime + ttl; }else{ delete _storage.__jstorage_meta.TTL[key]; } _save(); _handleTTL(); _publishChange(); return true; } return false; }, /** * Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set * * @param {String} key Key to check * @return {Number} Remaining TTL in milliseconds */ getTTL: function(key){ var curtime = +new Date(), ttl; _checkKey(key); if(key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]){ ttl = _storage.__jstorage_meta.TTL[key] - curtime; return ttl || 0; } return 0; }, /** * Deletes everything in cache. * * @return {Boolean} Always true */ flush: function(){ _storage = {__jstorage_meta:{CRC32:{}}}; _createPolyfillStorage("local", true); _save(); _publishChange(); _fireObservers(null, "flushed"); return true; }, /** * Returns a read-only copy of _storage * * @return {Object} Read-only copy of _storage */ storageObj: function(){ function F() {} F.prototype = _storage; return new F(); }, /** * Returns an index of all used keys as an array * ['key1', 'key2',..'keyN'] * * @return {Array} Used keys */ index: function(){ var index = [], i; for(i in _storage){ if(_storage.hasOwnProperty(i) && i != "__jstorage_meta"){ index.push(i); } } return index; }, /** * How much space in bytes does the storage take? * * @return {Number} Storage size in chars (not the same as in bytes, * since some chars may take several bytes) */ storageSize: function(){ return _storage_size; }, /** * Which backend is currently in use? * * @return {String} Backend name */ currentBackend: function(){ return _backend; }, /** * Test if storage is available * * @return {Boolean} True if storage can be used */ storageAvailable: function(){ return !!_backend; }, /** * Register change listeners * * @param {String} key Key name * @param {Function} callback Function to run when the key changes */ listenKeyChange: function(key, callback){ _checkKey(key); if(!_observers[key]){ _observers[key] = []; } _observers[key].push(callback); }, /** * Remove change listeners * * @param {String} key Key name to unregister listeners against * @param {Function} [callback] If set, unregister the callback, if not - unregister all */ stopListening: function(key, callback){ _checkKey(key); if(!_observers[key]){ return; } if(!callback){ delete _observers[key]; return; } for(var i = _observers[key].length - 1; i>=0; i--){ if(_observers[key][i] == callback){ _observers[key].splice(i,1); } } }, /** * Subscribe to a Publish/Subscribe event stream * * @param {String} channel Channel name * @param {Function} callback Function to run when the something is published to the channel */ subscribe: function(channel, callback){ channel = (channel || "").toString(); if(!channel){ throw new TypeError('Channel not defined'); } if(!_pubsub_observers[channel]){ _pubsub_observers[channel] = []; } _pubsub_observers[channel].push(callback); }, /** * Publish data to an event stream * * @param {String} channel Channel name * @param {Mixed} payload Payload to deliver */ publish: function(channel, payload){ channel = (channel || "").toString(); if(!channel){ throw new TypeError('Channel not defined'); } _publish(channel, payload); }, /** * Reloads the data from browser storage */ reInit: function(){ _reloadData(); } }; // Initialize jStorage _init(); })();libjs-jstorage-0.3.1/jstorage.min.js0000664000000000000000000002233312064636655016110 0ustar rootroot(function(){function z(a,b){function g(){if("session"==a)try{h=n.parse(window.name||"{}")}catch(b){h={}}}var k=!1,e=0,j,d,h={};Math.random();if(b||"undefined"==typeof window[a+"Storage"])if("local"==a&&window.globalStorage)localStorage=window.globalStorage[window.location.hostname];else if("userDataBehavior"==m){b&&(window[a+"Storage"]&&window[a+"Storage"].parentNode)&&window[a+"Storage"].parentNode.removeChild(window[a+"Storage"]);d=document.createElement("button");document.getElementsByTagName("head")[0].appendChild(d); "local"==a?h=c:"session"==a&&g();for(j in h)h.hasOwnProperty(j)&&("__jstorage_meta"!=j&&"length"!=j&&"undefined"!=typeof h[j])&&(j in d||e++,d[j]=h[j]);d.length=e;d.key=function(a){var b=0,c;g();for(c in h)if(h.hasOwnProperty(c)&&"__jstorage_meta"!=c&&"length"!=c&&"undefined"!=typeof h[c]){if(b==a)return c;b++}};d.getItem=function(b){g();return"session"==a?h[b]:q.jStorage.get(b)};d.setItem=function(a,b){"undefined"!=typeof b&&(d[a]=(b||"").toString())};d.removeItem=function(b){if("local"==a)return q.jStorage.deleteKey(b); d[b]=void 0;k=!0;b in d&&d.removeAttribute(b);k=!1};d.clear=function(){"session"==a?(window.name="",z("session",!0)):q.jStorage.flush()};"local"==a&&(B=function(a,b){"length"!=a&&(k=!0,"undefined"==typeof b?a in d&&(e--,d.removeAttribute(a)):(a in d||e++,d[a]=(b||"").toString()),d.length=e,k=!1)});d.attachEvent("onpropertychange",function(b){if("length"!=b.propertyName&&!(k||"length"==b.propertyName)){if("local"==a)!(b.propertyName in h)&&"undefined"!=typeof d[b.propertyName]&&e++;else if("session"== a){g();"undefined"!=typeof d[b.propertyName]&&!(b.propertyName in h)?(h[b.propertyName]=d[b.propertyName],e++):"undefined"==typeof d[b.propertyName]&&b.propertyName in h?(delete h[b.propertyName],e--):h[b.propertyName]=d[b.propertyName];"session"==a&&(window.name=n.stringify(h));d.length=e;return}q.jStorage.set(b.propertyName,d[b.propertyName]);d.length=e}});window[a+"Storage"]=d}}function F(){var a="{}";if("userDataBehavior"==m){f.load("jStorage");try{a=f.getAttribute("jStorage")}catch(b){}try{s= f.getAttribute("jStorage_update")}catch(c){}l.jStorage=a}G();A();H()}function v(){var a;clearTimeout(I);I=setTimeout(function(){if("localStorage"==m||"globalStorage"==m)a=l.jStorage_update;else if("userDataBehavior"==m){f.load("jStorage");try{a=f.getAttribute("jStorage_update")}catch(b){}}if(a&&a!=s){s=a;var g=n.parse(n.stringify(c.__jstorage_meta.CRC32)),k;F();k=n.parse(n.stringify(c.__jstorage_meta.CRC32));var e,j=[],d=[];for(e in g)g.hasOwnProperty(e)&&(k[e]?g[e]!=k[e]&&"2."==String(g[e]).substr(0, 2)&&j.push(e):d.push(e));for(e in k)k.hasOwnProperty(e)&&(g[e]||j.push(e));t(j,"updated");t(d,"deleted")}},25)}function t(a,b){a=[].concat(a||[]);if("flushed"==b){a=[];for(var c in p)p.hasOwnProperty(c)&&a.push(c);b="deleted"}c=0;for(var k=a.length;cD){var b=a[0],k=a[1];a=a[2];if(u[k])for(var e=0,j=u[k].length;e>>16)&65535)<<16),f^=f>>>24,f=1540483477*(f&65535)+((1540483477*(f>>>16)&65535)<<16),d=1540483477*(d&65535)+((1540483477*(d>>>16)&65535)<<16)^f,j-=4,++h;switch(j){case 3:d^=(e.charCodeAt(h+2)&255)<<16;case 2:d^=(e.charCodeAt(h+1)&255)<<8;case 1:d^=e.charCodeAt(h)&255,d=1540483477*(d&65535)+((1540483477*(d>>>16)&65535)<<16)}d^=d>>>13;d=1540483477*(d&65535)+((1540483477*(d>>>16)&65535)<<16);k[a]="2."+((d^d>>>15)>>>0);this.setTTL(a,g.TTL||0);B(a,b);t(a,"updated");return b},get:function(a,b){r(a); return a in c?c[a]&&"object"==typeof c[a]&&c[a]._is_xml&&c[a]._is_xml?E.decode(c[a].xml):c[a]:"undefined"==typeof b?null:b},deleteKey:function(a){r(a);return a in c?(delete c[a],"object"==typeof c.__jstorage_meta.TTL&&a in c.__jstorage_meta.TTL&&delete c.__jstorage_meta.TTL[a],delete c.__jstorage_meta.CRC32[a],B(a,void 0),x(),w(),t(a,"deleted"),!0):!1},setTTL:function(a,b){var g=+new Date;r(a);b=Number(b)||0;return a in c?(c.__jstorage_meta.TTL||(c.__jstorage_meta.TTL={}),0 jStorage - simple JavaScript plugin to store data locally

jStorage - store data locally with JavaScript

jStorage is a simple wrapper plugin for Prototype, MooTools and jQuery to cache data on browser side.

Add some values and refresh the page - if your browser supports storing local data, then the values should survive the page refresh.

KEY VALUE TTL (ms)  
ADD
Clicking "GET" alerts the value for provided key with the method $.jStorage.get(key) GET
  Clear all saved data FLUSH
  Refresh to clear expired keys REFRESH

NB! Key "test" has a special meaning - if it is updated or deleted, all open windows of the same page will alert the change.

libjs-jstorage-0.3.1/README.md0000664000000000000000000000521712064636655014433 0ustar rootroot# jStorage **jStorage** is a cross-browser key-value store database to store data locally in the browser - jStorage supports all major browsers, both in **desktop** (yes - even Internet Explorer 6) and in **mobile**. Additionally jStorage is library agnostic, it works well with any other JavaScript library on the same webpage, be it jQuery, Prototype, MooTools or something else. Though you still need to have either a third party library (Prototype, MooTools) or [JSON2](https://github.com/douglascrockford/JSON-js/blob/master/json2.js) on the page to support older IE versions. jStorage supports storing Strings, Numbers, JavaScript objects, Arrays and even native XML nodes which kind of makes it a JSON storage. jStorage also supports setting TTL values for auto expiring stored keys and - best of all - notifying other tabs/windows when a key has been changed, which makes jStorage also a local PubSub platform for web applications. jStorage is pretty small, about 10kB when minified, 4kB gzipped. If jStorage is loaded on the page localStorage and sessionStorage polyfills are added to IE6 and IE7 in addition to regular $.jStorage methods. You can use regular setItem/getItem methods with the polyfills but getter/setters can be used as well: localStorage.mykey = myval; is absolutely valid with jStorage. The only downside is that you can't use *onstorage* event, you need to fall back to *listenKeyChange* instead. ## Donate Support jStorage development [![Donate to author](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DB26KWR2BQX5W) ## Features jStorage supports the following features: * store and retrieve data from browser storage using any JSON compatible data format (+ native XML nodes) * set TTL values to stored keys for auto expiring * publish and subscribe to cross-window/tab events * listen for key changes (update, delete) from the current or any other browser window * use any browser since IE6, both in desktop and in mobile ## Browser support Current availability: jStorage supports all major browsers - Internet Explorer 6+, Firefox 2+, Safari 4+, Chrome 4+, Opera 10.50+ If the browser doesn't support data caching, then no exceptions are raised - jStorage can still be used by the script but nothing is actually stored. ## Tests See [tests/testrunner.html](http://www.jstorage.info/static/tests/testrunner.html) for unit tests **NB!** - listenKeyChange and publish/subscribe tests tend to fail sometimes in Internet Explorer, which should be ok. ## Docs Project homepage and docs: [www.jstorage.info](http://www.jstorage.info) ## License **MIT**libjs-jstorage-0.3.1/component.json0000664000000000000000000000024212064636655016042 0ustar rootroot{ "name": "jStorage", "version": "0.3.0", "main": "./jstorage.js", "author": "Andris Reinman ", "dependencies": {} }libjs-jstorage-0.3.1/tests/0000775000000000000000000000000012064636655014311 5ustar rootrootlibjs-jstorage-0.3.1/tests/test6_run.html0000664000000000000000000000101312064636655017123 0ustar rootroot libjs-jstorage-0.3.1/tests/test8_setup.html0000664000000000000000000000047312064636655017472 0ustar rootroot libjs-jstorage-0.3.1/tests/test2_run.html0000664000000000000000000000045112064636655017124 0ustar rootroot libjs-jstorage-0.3.1/tests/test13_run.html0000664000000000000000000000165112064636655017211 0ustar rootroot libjs-jstorage-0.3.1/tests/test2_setup.html0000664000000000000000000000046212064636655017462 0ustar rootroot libjs-jstorage-0.3.1/tests/test7_run.html0000664000000000000000000000044712064636655017136 0ustar rootroot libjs-jstorage-0.3.1/tests/test20_frame2.html0000664000000000000000000000114012064636655017550 0ustar rootroot libjs-jstorage-0.3.1/tests/test9_run.html0000664000000000000000000000070312064636655017133 0ustar rootroot libjs-jstorage-0.3.1/tests/test12_setup.html0000664000000000000000000000066112064636655017544 0ustar rootroot libjs-jstorage-0.3.1/tests/test20_run.html0000664000000000000000000000150312064636655017203 0ustar rootroot libjs-jstorage-0.3.1/tests/test3_setup.html0000664000000000000000000000045012064636655017460 0ustar rootroot libjs-jstorage-0.3.1/tests/test12_run.html0000664000000000000000000000107012064636655017203 0ustar rootroot libjs-jstorage-0.3.1/tests/test16_run.html0000664000000000000000000000117112064636655017211 0ustar rootroot libjs-jstorage-0.3.1/tests/test19_frame2.html0000664000000000000000000000121612064636655017564 0ustar rootroot libjs-jstorage-0.3.1/tests/test6_setup.html0000664000000000000000000000062612064636655017470 0ustar rootroot libjs-jstorage-0.3.1/tests/test19_run.html0000664000000000000000000000150012064636655017210 0ustar rootroot libjs-jstorage-0.3.1/tests/ajax-loader.gif0000664000000000000000000000347112064636655017174 0ustar rootrootGIF89a}}9Z@}}Qk(s0{bI!Created with ajaxload.info! ! NETSCAPE2.0,w  !DBAH¬aD@ ^AXP@"UQ# B\; 1 o:2$v@ $|,3 _# d53" s5 e!! ,v i@e9DAA/`ph$Ca%@ pHxFuSx# .݄YfL_" p 3BW ]|L \6{|z87[7!! ,x  e9DE"2r,qPj`8@8bH, *0- mFW9LPE3+ (B"  f{*BW_/ @_$~Kr7Ar7!! ,v 4e9!H"* Q/@-4ép4R+-pȧ`P(6᠝U/  *,)(+/]"lO/*Ak K]A~666!! ,l ie9"* -80H=N; TEqe UoK2_WZ݌V1jgWe@tuH//w`?f~#6#!! ,~ ,e9"* ; pR%#0` 'c(J@@/1i4`VBV u}"caNi/ ] ))-Lel  mi} me[+!! ,y Ie9"M6*¨"7E͖@G((L&pqj@Z %@wZ) pl( ԭqu*R&c `))( s_J>_\'Gm7$+!! ,w Ie9*, (*(B5[1 ZIah!GexzJ0e6@V|U4Dm%$͛p \Gx }@+| =+ 1- Ea5l)+!! ,y )䨞'AKڍ,E\(l&;5 5D03a0--ÃpH4V % i p[R"| #  6iZwcw*!! ,y )䨞,K*0 a;׋аY8b`4n ¨Bbbx,( Ƚ  % >  2*i* /:+$v*!! ,u )䨞l[$ Jq[q 3`Q[5:IX!0rAD8 CvHPfiiQAP@pC %D PQ46  iciNj0w )#!! ,y ). q ,G Jr(J8 C*B,&< h W~-`, ,>; 8RN<, <1T] c' qk$ @)#!;libjs-jstorage-0.3.1/tests/test18_setup.html0000664000000000000000000000053412064636655017551 0ustar rootroot libjs-jstorage-0.3.1/tests/test8_run.html0000664000000000000000000000046212064636655017134 0ustar rootroot libjs-jstorage-0.3.1/tests/test4_setup.html0000664000000000000000000000067712064636655017474 0ustar rootroot libjs-jstorage-0.3.1/tests/test19_frame1.html0000664000000000000000000000060512064636655017564 0ustar rootroot libjs-jstorage-0.3.1/tests/test7_setup.html0000664000000000000000000000046112064636655017466 0ustar rootroot libjs-jstorage-0.3.1/tests/test20_setup.html0000664000000000000000000000040012064636655017532 0ustar rootroot libjs-jstorage-0.3.1/tests/test5_run.html0000664000000000000000000000175112064636655017133 0ustar rootroot libjs-jstorage-0.3.1/tests/test10_run.html0000664000000000000000000000162712064636655017211 0ustar rootroot libjs-jstorage-0.3.1/tests/test1_setup.html0000664000000000000000000000045012064636655017456 0ustar rootroot libjs-jstorage-0.3.1/tests/test14_setup.html0000664000000000000000000000133112064636655017541 0ustar rootroot libjs-jstorage-0.3.1/tests/test3_run.html0000664000000000000000000000065012064636655017126 0ustar rootroot libjs-jstorage-0.3.1/tests/test5_setup.html0000664000000000000000000000062612064636655017467 0ustar rootroot libjs-jstorage-0.3.1/tests/test20_frame1.html0000664000000000000000000000061712064636655017557 0ustar rootroot libjs-jstorage-0.3.1/tests/test18_run.html0000664000000000000000000000164512064636655017221 0ustar rootroot libjs-jstorage-0.3.1/tests/test17_setup.html0000664000000000000000000000053412064636655017550 0ustar rootroot libjs-jstorage-0.3.1/tests/test15_run.html0000664000000000000000000000117112064636655017210 0ustar rootroot libjs-jstorage-0.3.1/tests/test4_run.html0000664000000000000000000000150612064636655017130 0ustar rootroot libjs-jstorage-0.3.1/tests/data.xml0000664000000000000000000000035512064636655015747 0ustar rootroot Pealkiri Lingi nimi Kirjeldus et libjs-jstorage-0.3.1/tests/test15_setup.html0000664000000000000000000000047112064636655017546 0ustar rootroot libjs-jstorage-0.3.1/tests/test16_setup.html0000664000000000000000000000052712064636655017551 0ustar rootroot libjs-jstorage-0.3.1/tests/test9_setup.html0000664000000000000000000000046112064636655017470 0ustar rootroot libjs-jstorage-0.3.1/tests/test17_run.html0000664000000000000000000000141212064636655017210 0ustar rootroot libjs-jstorage-0.3.1/tests/test10_setup.html0000664000000000000000000000074312064636655017543 0ustar rootroot libjs-jstorage-0.3.1/tests/test14_run.html0000664000000000000000000000110712064636655017206 0ustar rootroot libjs-jstorage-0.3.1/tests/test19_setup.html0000664000000000000000000000040012064636655017542 0ustar rootroot libjs-jstorage-0.3.1/tests/test11_run.html0000664000000000000000000000202612064636655017204 0ustar rootroot libjs-jstorage-0.3.1/tests/test13_setup.html0000664000000000000000000000070712064636655017546 0ustar rootroot libjs-jstorage-0.3.1/tests/test11_setup.html0000664000000000000000000000066112064636655017543 0ustar rootroot libjs-jstorage-0.3.1/tests/test1_run.html0000664000000000000000000000043612064636655017126 0ustar rootroot libjs-jstorage-0.3.1/tests/testrunner.html0000664000000000000000000001255612064636655017421 0ustar rootroot

jStorage tests