--- /dev/null
+/*
+ * ----------------------------- 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 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.
+ */
+
+/**
+ * $.jStorage
+ *
+ * USAGE:
+ *
+ * jStorage requires Prototype, MooTools or jQuery! If jQuery is used, then
+ * jQuery-JSON (http://code.google.com/p/jquery-json/) is also needed.
+ * (jQuery-JSON needs to be loaded BEFORE jStorage!)
+ *
+ * Methods:
+ *
+ * -set(key, value)
+ * $.jStorage.set(key, value) -> saves a value
+ *
+ * -get(key[, default])
+ * value = $.jStorage.get(key [, default]) ->
+ * retrieves value if key exists, or default if it doesn't
+ *
+ * -deleteKey(key)
+ * $.jStorage.deleteKey(key) -> removes a key from the storage
+ *
+ * -flush()
+ * $.jStorage.flush() -> clears the cache
+ *
+ * -storageObj()
+ * $.jStorage.storageObj() -> returns a read-ony copy of the actual storage
+ *
+ * -storageSize()
+ * $.jStorage.storageSize() -> returns the size of the storage in bytes
+ *
+ * -index()
+ * $.jStorage.index() -> returns the used keys as an array
+ *
+ * -storageAvailable()
+ * $.jStorage.storageAvailable() -> returns true if storage is available
+ *
+ * -reInit()
+ * $.jStorage.reInit() -> reloads the data from browser storage
+ *
+ * <value> can be any JSON-able value, including objects and arrays.
+ *
+ **/
+
+(function($){
+ if(!$ || !($.toJSON || Object.toJSON || window.JSON)){
+ throw new Error("jQuery, MooTools or Prototype needs to be loaded before jStorage!");
+ }
+
+ 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,
+
+ /* function to encode objects to JSON strings */
+ json_encode = $.toJSON || Object.toJSON || (window.JSON && (JSON.encode || JSON.stringify)),
+
+ /* function to decode objects from JSON strings */
+ json_decode = $.evalJSON || (window.JSON && (JSON.decode || JSON.parse)) || function(str){
+ return String(str).evalJSON();
+ },
+
+ /* which backend is currently used */
+ _backend = false;
+
+ /**
+ * 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;
+ }
+ };
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ /**
+ * Initialization function. Detects if the browser supports DOM Storage
+ * or userData behavior and behaves accordingly.
+ * @returns undefined
+ */
+ function _init(){
+ /* Check if browser supports localStorage */
+ if("localStorage" in window){
+ try {
+ if(window.localStorage) {
+ _storage_service = window.localStorage;
+ _backend = "localStorage";
+ }
+ } 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";
+ }
+ } 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);
+
+ _storage_elm.load("jStorage");
+ var data = "{}";
+ try{
+ data = _storage_elm.getAttribute("jStorage");
+ }catch(E5){}
+ _storage_service.jStorage = data;
+ _backend = "userDataBehavior";
+ }else{
+ _storage_elm = null;
+ return;
+ }
+ }
+
+ _load_storage();
+ }
+
+ /**
+ * Loads the data from the storage based on the supported mechanism
+ * @returns undefined
+ */
+ function _load_storage(){
+ /* if jStorage string is retrieved, then decode it */
+ if(_storage_service.jStorage){
+ try{
+ _storage = json_decode(String(_storage_service.jStorage));
+ }catch(E6){_storage_service.jStorage = "{}";}
+ }else{
+ _storage_service.jStorage = "{}";
+ }
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
+ }
+
+ /**
+ * This functions provides the "save" mechanism to store the jStorage object
+ * @returns undefined
+ */
+ function _save(){
+ try{
+ _storage_service.jStorage = json_encode(_storage);
+ // If userData is used as the storage engine, additional
+ if(_storage_elm) {
+ _storage_elm.setAttribute("jStorage",_storage_service.jStorage);
+ _storage_elm.save("jStorage");
+ }
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
+ }catch(E7){/* probably cache is full, nothing is saved this way*/}
+ }
+
+ /**
+ * Function checks if a key is set and is string or numberic
+ */
+ function _checkKey(key){
+ if(!key || (typeof key != "string" && typeof key != "number")){
+ throw new TypeError('Key name must be string or numeric');
+ }
+ return true;
+ }
+
+ ////////////////////////// PUBLIC INTERFACE /////////////////////////
+
+ $.jStorage = {
+ /* Version number */
+ version: "0.1.5.0",
+
+ /**
+ * 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 value - Value to set. This can be any value that is JSON
+ * compatible (Numbers, Strings, Objects etc.).
+ * @returns the used value
+ */
+ set: function(key, value){
+ _checkKey(key);
+ if(_XMLService.isXML(value)){
+ value = {_is_xml:true,xml:_XMLService.encode(value)};
+ }
+ _storage[key] = value;
+ _save();
+ 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.
+ * @returns the key value, default value or <null>
+ */
+ get: function(key, def){
+ _checkKey(key);
+ if(key in _storage){
+ if(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.
+ * @returns true if key existed or false if it didn't
+ */
+ deleteKey: function(key){
+ _checkKey(key);
+ if(key in _storage){
+ delete _storage[key];
+ _save();
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Deletes everything in cache.
+ *
+ * @returns true
+ */
+ flush: function(){
+ _storage = {};
+ _save();
+ /*
+ * Just to be sure - andris9/jStorage#3
+ */
+ try{
+ window.localStorage.clear();
+ }catch(E8){}
+ return true;
+ },
+
+ /**
+ * Returns a read-only copy of _storage
+ *
+ * @returns Object
+ */
+ storageObj: function(){
+ function F() {}
+ F.prototype = _storage;
+ return new F();
+ },
+
+ /**
+ * Returns an index of all used keys as an array
+ * ['key1', 'key2',..'keyN']
+ *
+ * @returns Array
+ */
+ index: function(){
+ var index = [], i;
+ for(i in _storage){
+ if(_storage.hasOwnProperty(i)){
+ index.push(i);
+ }
+ }
+ return index;
+ },
+
+ /**
+ * How much space in bytes does the storage take?
+ *
+ * @returns Number
+ */
+ storageSize: function(){
+ return _storage_size;
+ },
+
+ /**
+ * Which backend is currently in use?
+ *
+ * @returns String
+ */
+ currentBackend: function(){
+ return _backend;
+ },
+
+ /**
+ * Test if storage is available
+ *
+ * @returns Boolean
+ */
+ storageAvailable: function(){
+ return !!_backend;
+ },
+
+ /**
+ * Reloads the data from browser storage
+ *
+ * @returns undefined
+ */
+ reInit: function(){
+ var new_storage_elm, data;
+ if(_storage_elm && _storage_elm.addBehavior){
+ new_storage_elm = document.createElement('link');
+
+ _storage_elm.parentNode.replaceChild(new_storage_elm, _storage_elm);
+ _storage_elm = new_storage_elm;
+
+ /* 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);
+
+ _storage_elm.load("jStorage");
+ data = "{}";
+ try{
+ data = _storage_elm.getAttribute("jStorage");
+ }catch(E5){}
+ _storage_service.jStorage = data;
+ _backend = "userDataBehavior";
+ }
+
+ _load_storage();
+ }
+ };
+
+ // Initialize jStorage
+ _init();
+
+})(window.jQuery || window.$);
\ No newline at end of file