├── LICENSE ├── README.rst ├── build-config.json ├── builds ├── storage-full-behavior.js ├── storage-full-behavior.uncompressed.js ├── storage-full-cookie.js ├── storage-full-cookie.uncompressed.js ├── storage-full-gears.js ├── storage-full-gears.uncompressed.js ├── storage-full-localStorage.js ├── storage-full-localStorage.uncompressed.js ├── storage-full-widget.js ├── storage-full-widget.uncompressed.js ├── storage-minimal-behavior.js ├── storage-minimal-behavior.uncompressed.js ├── storage-minimal-cookie.js ├── storage-minimal-cookie.uncompressed.js ├── storage-minimal-gears.js ├── storage-minimal-gears.uncompressed.js ├── storage-minimal-localStorage.js ├── storage-minimal-localStorage.uncompressed.js ├── storage-minimal-widget.js └── storage-minimal-widget.uncompressed.js ├── features ├── checkedSet │ ├── README │ ├── checkedSet.js │ └── dependencies.json ├── clear │ ├── README │ ├── behavior.js │ ├── cookie.js │ ├── dependencies.json │ ├── gears.js │ ├── localStorage.js │ └── widget.js ├── engine │ ├── README │ ├── behavior.js │ ├── cookie.js │ ├── dependencies.json │ ├── gears.js │ ├── localStorage.js │ └── widget.js ├── getAll │ ├── README │ ├── behavior.js │ ├── cookie.js │ ├── dependencies.json │ ├── gears.js │ ├── keymapped.js │ └── localStorage.js ├── getAllKeys │ ├── README │ ├── behavior.js │ ├── cookie.js │ ├── dependencies.json │ ├── gears.js │ ├── keymapped.js │ └── localStorage.js ├── keyMap │ ├── README │ ├── dependencies.json │ ├── generic.js │ └── widget.js ├── object │ ├── dependencies.json │ └── object.js └── wrappedWrites │ ├── README │ ├── dependencies.json │ └── wrappedWrites.js ├── platforms ├── behavior.json ├── cookie.json ├── gears.json ├── localStorage.json └── widget.json └── tests ├── test_behavior.html ├── test_cookie.html ├── test_gears.html ├── test_localStorage.html ├── test_widget.html ├── tests.js └── widget ├── SJS.wgt ├── config.xml ├── index.html ├── storage-full-widget.js └── tests.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010 Jens Arps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | StorageJS 2 | ========= 3 | 4 | Intro 5 | ----- 6 | 7 | StorageJS is a micro wrapper for client side persistent storage. It is explicitly aimed at mobile devices (but can be used for desktop apps, too, of course). 8 | 9 | StorageJS uses the EmbedJS approach. That means: 10 | 11 | a) It is divided into features, and for these features exist different implementations (based on the targeted storage engine). 12 | 13 | b) You have different output builds for the different storage backends. There is branching on run time. 14 | 15 | That way, you have the smallest possible footprint for your project, and deliver only the code that you really need for your project. 16 | 17 | 18 | Supported Storage Engines 19 | ------------------------- 20 | 21 | StorageJS supports localStorage, Widget preference store, Gears, userData behavior and Cookies. Due to the fact that StorageJS provides sync read access to storage, there's no support for Sqlite impls. 22 | 23 | 24 | Features 25 | -------- 26 | 27 | The base feature, "engine", exposes the follwing methods: 28 | 29 | var value = storage.get(key); 30 | 31 | storage.set(key, value); 32 | 33 | storage.remove(key); 34 | 35 | Both key and value MUST be strings. 36 | 37 | The other features add more methods, such as clear(), getAll() or getAllKeys(), or modify given methods. Please refer to the README in each feature's directory to learn more about what it does. 38 | 39 | 40 | Building 41 | -------- 42 | 43 | To create a build specific to your project, you can cherry-pick whatever features you need and create a profile. However, some default profiles that cover the most use cases are already pre-defined. Inside of the "builds" directory are ready made builds you can use out of the box. 44 | 45 | To build your custom profile, you need the EmbedJS build tool. You can get it from github. Next, you need to modify the build-config.json file. It's well commented, so don't hesitate! Finally, run the build.sh shell script to create your builds. 46 | 47 | :: 48 | 49 | # Clone the repos 50 | > git clone git@github.com:jensarps/StorageJS.git 51 | > git clone git@github.com:uxebu/embedjs-tools.git 52 | 53 | # trigger the actual build using the embedjs-tools bash script 54 | > cd StorageJS 55 | > ../embedjs-tools/build.sh profile=YourCustomProfile 56 | 57 | 58 | 59 | Size matters 60 | ------------ 61 | 62 | The minimal profile, containing the base feature "engine" (providing the get/set/remove methods), results in builds of the following size (not gzipped): 63 | 64 | :: 65 | 66 | storage-minimal-behavior.js 622b 67 | storage-minimal-cookie.js 1351b 68 | storage-minimal-gears.js 1474b 69 | storage-minimal-localStorage.js 187b 70 | storage-minimal-widget.js 306b 71 | 72 | 73 | The full profile, including the features getAllKeys, getAll and clear (providing the methods getAllKeys(), getAll() and clear()), results in builds of the following size (not gzipped): 74 | 75 | :: 76 | 77 | storage-full-behavior.js 1157b 78 | storage-full-cookie.js 1626b 79 | storage-full-gears.js 1996b 80 | storage-full-localStorage.js 509b 81 | storage-full-widget.js 1677b 82 | 83 | 84 | 85 | Documentation 86 | ------------- 87 | 88 | Please see each feature's own Readme file, located in their respective directories. 89 | -------------------------------------------------------------------------------- /build-config.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | isVerbose: true, 4 | 5 | // All paths are relative to this file!!! 6 | // Trailing and leading slashes are not needed! 7 | paths: { 8 | // The path where to find the platform JSON files. 9 | // Those files define the features and which files belong to each of them. 10 | platforms: "platforms", 11 | 12 | // Where the features (the source code) can be found. 13 | source: "features", 14 | 15 | // Where the built files should be put. 16 | build: "builds" 17 | }, 18 | 19 | build: { 20 | // How to create the final file name for the built file. 21 | // You can use "PROFILE" and "PLATFORM" as variables, like so: 22 | // buildFileName:"embed-${PROFILE}-${PLATFORM}" 23 | // The ${} surrounds the varibales. 24 | // The final files may look like so: 25 | // storage-minimal-localStorage.js 26 | // You can see the ".js" gets appended automatically. 27 | fileName: "storage-${PROFILE}-${PLATFORM}", 28 | 29 | // If you also want to generate the uncompressed file set the 30 | // following option to true. 31 | // This will result in a file like: 32 | // storage-minimal-localStorage.uncompressed.js 33 | generateUncompressedFiles: false, 34 | }, 35 | 36 | defaults: { 37 | // If no profile is given explicitly as a parameter in the build process 38 | // the following is used as the default parameter. 39 | profile: "full", 40 | 41 | // The default if no platform is given during the build process. 42 | platform: "localStorage", 43 | }, 44 | 45 | // Each profile defines a set of features which will be build 46 | // in the order of lsiting. To learn more about a given feature, 47 | // refer to the README file in the specific fetaure folder. 48 | // 49 | // You can setup your own profile here. All profiles need to contain the 50 | // feature "engine" to work, and can in addition contain one or more of 51 | // the following features: 52 | // "clear" 53 | // "getAll" 54 | // "getAllKeys" 55 | // "checkedSet" 56 | // "wrappedWrites" 57 | // "object" 58 | profiles: { 59 | 60 | // Basic key/value, String only. 61 | 62 | "minimal":[ 63 | "engine" 64 | ], 65 | 66 | "minimal+clear":[ 67 | "engine", "clear" 68 | ], 69 | 70 | "full": [ 71 | "engine", "clear", "getAll", "getAllKeys" 72 | ], 73 | 74 | "full-checked": [ 75 | "engine", "clear", "getAll", "getAllKeys", "checkedSet" 76 | ], 77 | 78 | "full-wrapped": [ 79 | "engine", "clear", "getAll", "getAllKeys", "wrappedWrites" 80 | ], 81 | 82 | // Object store 83 | 84 | "object": [ 85 | "engine", "clear", "getAll", "getAllKeys", "object" 86 | ], 87 | 88 | "object-checked": [ 89 | "engine", "clear", "getAll", "getAllKeys", "object", "checkedSet" 90 | ], 91 | 92 | "object-wrapped": [ 93 | "engine", "clear", "getAll", "getAllKeys", "object", "wrappedWrites" 94 | ], 95 | 96 | // Come get some 97 | 98 | "dnstuff": [ 99 | "engine", "clear", "getAll", "getAllKeys", "object", "checkedSet", "wrappedWrites" 100 | ] 101 | } 102 | } -------------------------------------------------------------------------------- /builds/storage-full-behavior.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"behavior",store:null,storeName:"__StorageJS_BehaviorStorage",init:function(){this.store=this._createStore();this.store.load(this.storeName);},_createStore:function(){var _1=document.createElement("link");_1.id=this.storeName+"Node";_1.style.display="none";document.getElementsByTagName("head")[0].appendChild(_1);_1.addBehavior("#default#userdata");return _1;},get:function(_2){return this.store.getAttribute(_2);},set:function(_3,_4){this.store.setAttribute(_3,_4);this.store.save(this.storeName);},remove:function(_5){this.store.removeAttribute(_5);this.store.save(this.storeName);}};storage.init();storage.clear=function(){var _6=this.store.XMLDocument.documentElement.attributes;for(var i=0,m=_6.length;i0){_2=rs.field(0);}rs.close();return _2;},set:function(_3,_4){if(this.get(_3)===null){this.db.execute("INSERT INTO "+this.tableName+" values (?, ?)",[_3,_4]);}else{this.db.execute("UPDATE "+this.tableName+" SET value = ? WHERE key = ?",[_4,_3]);}},remove:function(_5){this.db.execute("DELETE FROM "+this.tableName+" WHERE key = ?",[_5]);},initGears:function(){if(window.google&&google.gears){return;}var _6=null;if(typeof GearsFactory!="undefined"){_6=new GearsFactory();}else{try{_6=new ActiveXObject("Gears.Factory");if(_6.getBuildInfo().indexOf("ie_mobile")!=-1){_6.privateSetGlobalObject(this);}}catch(e){if((typeof navigator.mimeTypes!="undefined")&&navigator.mimeTypes["application/x-googlegears"]){_6=document.createElement("object");_6.style.display="none";_6.width=0;_6.height=0;_6.type="application/x-googlegears";document.documentElement.appendChild(_6);if(_6&&(typeof _6.create=="undefined")){_6=null;}}}}if(!_6){return;}if(!window.google){google={};}if(!google.gears){google.gears={factory:_6};}}};storage.init();storage.clear=function(){this.db.execute("DELETE FROM "+this.tableName);};storage.getAll=function(){var _7=[];var rs=this.db.execute("SELECT * FROM "+this.tableName);var _8=0;while(rs.isValidRow()&&rs.fieldCount()>1){_7.push({key:rs.fieldByName("key"),value:rs.fieldByName("value")});rs.next();}rs.close();return _7;};storage.getAllKeys=function(){var _9=[];var rs=this.db.execute("SELECT key FROM "+this.tableName);var _a=0;while(rs.isValidRow()&&rs.fieldCount()>0){_9.push(rs.field(0));rs.next();}rs.close();return _9;}; -------------------------------------------------------------------------------- /builds/storage-full-gears.uncompressed.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /*********FILE********** 5 | /features/engine/gears.js 6 | ********************/ 7 | 8 | 9 | // The initGears method is Copyright 2007, Google Inc. 10 | 11 | 12 | var storage = { 13 | 14 | engine: "gears", 15 | 16 | dbName: 'SJSDatabase', 17 | 18 | tableName: 'SJSStorageTable', 19 | 20 | db: null, 21 | 22 | init: function(){ 23 | this.initGears(); 24 | this.db = google.gears.factory.create('beta.database'); 25 | this.db.open(this.dbName); 26 | this.db.execute('CREATE TABLE IF NOT EXISTS ' + this.tableName + ' ( key TEXT PRIMARY KEY, value TEXT )'); 27 | }, 28 | 29 | get: function(key){ 30 | var rs = this.db.execute('SELECT value FROM ' + this.tableName + ' WHERE key = ?', [key]); 31 | var value = null; 32 | if(rs.isValidRow() && rs.fieldCount() > 0) { 33 | value = rs.field(0); 34 | } 35 | rs.close(); 36 | return value; 37 | }, 38 | 39 | set: function(key, value){ 40 | if(this.get(key) === null){ // no such key present, insert 41 | this.db.execute('INSERT INTO ' + this.tableName + ' values (?, ?)', [key, value]); 42 | }else{ // update 43 | this.db.execute('UPDATE ' + this.tableName + ' SET value = ? WHERE key = ?', [value, key]); 44 | } 45 | }, 46 | 47 | remove: function(key){ 48 | this.db.execute('DELETE FROM ' + this.tableName + ' WHERE key = ?', [key]); 49 | }, 50 | 51 | initGears: function(){ 52 | if (window.google && google.gears) { 53 | return; 54 | } 55 | 56 | var factory = null; 57 | 58 | // Firefox 59 | if (typeof GearsFactory != 'undefined') { 60 | factory = new GearsFactory(); 61 | } else { 62 | // IE 63 | try { 64 | factory = new ActiveXObject('Gears.Factory'); 65 | // privateSetGlobalObject is only required and supported on IE Mobile on 66 | // WinCE. 67 | if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { 68 | factory.privateSetGlobalObject(this); 69 | } 70 | } catch (e) { 71 | // Safari 72 | if ((typeof navigator.mimeTypes != 'undefined') 73 | && navigator.mimeTypes["application/x-googlegears"]) { 74 | factory = document.createElement("object"); 75 | factory.style.display = "none"; 76 | factory.width = 0; 77 | factory.height = 0; 78 | factory.type = "application/x-googlegears"; 79 | document.documentElement.appendChild(factory); 80 | if(factory && (typeof factory.create == 'undefined')) { 81 | // If NP_Initialize() returns an error, factory will still be created. 82 | // We need to make sure this case doesn't cause Gears to appear to 83 | // have been initialized. 84 | factory = null; 85 | } 86 | } 87 | } 88 | } 89 | 90 | // *Do not* define any objects if Gears is not installed. This mimics the 91 | // behavior of Gears defining the objects in the future. 92 | if (!factory) { 93 | return; 94 | } 95 | 96 | // Now set up the objects, being careful not to overwrite anything. 97 | // 98 | // Note: In Internet Explorer for Windows Mobile, you can't add properties to 99 | // the window object. However, global objects are automatically added as 100 | // properties of the window object in all browsers. 101 | if (!window.google) { 102 | google = {}; 103 | } 104 | 105 | if (!google.gears) { 106 | google.gears = {factory: factory}; 107 | } 108 | 109 | } 110 | }; 111 | 112 | storage.init(); 113 | 114 | 115 | 116 | /*********FILE********** 117 | /features/clear/gears.js 118 | ********************/ 119 | 120 | 121 | storage.clear = function(){ 122 | this.db.execute('DELETE FROM ' + this.tableName); 123 | }; 124 | 125 | 126 | 127 | /*********FILE********** 128 | /features/getAll/gears.js 129 | ********************/ 130 | 131 | 132 | storage.getAll = function(){ 133 | var all = []; 134 | 135 | var rs = this.db.execute('SELECT * FROM ' + this.tableName); 136 | var index = 0; 137 | while (rs.isValidRow() && rs.fieldCount() > 1) { 138 | all.push({key: rs.fieldByName('key'), value: rs.fieldByName('value')}); 139 | rs.next(); 140 | } 141 | rs.close(); 142 | 143 | return all; 144 | }; 145 | 146 | 147 | 148 | /*********FILE********** 149 | /features/getAllKeys/gears.js 150 | ********************/ 151 | 152 | 153 | storage.getAllKeys = function(){ 154 | var keys = []; 155 | 156 | var rs = this.db.execute('SELECT key FROM ' + this.tableName); 157 | var index = 0; 158 | while (rs.isValidRow() && rs.fieldCount() > 0) { 159 | keys.push(rs.field(0)); 160 | rs.next(); 161 | } 162 | rs.close(); 163 | 164 | return keys; 165 | }; 166 | -------------------------------------------------------------------------------- /builds/storage-full-localStorage.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"localStorage",get:function(_1){return localStorage.getItem(_1);},set:function(_2,_3){localStorage.setItem(_2,_3);},remove:function(_4){localStorage.removeItem(_4);}};storage.clear=function(){localStorage.clear();};storage.getAll=function(){var _5=[],i=0,m=localStorage.length,_6;for(;i0?this.parseString(_e):[];this.keys=_f;};storage.loadKeyMap();storage.clear=function(){for(var i=0,m=this.keys.length;i 0 ? this.parseString(keyString) : []; 105 | this.keys = keys; 106 | }; 107 | 108 | storage.loadKeyMap(); 109 | 110 | 111 | 112 | /*********FILE********** 113 | /features/clear/widget.js 114 | ********************/ 115 | 116 | 117 | storage.clear = function(){ 118 | for(var i = 0, m = this.keys.length; i < m; i++){ 119 | widget.setPreferenceForKey(null, this.keys[i]); 120 | } 121 | this.keys = []; 122 | this.saveKeyMap(); 123 | }; 124 | 125 | 126 | 127 | /*********FILE********** 128 | /features/getAll/keymapped.js 129 | ********************/ 130 | 131 | 132 | storage.getAll = function(){ 133 | var all = []; 134 | for(var i = 0, m = this.keys.length; i < m; i++){ 135 | all.push({key: this.keys[i], value: this.get(this.keys[i])}); 136 | } 137 | return all; 138 | }; 139 | 140 | 141 | 142 | /*********FILE********** 143 | /features/getAllKeys/keymapped.js 144 | ********************/ 145 | 146 | 147 | storage.getAllKeys = function(){ 148 | return this.keys; 149 | }; 150 | -------------------------------------------------------------------------------- /builds/storage-minimal-behavior.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"behavior",store:null,storeName:"__StorageJS_BehaviorStorage",init:function(){this.store=this._createStore();this.store.load(this.storeName);},_createStore:function(){var _1=document.createElement("link");_1.id=this.storeName+"Node";_1.style.display="none";document.getElementsByTagName("head")[0].appendChild(_1);_1.addBehavior("#default#userdata");return _1;},get:function(_2){return this.store.getAttribute(_2);},set:function(_3,_4){this.store.setAttribute(_3,_4);this.store.save(this.storeName);},remove:function(_5){this.store.removeAttribute(_5);this.store.save(this.storeName);}};storage.init(); -------------------------------------------------------------------------------- /builds/storage-minimal-behavior.uncompressed.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /*********FILE********** 5 | /features/engine/behavior.js 6 | ********************/ 7 | 8 | 9 | var storage = { 10 | 11 | engine: "behavior", 12 | 13 | store: null, 14 | 15 | storeName: '__StorageJS_BehaviorStorage', 16 | 17 | init: function(){ 18 | this.store = this._createStore(); 19 | this.store.load(this.storeName); 20 | }, 21 | 22 | _createStore: function() { 23 | var storeNode = document.createElement('link'); 24 | storeNode.id = this.storeName + 'Node' 25 | storeNode.style.display = 'none'; 26 | 27 | document.getElementsByTagName('head')[0].appendChild(storeNode); 28 | storeNode.addBehavior('#default#userdata'); 29 | 30 | return storeNode; 31 | }, 32 | 33 | get: function(key){ 34 | return this.store.getAttribute(key); 35 | }, 36 | 37 | set: function(key, value){ 38 | this.store.setAttribute(key, value); 39 | this.store.save(this.storeName); 40 | }, 41 | 42 | remove: function(key){ 43 | this.store.removeAttribute(key); 44 | this.store.save(this.storeName); 45 | } 46 | }; 47 | 48 | storage.init(); 49 | -------------------------------------------------------------------------------- /builds/storage-minimal-cookie.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"cookie",cookieName:"StorageJSCookie",store:{},init:function(){this.readStoreFromCookie();},get:function(_1){return this.store[_1]||null;},set:function(_2,_3){this.store[_2]=_3;this.updateCookie();},remove:function(_4){delete this.store[_4];this.updateCookie();},updateCookie:function(){var _5=this.stringify(this.store);var c=document.cookie;var _6={expires:100};var _7=_6.expires;if(typeof _7=="number"){var d=new Date();d.setTime(d.getTime()+_7*24*60*60*1000);_7=_6.expires=d;}if(_7&&_7.toUTCString){_6.expires=_7.toUTCString();}var _8=encodeURIComponent(_5);var _9=this.cookieName+"="+_8,_a;for(_a in _6){_9+="; "+_a;var _b=_6[_a];if(_b!==true){_9+="="+_b;}}document.cookie=_9;},readStoreFromCookie:function(){var c=document.cookie;var _c=c.match(new RegExp("(?:^|; )"+this.cookieName+"=([^;]*)"));var _d=_c?this.parse(decodeURIComponent(_c[1])):{};this.store=_d;},stringify:function(_e){if(typeof (JSON)!="undefined"&&JSON.stringify){return JSON.stringify(_e);}var _f="";for(var _10 in this.store){_f+=_10+":sjs-kv:"+this.store[_10]+":sjs-i:";}_f=_f.substring(0,_f.length-8);return _f;},parse:function(_11){if(typeof (JSON)!="undefined"&&JSON.parse){return JSON.parse(_11);}var _12={};var _13=_11.split(":sjs-i:");for(var i=0,m=_13.length,kv;i0){_2=rs.field(0);}rs.close();return _2;},set:function(_3,_4){if(this.get(_3)===null){this.db.execute("INSERT INTO "+this.tableName+" values (?, ?)",[_3,_4]);}else{this.db.execute("UPDATE "+this.tableName+" SET value = ? WHERE key = ?",[_4,_3]);}},remove:function(_5){this.db.execute("DELETE FROM "+this.tableName+" WHERE key = ?",[_5]);},initGears:function(){if(window.google&&google.gears){return;}var _6=null;if(typeof GearsFactory!="undefined"){_6=new GearsFactory();}else{try{_6=new ActiveXObject("Gears.Factory");if(_6.getBuildInfo().indexOf("ie_mobile")!=-1){_6.privateSetGlobalObject(this);}}catch(e){if((typeof navigator.mimeTypes!="undefined")&&navigator.mimeTypes["application/x-googlegears"]){_6=document.createElement("object");_6.style.display="none";_6.width=0;_6.height=0;_6.type="application/x-googlegears";document.documentElement.appendChild(_6);if(_6&&(typeof _6.create=="undefined")){_6=null;}}}}if(!_6){return;}if(!window.google){google={};}if(!google.gears){google.gears={factory:_6};}}};storage.init(); -------------------------------------------------------------------------------- /builds/storage-minimal-gears.uncompressed.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /*********FILE********** 5 | /features/engine/gears.js 6 | ********************/ 7 | 8 | 9 | // The initGears method is Copyright 2007, Google Inc. 10 | 11 | 12 | var storage = { 13 | 14 | engine: "gears", 15 | 16 | dbName: 'SJSDatabase', 17 | 18 | tableName: 'SJSStorageTable', 19 | 20 | db: null, 21 | 22 | init: function(){ 23 | this.initGears(); 24 | this.db = google.gears.factory.create('beta.database'); 25 | this.db.open(this.dbName); 26 | this.db.execute('CREATE TABLE IF NOT EXISTS ' + this.tableName + ' ( key TEXT PRIMARY KEY, value TEXT )'); 27 | }, 28 | 29 | get: function(key){ 30 | var rs = this.db.execute('SELECT value FROM ' + this.tableName + ' WHERE key = ?', [key]); 31 | var value = null; 32 | if(rs.isValidRow() && rs.fieldCount() > 0) { 33 | value = rs.field(0); 34 | } 35 | rs.close(); 36 | return value; 37 | }, 38 | 39 | set: function(key, value){ 40 | if(this.get(key) === null){ // no such key present, insert 41 | this.db.execute('INSERT INTO ' + this.tableName + ' values (?, ?)', [key, value]); 42 | }else{ // update 43 | this.db.execute('UPDATE ' + this.tableName + ' SET value = ? WHERE key = ?', [value, key]); 44 | } 45 | }, 46 | 47 | remove: function(key){ 48 | this.db.execute('DELETE FROM ' + this.tableName + ' WHERE key = ?', [key]); 49 | }, 50 | 51 | initGears: function(){ 52 | if (window.google && google.gears) { 53 | return; 54 | } 55 | 56 | var factory = null; 57 | 58 | // Firefox 59 | if (typeof GearsFactory != 'undefined') { 60 | factory = new GearsFactory(); 61 | } else { 62 | // IE 63 | try { 64 | factory = new ActiveXObject('Gears.Factory'); 65 | // privateSetGlobalObject is only required and supported on IE Mobile on 66 | // WinCE. 67 | if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { 68 | factory.privateSetGlobalObject(this); 69 | } 70 | } catch (e) { 71 | // Safari 72 | if ((typeof navigator.mimeTypes != 'undefined') 73 | && navigator.mimeTypes["application/x-googlegears"]) { 74 | factory = document.createElement("object"); 75 | factory.style.display = "none"; 76 | factory.width = 0; 77 | factory.height = 0; 78 | factory.type = "application/x-googlegears"; 79 | document.documentElement.appendChild(factory); 80 | if(factory && (typeof factory.create == 'undefined')) { 81 | // If NP_Initialize() returns an error, factory will still be created. 82 | // We need to make sure this case doesn't cause Gears to appear to 83 | // have been initialized. 84 | factory = null; 85 | } 86 | } 87 | } 88 | } 89 | 90 | // *Do not* define any objects if Gears is not installed. This mimics the 91 | // behavior of Gears defining the objects in the future. 92 | if (!factory) { 93 | return; 94 | } 95 | 96 | // Now set up the objects, being careful not to overwrite anything. 97 | // 98 | // Note: In Internet Explorer for Windows Mobile, you can't add properties to 99 | // the window object. However, global objects are automatically added as 100 | // properties of the window object in all browsers. 101 | if (!window.google) { 102 | google = {}; 103 | } 104 | 105 | if (!google.gears) { 106 | google.gears = {factory: factory}; 107 | } 108 | 109 | } 110 | }; 111 | 112 | storage.init(); 113 | -------------------------------------------------------------------------------- /builds/storage-minimal-localStorage.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"localStorage",get:function(_1){return localStorage.getItem(_1);},set:function(_2,_3){localStorage.setItem(_2,_3);},remove:function(_4){localStorage.removeItem(_4);}}; -------------------------------------------------------------------------------- /builds/storage-minimal-localStorage.uncompressed.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /*********FILE********** 5 | /features/engine/localStorage.js 6 | ********************/ 7 | 8 | 9 | var storage = { 10 | 11 | engine: "localStorage", 12 | 13 | get: function(/*String*/ key){ 14 | // summary: 15 | // Retrieves a value from storage. 16 | // description: 17 | // With `storage.get` you can retrieve 18 | // a previously stored item from the storage. 19 | // If there is no item associated with the 20 | // given key, `get` will return `null`. 21 | // feature: 22 | // engine 23 | // key: String 24 | // The key to look up in the storage. 25 | // example: 26 | // | var value = storage.get('someKey'); 27 | return localStorage.getItem(key); // String 28 | }, 29 | 30 | set: function(/*String*/ key, /*String*/ value){ 31 | // summary: 32 | // Stores a key/value pair in the storage. 33 | // description: 34 | // Tries to store the given value under 35 | // the given key. Depending on the used 36 | // storage engine, an exception may be 37 | // raised during the process if the 38 | // operation fails. 39 | // If there is already a value stored 40 | // with the same key, the old value is 41 | // repleaced with the new one. 42 | // Returns nothing. 43 | // feature: 44 | // engine 45 | // key: String 46 | // The unique key to store the value under. 47 | // This key is the identifier of the value, 48 | // and can be used to retrieve the value 49 | // later on. 50 | // value: String 51 | // The value to store. 52 | // example: 53 | // | storage.set('someKey', 'someValue'); 54 | localStorage.setItem(key, value); 55 | }, 56 | 57 | remove: function(/*String*/ key){ 58 | // summary: 59 | // Removes a key/value pair from the 60 | // storage. 61 | // description: 62 | // `remove` deletes the key/value pair 63 | // that is associated with the given key, 64 | // and frees up the storage space used 65 | // by this pair. 66 | // If there is no entry for the given 67 | // key, nothing happens. 68 | // Returns nothing. 69 | // feature: 70 | // engine 71 | // key: String 72 | // The key that identifies the pair. 73 | // example: 74 | // | storage.remove('someKey'); 75 | localStorage.removeItem(key); 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /builds/storage-minimal-widget.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"widget",get:function(_1){return widget.preferenceForKey(_1);},set:function(_2,_3){this.ensureKeyInMap(_2);widget.setPreferenceForKey(_3,_2);},remove:function(_4){this.removeKeyFromMap(_4);widget.setPreferenceForKey(null,_4);},ensureKeyInMap:function(){},removeKeyFromMap:function(){}}; -------------------------------------------------------------------------------- /builds/storage-minimal-widget.uncompressed.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /*********FILE********** 5 | /features/engine/widget.js 6 | ********************/ 7 | 8 | 9 | var storage = { 10 | 11 | engine: "widget", 12 | 13 | get: function(key){ 14 | return widget.preferenceForKey(key); 15 | }, 16 | 17 | set: function(key, value){ 18 | this.ensureKeyInMap(key); 19 | widget.setPreferenceForKey(value, key); 20 | }, 21 | 22 | remove: function(key){ 23 | this.removeKeyFromMap(key); 24 | widget.setPreferenceForKey(null, key); 25 | }, 26 | 27 | /* -- stubs for keymap feature -- */ 28 | 29 | ensureKeyInMap: function(){}, 30 | 31 | removeKeyFromMap: function(){} 32 | }; 33 | -------------------------------------------------------------------------------- /features/checkedSet/README: -------------------------------------------------------------------------------- 1 | The feature "checkedSet" will modify the following method: 2 | 3 | - storage.set(key, value) 4 | 5 | When this feture is included, the set() method will check if the 6 | write action was successful, and will return boolean true if it was, 7 | and false if it failed. -------------------------------------------------------------------------------- /features/checkedSet/checkedSet.js: -------------------------------------------------------------------------------- 1 | (function(oldSet){ 2 | 3 | storage.set = function(key, value){ 4 | oldSet.call(storage, key, value); 5 | return storage.get(key) == value; 6 | }; 7 | 8 | })(storage.set); 9 | -------------------------------------------------------------------------------- /features/checkedSet/dependencies.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensarps/StorageJS/761426866a1cf21d97e221bf0f14370e8a3bdadd/features/checkedSet/dependencies.json -------------------------------------------------------------------------------- /features/clear/README: -------------------------------------------------------------------------------- 1 | The feature "clear" adds the following method: 2 | 3 | - storage.clear() 4 | 5 | Calling clear() will clear the storage, i.e. remove all keys. -------------------------------------------------------------------------------- /features/clear/behavior.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | var attributes = this.store.XMLDocument.documentElement.attributes; 3 | for(var i = 0, m = attributes.length; i < m; i++){ 4 | this.store.removeAttribute(attributes[0].name); 5 | } 6 | this.store.save(this.storeName); 7 | }; 8 | -------------------------------------------------------------------------------- /features/clear/cookie.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | this.store = {}; 3 | this.updateCookie(); 4 | }; -------------------------------------------------------------------------------- /features/clear/dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget.js": [ // The "clear" impl for the widget storage relies on the "keyMap" feature. 3 | "keyMap" 4 | ] 5 | } -------------------------------------------------------------------------------- /features/clear/gears.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | this.db.execute('DELETE FROM ' + this.tableName); 3 | }; -------------------------------------------------------------------------------- /features/clear/localStorage.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | // summary: 3 | // Clears the storage. 4 | // description: 5 | // `clear` will delete everything 6 | // in the storage. 7 | // Returns nothing. 8 | // feature: 9 | // clear 10 | // example: 11 | // | storage.clear(); 12 | localStorage.clear(); 13 | }; -------------------------------------------------------------------------------- /features/clear/widget.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | for(var i = 0, m = this.keys.length; i < m; i++){ 3 | widget.setPreferenceForKey(null, this.keys[i]); 4 | } 5 | this.keys = []; 6 | this.saveKeyMap(); 7 | }; -------------------------------------------------------------------------------- /features/engine/README: -------------------------------------------------------------------------------- 1 | The feature "engine" is the basic storage engine wrapper. It provides the 2 | following methods: 3 | 4 | - storage.get(key) 5 | - storage.set(key, value) 6 | - storage.remove(key) 7 | 8 | Note that "key" AND "value" MUST be strings! -------------------------------------------------------------------------------- /features/engine/behavior.js: -------------------------------------------------------------------------------- 1 | var storage = { 2 | 3 | engine: "behavior", 4 | 5 | store: null, 6 | 7 | storeName: '__StorageJS_BehaviorStorage', 8 | 9 | init: function(){ 10 | this.store = this._createStore(); 11 | this.store.load(this.storeName); 12 | }, 13 | 14 | _createStore: function() { 15 | var storeNode = document.createElement('link'); 16 | storeNode.id = this.storeName + 'Node' 17 | storeNode.style.display = 'none'; 18 | 19 | document.getElementsByTagName('head')[0].appendChild(storeNode); 20 | storeNode.addBehavior('#default#userdata'); 21 | 22 | return storeNode; 23 | }, 24 | 25 | get: function(key){ 26 | return this.store.getAttribute(key) || null; 27 | }, 28 | 29 | set: function(key, value){ 30 | this.store.setAttribute(key, value); 31 | this.store.save(this.storeName); 32 | }, 33 | 34 | remove: function(key){ 35 | this.store.removeAttribute(key); 36 | this.store.save(this.storeName); 37 | } 38 | }; 39 | 40 | storage.init(); 41 | -------------------------------------------------------------------------------- /features/engine/cookie.js: -------------------------------------------------------------------------------- 1 | var storage = { 2 | 3 | engine: "cookie", 4 | 5 | cookieName: 'StorageJSCookie', 6 | 7 | store: {}, 8 | 9 | init: function(){ 10 | this.readStoreFromCookie(); 11 | }, 12 | 13 | get: function(key){ 14 | return this.store[key] || null; 15 | }, 16 | 17 | set: function(key, value){ 18 | this.store[key] = value; 19 | this.updateCookie(); 20 | }, 21 | 22 | remove: function(key){ 23 | delete this.store[key]; 24 | this.updateCookie(); 25 | }, 26 | 27 | updateCookie: function(){ 28 | var cookieString = this.stringify(this.store); 29 | var c = document.cookie; 30 | var props = { 31 | expires: 100 32 | } 33 | // this is a shameless theft from dojo. 34 | var exp = props.expires; 35 | if(typeof exp == "number"){ 36 | var d = new Date(); 37 | d.setTime(d.getTime() + exp*24*60*60*1000); 38 | exp = props.expires = d; 39 | } 40 | if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); } 41 | 42 | var value = encodeURIComponent(cookieString); 43 | var updatedCookie = this.cookieName + "=" + value, propName; 44 | for(propName in props){ 45 | updatedCookie += "; " + propName; 46 | var propValue = props[propName]; 47 | if(propValue !== true){ updatedCookie += "=" + propValue; } 48 | } 49 | document.cookie = updatedCookie; 50 | }, 51 | 52 | readStoreFromCookie: function(){ 53 | var c = document.cookie; 54 | var matches = c.match(new RegExp("(?:^|; )" + this.cookieName + "=([^;]*)")); 55 | var data = matches ? this.parse(decodeURIComponent(matches[1])) : {}; 56 | 57 | this.store = data; 58 | }, 59 | 60 | stringify: function(data){ 61 | if(typeof(JSON) != 'undefined' && JSON.stringify){ 62 | return JSON.stringify(data); 63 | } 64 | var string = ''; 65 | for(var item in this.store){ 66 | string += item + ':sjs-kv:' + this.store[item] + ':sjs-i:'; 67 | } 68 | string = string.substring(0,string.length - 8); 69 | return string; 70 | }, 71 | 72 | parse: function(string){ 73 | if(typeof(JSON) != 'undefined' && JSON.parse){ 74 | return JSON.parse(string); 75 | } 76 | var data = {}; 77 | var pairs = string.split(':sjs-i:'); 78 | for(var i=0, m=pairs.length ,kv; i 0) { 25 | value = rs.field(0); 26 | } 27 | rs.close(); 28 | return value; 29 | }, 30 | 31 | set: function(key, value){ 32 | if(this.get(key) === null){ // no such key present, insert 33 | this.db.execute('INSERT INTO ' + this.tableName + ' values (?, ?)', [key, value]); 34 | }else{ // update 35 | this.db.execute('UPDATE ' + this.tableName + ' SET value = ? WHERE key = ?', [value, key]); 36 | } 37 | }, 38 | 39 | remove: function(key){ 40 | this.db.execute('DELETE FROM ' + this.tableName + ' WHERE key = ?', [key]); 41 | }, 42 | 43 | initGears: function(){ 44 | if (window.google && google.gears) { 45 | return; 46 | } 47 | 48 | var factory = null; 49 | 50 | // Firefox 51 | if (typeof GearsFactory != 'undefined') { 52 | factory = new GearsFactory(); 53 | } else { 54 | // IE 55 | try { 56 | factory = new ActiveXObject('Gears.Factory'); 57 | // privateSetGlobalObject is only required and supported on IE Mobile on 58 | // WinCE. 59 | if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { 60 | factory.privateSetGlobalObject(this); 61 | } 62 | } catch (e) { 63 | // Safari 64 | if ((typeof navigator.mimeTypes != 'undefined') 65 | && navigator.mimeTypes["application/x-googlegears"]) { 66 | factory = document.createElement("object"); 67 | factory.style.display = "none"; 68 | factory.width = 0; 69 | factory.height = 0; 70 | factory.type = "application/x-googlegears"; 71 | document.documentElement.appendChild(factory); 72 | if(factory && (typeof factory.create == 'undefined')) { 73 | // If NP_Initialize() returns an error, factory will still be created. 74 | // We need to make sure this case doesn't cause Gears to appear to 75 | // have been initialized. 76 | factory = null; 77 | } 78 | } 79 | } 80 | } 81 | 82 | // *Do not* define any objects if Gears is not installed. This mimics the 83 | // behavior of Gears defining the objects in the future. 84 | if (!factory) { 85 | return; 86 | } 87 | 88 | // Now set up the objects, being careful not to overwrite anything. 89 | // 90 | // Note: In Internet Explorer for Windows Mobile, you can't add properties to 91 | // the window object. However, global objects are automatically added as 92 | // properties of the window object in all browsers. 93 | if (!window.google) { 94 | google = {}; 95 | } 96 | 97 | if (!google.gears) { 98 | google.gears = {factory: factory}; 99 | } 100 | 101 | } 102 | }; 103 | 104 | storage.init(); 105 | -------------------------------------------------------------------------------- /features/engine/localStorage.js: -------------------------------------------------------------------------------- 1 | var storage = { 2 | 3 | engine: "localStorage", 4 | 5 | get: function(/*String*/ key){ 6 | // summary: 7 | // Retrieves a value from storage. 8 | // description: 9 | // With `storage.get` you can retrieve 10 | // a previously stored item from the storage. 11 | // If there is no item associated with the 12 | // given key, `get` will return `null`. 13 | // feature: 14 | // engine 15 | // key: String 16 | // The key to look up in the storage. 17 | // example: 18 | // | var value = storage.get('someKey'); 19 | return localStorage.getItem(key); // String 20 | }, 21 | 22 | set: function(/*String*/ key, /*String*/ value){ 23 | // summary: 24 | // Stores a key/value pair in the storage. 25 | // description: 26 | // Tries to store the given value under 27 | // the given key. Depending on the used 28 | // storage engine, an exception may be 29 | // raised during the process if the 30 | // operation fails. 31 | // If there is already a value stored 32 | // with the same key, the old value is 33 | // repleaced with the new one. 34 | // Returns nothing. 35 | // feature: 36 | // engine 37 | // key: String 38 | // The unique key to store the value under. 39 | // This key is the identifier of the value, 40 | // and can be used to retrieve the value 41 | // later on. 42 | // value: String 43 | // The value to store. 44 | // example: 45 | // | storage.set('someKey', 'someValue'); 46 | localStorage.setItem(key, value); 47 | }, 48 | 49 | remove: function(/*String*/ key){ 50 | // summary: 51 | // Removes a key/value pair from the 52 | // storage. 53 | // description: 54 | // `remove` deletes the key/value pair 55 | // that is associated with the given key, 56 | // and frees up the storage space used 57 | // by this pair. 58 | // If there is no entry for the given 59 | // key, nothing happens. 60 | // Returns nothing. 61 | // feature: 62 | // engine 63 | // key: String 64 | // The key that identifies the pair. 65 | // example: 66 | // | storage.remove('someKey'); 67 | localStorage.removeItem(key); 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /features/engine/widget.js: -------------------------------------------------------------------------------- 1 | var storage = { 2 | 3 | engine: "widget", 4 | 5 | get: function(key){ 6 | return widget.preferenceForKey(key) || null; 7 | }, 8 | 9 | set: function(key, value){ 10 | this.ensureKeyInMap(key); 11 | widget.setPreferenceForKey(value, key); 12 | }, 13 | 14 | remove: function(key){ 15 | this.removeKeyFromMap(key); 16 | widget.setPreferenceForKey(null, key); 17 | }, 18 | 19 | /* -- stubs for keymap feature -- */ 20 | 21 | ensureKeyInMap: function(){}, 22 | 23 | removeKeyFromMap: function(){} 24 | }; 25 | -------------------------------------------------------------------------------- /features/getAll/README: -------------------------------------------------------------------------------- 1 | The feature "getAll" adds the following method: 2 | 3 | - storage.getAll() 4 | 5 | Calling getAll() will return an Array of Objects, containing all 6 | key/value pairs present in storage. 7 | 8 | Example return value: 9 | 10 | [ 11 | { 12 | key: "foo", 13 | value: "foo-value" 14 | }, 15 | { 16 | key: "bar", 17 | value: "bar-value" 18 | } 19 | ] -------------------------------------------------------------------------------- /features/getAll/behavior.js: -------------------------------------------------------------------------------- 1 | storage.getAll = function(){ 2 | var all = []; 3 | var attributes = this.store.XMLDocument.documentElement.attributes; 4 | for(var i = 0, m = attributes.length; i < m; i++){ 5 | all.push({key: attributes[i].name, value: attributes[i].value }); 6 | } 7 | return all; 8 | }; -------------------------------------------------------------------------------- /features/getAll/cookie.js: -------------------------------------------------------------------------------- 1 | storage.getAll = function(){ 2 | var all = []; 3 | for(var key in this.store){ 4 | all.push({ key: key, value: this.get(key)}); 5 | } 6 | return all; 7 | }; -------------------------------------------------------------------------------- /features/getAll/dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "keymapped.js": [ // The "getAll" impls that use keymap rely on the "keyMap" feature. 3 | "keyMap" 4 | ] 5 | } -------------------------------------------------------------------------------- /features/getAll/gears.js: -------------------------------------------------------------------------------- 1 | storage.getAll = function(){ 2 | var all = []; 3 | 4 | var rs = this.db.execute('SELECT * FROM ' + this.tableName); 5 | var index = 0; 6 | while (rs.isValidRow() && rs.fieldCount() > 1) { 7 | all.push({key: rs.fieldByName('key'), value: rs.fieldByName('value')}); 8 | rs.next(); 9 | } 10 | rs.close(); 11 | 12 | return all; 13 | }; -------------------------------------------------------------------------------- /features/getAll/keymapped.js: -------------------------------------------------------------------------------- 1 | storage.getAll = function(){ 2 | var all = []; 3 | for(var i = 0, m = this.keys.length; i < m; i++){ 4 | all.push({key: this.keys[i], value: this.get(this.keys[i])}); 5 | } 6 | return all; 7 | }; -------------------------------------------------------------------------------- /features/getAll/localStorage.js: -------------------------------------------------------------------------------- 1 | storage.getAll = function(){ 2 | // summary: 3 | // Retrieves all stored key/value 4 | // pairs currently present in 5 | // storage. 6 | // description: 7 | // `getAll` will collect everything 8 | // that is stored and return an 9 | // array of objects. If the storage 10 | // is empty, it will return an empty 11 | // array. 12 | // feature: 13 | // getAll 14 | // example: 15 | // | var all = storage.getAll(); 16 | // | console.log(all); 17 | // | // output could be: 18 | // | // [{key: 'someKey', value: 'someValue'}] 19 | var all = [], 20 | i = 0, 21 | m = localStorage.length, 22 | key; 23 | for(; i < m; i++){ 24 | key = localStorage.key(i); 25 | all.push({ key: key, value: this.get(key)}); 26 | } 27 | return all; // Array 28 | }; -------------------------------------------------------------------------------- /features/getAllKeys/README: -------------------------------------------------------------------------------- 1 | The feature "getAllKeys" adds the following method: 2 | 3 | - storage.getAllKeys() 4 | 5 | Calling getAll() will return an Array of all keys 6 | present in storage. 7 | 8 | Example return value: 9 | 10 | ["foo", "bar"] -------------------------------------------------------------------------------- /features/getAllKeys/behavior.js: -------------------------------------------------------------------------------- 1 | storage.getAllKeys = function(){ 2 | var keys = []; 3 | var attributes = this.store.XMLDocument.documentElement.attributes; 4 | for(var i=0, m = attributes.length; i 0) { 7 | keys.push(rs.field(0)); 8 | rs.next(); 9 | } 10 | rs.close(); 11 | 12 | return keys; 13 | }; -------------------------------------------------------------------------------- /features/getAllKeys/keymapped.js: -------------------------------------------------------------------------------- 1 | storage.getAllKeys = function(){ 2 | return this.keys; 3 | }; -------------------------------------------------------------------------------- /features/getAllKeys/localStorage.js: -------------------------------------------------------------------------------- 1 | storage.getAllKeys = function(){ 2 | // summary: 3 | // Retrieves all keys currently 4 | // present in storage. 5 | // description: 6 | // `getAllKeys` will collect all 7 | // keys that are stored and return an 8 | // array of keys. If the storage 9 | // is empty, it will return an empty 10 | // array. 11 | // feature: 12 | // getAllKeys 13 | // example: 14 | // | var keys = storage.getAllKeys(); 15 | // | console.log(keys); 16 | // | // output could be: 17 | // | // ['someKey'] 18 | var keys = [], 19 | i = 0, 20 | m = localStorage.length; 21 | for(; i < m; i++){ 22 | keys.push(localStorage.key(i)); 23 | } 24 | return keys; // Array 25 | }; -------------------------------------------------------------------------------- /features/keyMap/README: -------------------------------------------------------------------------------- 1 | The feature "keyMap" will neither add or modify any API method. 2 | 3 | It's a special feature needed to provide features like clear or getAll 4 | for certain storage engines. You don't have to include it yourself, 5 | this is all handled by dependency resolution. Fell free to ignore 6 | this feature :) -------------------------------------------------------------------------------- /features/keyMap/dependencies.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensarps/StorageJS/761426866a1cf21d97e221bf0f14370e8a3bdadd/features/keyMap/dependencies.json -------------------------------------------------------------------------------- /features/keyMap/generic.js: -------------------------------------------------------------------------------- 1 | storage.keys = []; 2 | 3 | storage.ensureKeyInMap = function(key){ 4 | if(!this.hasKeyInMap(key)){ 5 | this.keys.push(key); 6 | this.saveKeyMap(); 7 | } 8 | }; 9 | 10 | storage.hasKeyInMap = function(key){ 11 | for(var i = 0, m = this.keys.length; i< m; i++){ 12 | if(key === this.keys[i]){ 13 | return true; 14 | } 15 | } 16 | return false; 17 | }; 18 | 19 | storage.removeKeyFromMap = function(key){ 20 | var newKeys = []; 21 | for(var i = 0, m = this.keys.length; i< m; i++){ 22 | if(key !== this.keys[i]){ 23 | newKeys.push(key); 24 | } 25 | } 26 | this.keys = newKeys; 27 | this.saveKeyMap(); 28 | }; 29 | 30 | storage.stringifyArray = function(data){ 31 | if(typeof JSON != 'undefined' && JSON.stringify){ 32 | return JSON.stringify(data); 33 | } 34 | var string = ''; 35 | for(var i = 0, m = data.length; i < m; i++){ 36 | string += item + ':sjs-k:'; 37 | } 38 | string = string.substring(0,string.length - 8); 39 | return string; 40 | }; 41 | 42 | storage.parseString = function(string){ 43 | if(typeof JSON != 'undefined' && JSON.parse){ 44 | return JSON.parse(string); 45 | } 46 | var data = string.split(':sjs-k:'); 47 | return data; 48 | }; 49 | -------------------------------------------------------------------------------- /features/keyMap/widget.js: -------------------------------------------------------------------------------- 1 | storage.saveKeyMap = function(){ 2 | var value = this.stringifyArray(this.keys); 3 | widget.setPreferenceForKey(value, 'sjs-keymap'); 4 | }; 5 | 6 | storage.loadKeyMap = function(){ 7 | var keyString = widget.preferenceForKey('sjs-keymap'); 8 | var keys = keyString.length && keyString.length > 0 ? this.parseString(keyString) : []; 9 | this.keys = keys; 10 | }; 11 | 12 | storage.loadKeyMap(); 13 | -------------------------------------------------------------------------------- /features/object/dependencies.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensarps/StorageJS/761426866a1cf21d97e221bf0f14370e8a3bdadd/features/object/dependencies.json -------------------------------------------------------------------------------- /features/object/object.js: -------------------------------------------------------------------------------- 1 | ;(function(oldSet, oldGet){ 2 | 3 | storage.get = function(/* String */ key, /* Function? */ parse){ 4 | // summary: 5 | // Retrieves an object from storage. 6 | // description: 7 | // With `storage.get` you can retrieve 8 | // a previously stored object from the storage. 9 | // If there is no item associated with the 10 | // given key, `getObject` will return `null`. 11 | // feature: 12 | // object 13 | // key: String 14 | // The key to look up in the storage. 15 | // parse: Function? 16 | // A parse method that consumes a JSON string 17 | // and returns a JavaScript object. If no parse 18 | // method is given, the JSON.parse method is 19 | // used. 20 | // example: 21 | // | var valueObj = storage.get('someKey'); 22 | return (parse || JSON.parse)(oldGet.call(storage, key)); 23 | }; 24 | 25 | storage.set = function(/* String */ key, /* Object */ value, /* Funtion? */ stringify){ 26 | // summary: 27 | // Stores a key/value pair in the storage. 28 | // description: 29 | // Tries to store the given value under 30 | // the given key. Depending on the used 31 | // storage engine, an exception may be 32 | // raised during the process if the 33 | // operation fails. 34 | // If there is already a value stored 35 | // with the same key, the old value is 36 | // repleaced with the new one. 37 | // Returns nothing. 38 | // feature: 39 | // object 40 | // key: String 41 | // The unique key to store the value under. 42 | // This key is the identifier of the value, 43 | // and can be used to retrieve the value 44 | // later on. 45 | // value: Object 46 | // The value to store. 47 | // stringify: Function? 48 | // A stringify method that consumes a JavaScript 49 | // object and returns a JSON string. If no 50 | // stringify method is given, the JSON.stringify 51 | // method is used. 52 | // example: 53 | // | storage.set('someKey', 'someObject'); 54 | return oldSet.call(storage, key, (stringify || JSON.stringify)(value)); 55 | }; 56 | 57 | })(storage.get, storage.set); -------------------------------------------------------------------------------- /features/wrappedWrites/README: -------------------------------------------------------------------------------- 1 | The feature "wrappedWrites" will modify the following methods: 2 | 3 | - storage.set(key, value) 4 | - storage.remove(key) 5 | - storage.clear() [if present] 6 | 7 | When this feture is included, all write access to storage 8 | will be wrapped in try/catch blocks, and the above mentioned 9 | methods will return false if an Error occurred within write 10 | access and true if not. 11 | 12 | Note that this is an expensive thing to do! -------------------------------------------------------------------------------- /features/wrappedWrites/dependencies.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensarps/StorageJS/761426866a1cf21d97e221bf0f14370e8a3bdadd/features/wrappedWrites/dependencies.json -------------------------------------------------------------------------------- /features/wrappedWrites/wrappedWrites.js: -------------------------------------------------------------------------------- 1 | (function(oldSet, oldGet, oldClear){ 2 | 3 | storage.set = function(key, value){ 4 | var result = false; 5 | try{ 6 | result = oldSet.call(storage, key, value); 7 | result = (result === false) ? false : true; 8 | }catch(e){ 9 | } 10 | return result; 11 | }; 12 | 13 | storage.remove = function(key, value){ 14 | var result = false; 15 | try{ 16 | oldRemove.call(storage, key, value); 17 | result = true; 18 | }catch(e){ 19 | } 20 | return result; 21 | }; 22 | 23 | if(oldClear){ 24 | 25 | storage.clear = function(key, value){ 26 | var result = false; 27 | try{ 28 | oldClear.call(storage, key, value); 29 | result = true; 30 | }catch(e){ 31 | } 32 | return result; 33 | }; 34 | } 35 | 36 | })(storage.set, storage.get, storage.clear); -------------------------------------------------------------------------------- /platforms/behavior.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file defines the files that implement 3 | // the given features for userData behavior storage. 4 | // 5 | // It must contain pointers to files for *ALL* 6 | // available features. 7 | 8 | "engine": [ 9 | "engine/behavior.js" 10 | ], 11 | 12 | "keyMap": [ 13 | ], 14 | 15 | "clear": [ 16 | "clear/behavior.js" 17 | ], 18 | 19 | "getAll": [ 20 | "getAll/behavior.js" 21 | ], 22 | 23 | "getAllKeys" : [ 24 | "getAllKeys/behavior.js" 25 | ], 26 | 27 | "checkedSet": [ 28 | "checkedSet/checkedSet.js" 29 | ], 30 | 31 | "wrappedWrites": [ 32 | "wrappedWrites/wrappedWrites.js" 33 | ], 34 | 35 | "object": [ 36 | "object/object.js" 37 | ] 38 | } -------------------------------------------------------------------------------- /platforms/cookie.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file defines the files that implement 3 | // the given features for cookie storage. 4 | // 5 | // It must contain pointers to files for *ALL* 6 | // available features. 7 | 8 | "engine": [ 9 | "engine/cookie.js" 10 | ], 11 | 12 | "clear": [ 13 | "clear/cookie.js" 14 | ], 15 | 16 | "getAll": [ 17 | "getAll/cookie.js" 18 | ], 19 | 20 | "getAllKeys" : [ 21 | "getAllKeys/cookie.js" 22 | ], 23 | 24 | "checkedSet": [ 25 | "checkedSet/checkedSet.js" 26 | ], 27 | 28 | "wrappedWrites": [ 29 | "wrappedWrites/wrappedWrites.js" 30 | ], 31 | 32 | "object": [ 33 | "object/object.js" 34 | ] 35 | } -------------------------------------------------------------------------------- /platforms/gears.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file defines the files that implement 3 | // the given features for Google gears storage. 4 | // 5 | // It must contain pointers to files for *ALL* 6 | // available features. 7 | 8 | "engine": [ 9 | "engine/gears.js" 10 | ], 11 | 12 | "clear": [ 13 | "clear/gears.js" 14 | ], 15 | 16 | "getAll": [ 17 | "getAll/gears.js" 18 | ], 19 | 20 | "getAllKeys" : [ 21 | "getAllKeys/gears.js" 22 | ], 23 | 24 | "checkedSet": [ 25 | "checkedSet/checkedSet.js" 26 | ], 27 | 28 | "wrappedWrites": [ 29 | "wrappedWrites/wrappedWrites.js" 30 | ], 31 | 32 | "object": [ 33 | "object/object.js" 34 | ] 35 | } -------------------------------------------------------------------------------- /platforms/localStorage.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file defines the files that implement 3 | // the given features for localStorage. 4 | // 5 | // It must contain pointers to files for *ALL* 6 | // available features. 7 | 8 | "engine": [ 9 | "engine/localStorage.js" 10 | ], 11 | 12 | "clear": [ 13 | "clear/localStorage.js" 14 | ], 15 | 16 | "getAll": [ 17 | "getAll/localStorage.js" 18 | ], 19 | 20 | "getAllKeys" : [ 21 | "getAllKeys/localStorage.js" 22 | ], 23 | 24 | "checkedSet": [ 25 | "checkedSet/checkedSet.js" 26 | ], 27 | 28 | "wrappedWrites": [ 29 | "wrappedWrites/wrappedWrites.js" 30 | ], 31 | 32 | "object": [ 33 | "object/object.js" 34 | ] 35 | } -------------------------------------------------------------------------------- /platforms/widget.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file defines the files that implement 3 | // the given features for widget prefs storage. 4 | // 5 | // It must contain pointers to files for *ALL* 6 | // available features. 7 | 8 | "engine": [ 9 | "engine/widget.js" 10 | ], 11 | 12 | "keyMap": [ 13 | "keyMap/generic.js", 14 | "keyMap/widget.js" 15 | ], 16 | 17 | "clear": [ 18 | "clear/widget.js" 19 | ], 20 | 21 | "getAll": [ 22 | "getAll/keymapped.js" 23 | ], 24 | 25 | "getAllKeys" : [ 26 | "getAllKeys/keymapped.js" 27 | ], 28 | 29 | "checkedSet": [ 30 | "checkedSet/checkedSet.js" 31 | ], 32 | 33 | "wrappedWrites": [ 34 | "wrappedWrites/wrappedWrites.js" 35 | ], 36 | 37 | "object": [ 38 | "object/object.js" 39 | ] 40 | } -------------------------------------------------------------------------------- /tests/test_behavior.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: userData behavior 5 | 6 | 7 | 8 |

StorageJS Tests: userData behavior

9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/test_cookie.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: cookie 5 | 6 | 7 | 8 |

StorageJS Tests: cookie

9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/test_gears.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: Gears 5 | 6 | 7 | 8 |

StorageJS Tests: Gears

9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/test_localStorage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: localStorage 5 | 6 | 7 | 8 |

StorageJS Tests: localStorage

9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/test_widget.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: Widget Preference Store 5 | 6 | 7 | 8 |

StorageJS Tests: Widget Preference Store

9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/tests.js: -------------------------------------------------------------------------------- 1 | var test = { 2 | 3 | resultsNode: document.getElementById('results'), 4 | 5 | tests: 0, 6 | 7 | failures: 0, 8 | 9 | log: function(msg, result){ 10 | this.tests++; 11 | if(!result){ 12 | this.failures++; 13 | } 14 | this.resultsNode.innerHTML += ( '
' + msg + ': ' + ( result ? 'success' : 'failure' ) + '
'); 15 | }, 16 | 17 | done: function(){ 18 | this.log("All done. " + this.tests + " Tests, " + this.failures + " Failures", this.failures === 0); 19 | } 20 | 21 | }; 22 | 23 | function runTests(){ 24 | 25 | var value, testValue, testValue2, 26 | nullValue = storage.engine == "widget" ? "" : null, // Widget Prefs store returns empty string as null value. 27 | getNewValue = function(){ return (+new Date()) + ""; }; 28 | 29 | // get/set 30 | value = getNewValue(); 31 | storage.set('test-key',value); 32 | testValue = storage.get('test-key'); 33 | test.log('testing set/get', value === testValue); 34 | 35 | // remove 36 | storage.remove('test-key'); 37 | testValue = storage.get('test-key'); 38 | test.log('testing remove', testValue === nullValue); 39 | 40 | // clear 41 | value = getNewValue(); 42 | storage.set('test-key',value); 43 | storage.set('test-key-2',value); 44 | 45 | storage.clear(); 46 | testValue = storage.get('test-key'); 47 | testValue2 = storage.get('test-key-2'); 48 | test.log('testing clear', testValue === nullValue && testValue2 === nullValue); 49 | 50 | // getAll 51 | value = getNewValue(); 52 | storage.set('test-key',value); 53 | storage.set('test-key-2',value); 54 | 55 | var all = storage.getAll(); 56 | test.log('testing getAll', 57 | all.length === 2 && 58 | ( 59 | all[0].key === 'test-key' && 60 | all[0].value === value && 61 | all[1].key === 'test-key-2' && 62 | all[1].value === value 63 | ) || 64 | ( 65 | all[1].key === 'test-key' && 66 | all[1].value === value && 67 | all[0].key === 'test-key-2' && 68 | all[0].value === value 69 | ) 70 | ); 71 | 72 | // getAllKeys 73 | var allKeys = storage.getAllKeys(); 74 | test.log('testing getAllKeys', 75 | all.length === 2 && 76 | ( 77 | allKeys[0] === 'test-key' && 78 | allKeys[1] === 'test-key-2' 79 | ) || 80 | ( 81 | allKeys[1] === 'test-key' && 82 | allKeys[0] === 'test-key-2' 83 | ) 84 | ); 85 | 86 | // done! 87 | test.done(); 88 | 89 | } 90 | -------------------------------------------------------------------------------- /tests/widget/SJS.wgt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensarps/StorageJS/761426866a1cf21d97e221bf0f14370e8a3bdadd/tests/widget/SJS.wgt -------------------------------------------------------------------------------- /tests/widget/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | StorageJS Testwidget 4 | Tests for the Widget Preference Store. 5 | 400 6 | 600 7 | 8 | Jens Arps 9 | mail@jensarps.de 10 | http://jensarps.de 11 | 12 | 13 | jensarps.de 14 | SJSTest 15 | 2010-10-11 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: Widget Preference Store 5 | 6 | 9 | 10 | 11 |

StorageJS Tests: Widget Preference Store

12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/widget/storage-full-widget.js: -------------------------------------------------------------------------------- 1 | var storage={engine:"widget",get:function(_1){ 2 | return widget.preferenceForKey(_1); 3 | },set:function(_2,_3){ 4 | this.ensureKeyInMap(_2); 5 | widget.setPreferenceForKey(_3,_2); 6 | },remove:function(_4){ 7 | this.removeKeyFromMap(_4); 8 | widget.setPreferenceForKey(null,_4); 9 | },ensureKeyInMap:function(){ 10 | },removeKeyFromMap:function(){ 11 | }}; 12 | storage.keys=[]; 13 | storage.ensureKeyInMap=function(_1){ 14 | if(!this.hasKeyInMap(_1)){ 15 | this.keys.push(_1); 16 | this.saveKeyMap(); 17 | } 18 | }; 19 | storage.hasKeyInMap=function(_2){ 20 | for(var i=0,m=this.keys.length;i0?this.parseString(_2):[]; 62 | this.keys=_3; 63 | }; 64 | storage.loadKeyMap(); 65 | storage.clear=function(){ 66 | for(var i=0,m=this.keys.length;i' + msg + ': ' + ( result ? 'success' : 'failure' ) + ''); 15 | }, 16 | 17 | done: function(){ 18 | this.log("All done. " + this.tests + " Tests, " + this.failures + " Failures", this.failures === 0); 19 | } 20 | 21 | }; 22 | 23 | function runTests(){ 24 | 25 | var value, testValue, testValue2, 26 | nullValue = storage.engine == "widget" ? "" : null, // Widget Prefs store returns empty string as null value. 27 | getNewValue = function(){ return (+new Date()) + ""; }; 28 | 29 | // get/set 30 | value = getNewValue(); 31 | storage.set('test-key',value); 32 | testValue = storage.get('test-key'); 33 | test.log('testing set/get', value === testValue); 34 | 35 | // remove 36 | storage.remove('test-key'); 37 | testValue = storage.get('test-key'); 38 | test.log('testing remove', testValue === nullValue); 39 | 40 | // clear 41 | value = getNewValue(); 42 | storage.set('test-key',value); 43 | storage.set('test-key-2',value); 44 | 45 | storage.clear(); 46 | testValue = storage.get('test-key'); 47 | testValue2 = storage.get('test-key-2'); 48 | test.log('testing clear', testValue === nullValue && testValue2 === nullValue); 49 | 50 | // getAll 51 | value = getNewValue(); 52 | storage.set('test-key',value); 53 | storage.set('test-key-2',value); 54 | 55 | var all = storage.getAll(); 56 | test.log('testing getAll', 57 | all.length === 2 && 58 | ( 59 | all[0].key === 'test-key' && 60 | all[0].value === value && 61 | all[1].key === 'test-key-2' && 62 | all[1].value === value 63 | ) || 64 | ( 65 | all[1].key === 'test-key' && 66 | all[1].value === value && 67 | all[0].key === 'test-key-2' && 68 | all[0].value === value 69 | ) 70 | ); 71 | 72 | // getAllKeys 73 | var allKeys = storage.getAllKeys(); 74 | test.log('testing getAllKeys', 75 | all.length === 2 && 76 | ( 77 | allKeys[0] === 'test-key' && 78 | allKeys[1] === 'test-key-2' 79 | ) || 80 | ( 81 | allKeys[1] === 'test-key' && 82 | allKeys[0] === 'test-key-2' 83 | ) 84 | ); 85 | 86 | // done! 87 | test.done(); 88 | 89 | } 90 | --------------------------------------------------------------------------------