2 * ----------------------------- JSTORAGE -------------------------------------
3 * Simple local storage wrapper to save data on the browser side, supporting
4 * all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+
6 * Copyright (c) 2010 Andris Reinman, andris.reinman@gmail.com
7 * Project homepage: www.jstorage.info
9 * Licensed under MIT-style license:
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * jStorage requires Prototype, MooTools or jQuery! If jQuery is used, then
33 * jQuery-JSON (http://code.google.com/p/jquery-json/) is also needed.
34 * (jQuery-JSON needs to be loaded BEFORE jStorage!)
39 * $.jStorage.set(key, value) -> saves a value
41 * -get(key[, default])
42 * value = $.jStorage.get(key [, default]) ->
43 * retrieves value if key exists, or default if it doesn't
46 * $.jStorage.deleteKey(key) -> removes a key from the storage
49 * $.jStorage.flush() -> clears the cache
52 * $.jStorage.storageObj() -> returns a read-ony copy of the actual storage
55 * $.jStorage.storageSize() -> returns the size of the storage in bytes
58 * $.jStorage.index() -> returns the used keys as an array
61 * $.jStorage.storageAvailable() -> returns true if storage is available
64 * $.jStorage.reInit() -> reloads the data from browser storage
66 * <value> can be any JSON-able value, including objects and arrays.
71 if(!$ || !($.toJSON || Object.toJSON || window.JSON)){
72 throw new Error("jQuery, MooTools or Prototype needs to be loaded before jStorage!");
76 /* This is the object, that holds the cached values */
79 /* Actual browser storage (localStorage or globalStorage['domain']) */
80 _storage_service = {jStorage:"{}"},
82 /* DOM element for older IE versions, holds userData behavior */
85 /* How much space does the storage take */
88 /* function to encode objects to JSON strings */
89 json_encode = $.toJSON || Object.toJSON || (window.JSON && (JSON.encode || JSON.stringify)),
91 /* function to decode objects from JSON strings */
92 json_decode = $.evalJSON || (window.JSON && (JSON.decode || JSON.parse)) || function(str){
93 return String(str).evalJSON();
96 /* which backend is currently used */
100 * XML encoding and decoding as XML nodes can't be JSON'ized
101 * XML nodes are encoded and decoded if the node is the value to be saved
102 * but not if it's as a property of another object
104 * $.jStorage.set("key", xmlNode); // IS OK
105 * $.jStorage.set("key", {xml: xmlNode}); // NOT OK
110 * Validates a XML node to be XML
111 * based on jQuery.isXML function
113 isXML: function(elm){
114 var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;
115 return documentElement ? documentElement.nodeName !== "HTML" : false;
119 * Encodes a XML node to string
120 * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/
122 encode: function(xmlNode) {
123 if(!this.isXML(xmlNode)){
126 try{ // Mozilla, Webkit, Opera
127 return new XMLSerializer().serializeToString(xmlNode);
137 * Decodes a XML node from string
138 * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/
140 decode: function(xmlString){
141 var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) ||
142 (window.ActiveXObject && function(_xmlString) {
143 var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
144 xml_doc.async = 'false';
145 xml_doc.loadXML(_xmlString);
152 resultXML = dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml');
153 return this.isXML(resultXML)?resultXML:false;
157 ////////////////////////// PRIVATE METHODS ////////////////////////
160 * Initialization function. Detects if the browser supports DOM Storage
161 * or userData behavior and behaves accordingly.
165 /* Check if browser supports localStorage */
166 if("localStorage" in window){
168 if(window.localStorage) {
169 _storage_service = window.localStorage;
170 _backend = "localStorage";
172 } catch(E3) {/* Firefox fails when touching localStorage and cookies are disabled */}
174 /* Check if browser supports globalStorage */
175 else if("globalStorage" in window){
177 if(window.globalStorage) {
178 _storage_service = window.globalStorage[window.location.hostname];
179 _backend = "globalStorage";
181 } catch(E4) {/* Firefox fails when touching localStorage and cookies are disabled */}
183 /* Check if browser supports userData behavior */
185 _storage_elm = document.createElement('link');
186 if(_storage_elm.addBehavior){
188 /* Use a DOM element to act as userData storage */
189 _storage_elm.style.behavior = 'url(#default#userData)';
191 /* userData element needs to be inserted into the DOM! */
192 document.getElementsByTagName('head')[0].appendChild(_storage_elm);
194 _storage_elm.load("jStorage");
197 data = _storage_elm.getAttribute("jStorage");
199 _storage_service.jStorage = data;
200 _backend = "userDataBehavior";
211 * Loads the data from the storage based on the supported mechanism
214 function _load_storage(){
215 /* if jStorage string is retrieved, then decode it */
216 if(_storage_service.jStorage){
218 _storage = json_decode(String(_storage_service.jStorage));
219 }catch(E6){_storage_service.jStorage = "{}";}
221 _storage_service.jStorage = "{}";
223 _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
227 * This functions provides the "save" mechanism to store the jStorage object
232 _storage_service.jStorage = json_encode(_storage);
233 // If userData is used as the storage engine, additional
235 _storage_elm.setAttribute("jStorage",_storage_service.jStorage);
236 _storage_elm.save("jStorage");
238 _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
239 }catch(E7){/* probably cache is full, nothing is saved this way*/}
243 * Function checks if a key is set and is string or numberic
245 function _checkKey(key){
246 if(!key || (typeof key != "string" && typeof key != "number")){
247 throw new TypeError('Key name must be string or numeric');
252 ////////////////////////// PUBLIC INTERFACE /////////////////////////
259 * Sets a key's value.
261 * @param {String} key - Key to set. If this value is not set or not
262 * a string an exception is raised.
263 * @param value - Value to set. This can be any value that is JSON
264 * compatible (Numbers, Strings, Objects etc.).
265 * @returns the used value
267 set: function(key, value){
269 if(_XMLService.isXML(value)){
270 value = {_is_xml:true,xml:_XMLService.encode(value)};
272 _storage[key] = value;
278 * Looks up a key in cache
280 * @param {String} key - Key to look up.
281 * @param {mixed} def - Default value to return, if key didn't exist.
282 * @returns the key value, default value or <null>
284 get: function(key, def){
287 if(typeof _storage[key] == "object" &&
288 _storage[key]._is_xml &&
289 _storage[key]._is_xml){
290 return _XMLService.decode(_storage[key].xml);
292 return _storage[key];
295 return typeof(def) == 'undefined' ? null : def;
299 * Deletes a key from cache.
301 * @param {String} key - Key to delete.
302 * @returns true if key existed or false if it didn't
304 deleteKey: function(key){
307 delete _storage[key];
315 * Deletes everything in cache.
323 * Just to be sure - andris9/jStorage#3
326 window.localStorage.clear();
332 * Returns a read-only copy of _storage
336 storageObj: function(){
338 F.prototype = _storage;
343 * Returns an index of all used keys as an array
344 * ['key1', 'key2',..'keyN']
351 if(_storage.hasOwnProperty(i)){
359 * How much space in bytes does the storage take?
363 storageSize: function(){
364 return _storage_size;
368 * Which backend is currently in use?
372 currentBackend: function(){
377 * Test if storage is available
381 storageAvailable: function(){
386 * Reloads the data from browser storage
391 var new_storage_elm, data;
392 if(_storage_elm && _storage_elm.addBehavior){
393 new_storage_elm = document.createElement('link');
395 _storage_elm.parentNode.replaceChild(new_storage_elm, _storage_elm);
396 _storage_elm = new_storage_elm;
398 /* Use a DOM element to act as userData storage */
399 _storage_elm.style.behavior = 'url(#default#userData)';
401 /* userData element needs to be inserted into the DOM! */
402 document.getElementsByTagName('head')[0].appendChild(_storage_elm);
404 _storage_elm.load("jStorage");
407 data = _storage_elm.getAttribute("jStorage");
409 _storage_service.jStorage = data;
410 _backend = "userDataBehavior";
417 // Initialize jStorage
420 })(window.jQuery || window.$);