/static/scripts/jstorage.js
https://bitbucket.org/cistrome/cistrome-harvard/ · JavaScript · 420 lines · 195 code · 41 blank · 184 comment · 44 complexity · 1ed3525ccbd6baad44ed74b13096a156 MD5 · raw file
- /*
- * ----------------------------- 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.$);