├── features ├── engine │ ├── dependencies.json │ ├── README │ ├── widget.js │ ├── behavior.js │ ├── localStorage.js │ ├── cookie.js │ └── gears.js ├── keyMap │ ├── dependencies.json │ ├── README │ ├── widget.js │ └── generic.js ├── object │ ├── dependencies.json │ └── object.js ├── checkedSet │ ├── dependencies.json │ ├── checkedSet.js │ └── README ├── wrappedWrites │ ├── dependencies.json │ ├── README │ └── wrappedWrites.js ├── getAllKeys │ ├── keymapped.js │ ├── dependencies.json │ ├── cookie.js │ ├── README │ ├── behavior.js │ ├── gears.js │ └── localStorage.js ├── clear │ ├── cookie.js │ ├── gears.js │ ├── dependencies.json │ ├── README │ ├── widget.js │ ├── behavior.js │ └── localStorage.js └── getAll │ ├── dependencies.json │ ├── cookie.js │ ├── keymapped.js │ ├── behavior.js │ ├── gears.js │ ├── README │ └── localStorage.js ├── tests ├── widget │ ├── SJS.wgt │ ├── config.xml │ ├── index.html │ ├── storage-full-widget.js │ └── tests.js ├── test_gears.html ├── test_cookie.html ├── test_behavior.html ├── test_localStorage.html ├── test_widget.html └── tests.js ├── platforms ├── cookie.json ├── gears.json ├── localStorage.json ├── behavior.json └── widget.json ├── LICENSE └── README.rst /features/engine/dependencies.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/keyMap/dependencies.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/object/dependencies.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/checkedSet/dependencies.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/wrappedWrites/dependencies.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/getAllKeys/keymapped.js: -------------------------------------------------------------------------------- 1 | storage.getAllKeys = function(){ 2 | return this.keys; 3 | }; -------------------------------------------------------------------------------- /tests/widget/SJS.wgt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jensarps/StorageJS/HEAD/tests/widget/SJS.wgt -------------------------------------------------------------------------------- /features/clear/cookie.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | this.store = {}; 3 | this.updateCookie(); 4 | }; -------------------------------------------------------------------------------- /features/clear/gears.js: -------------------------------------------------------------------------------- 1 | storage.clear = function(){ 2 | this.db.execute('DELETE FROM ' + this.tableName); 3 | }; -------------------------------------------------------------------------------- /features/getAll/dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "keymapped.js": [ // The "getAll" impls that use keymap rely on the "keyMap" feature. 3 | "keyMap" 4 | ] 5 | } -------------------------------------------------------------------------------- /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/getAllKeys/dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "keymapped.js": [ // The "getAllKeys" impls using keymap rely on the "keyMap" feature. 3 | "keyMap" 4 | ] 5 | } -------------------------------------------------------------------------------- /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/getAllKeys/cookie.js: -------------------------------------------------------------------------------- 1 | storage.getAllKeys = function(){ 2 | var keys = []; 3 | for(var key in this.store){ 4 | keys.push(key) 5 | } 6 | return keys; 7 | }; -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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 | ] -------------------------------------------------------------------------------- /tests/test_gears.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StorageJS Tests: Gears 5 | 6 | 7 | 8 |

StorageJS Tests: Gears

9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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_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_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 | -------------------------------------------------------------------------------- /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! -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | }; -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | }; -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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/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); -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests/widget/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /features/engine/gears.js: -------------------------------------------------------------------------------- 1 | // The initGears method is Copyright 2007, Google Inc. 2 | 3 | 4 | var storage = { 5 | 6 | engine: "gears", 7 | 8 | dbName: 'SJSDatabase', 9 | 10 | tableName: 'SJSStorageTable', 11 | 12 | db: null, 13 | 14 | init: function(){ 15 | this.initGears(); 16 | this.db = google.gears.factory.create('beta.database'); 17 | this.db.open(this.dbName); 18 | this.db.execute('CREATE TABLE IF NOT EXISTS ' + this.tableName + ' ( key TEXT PRIMARY KEY, value TEXT )'); 19 | }, 20 | 21 | get: function(key){ 22 | var rs = this.db.execute('SELECT value FROM ' + this.tableName + ' WHERE key = ?', [key]); 23 | var value = null; 24 | if(rs.isValidRow() && rs.fieldCount() > 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 | --------------------------------------------------------------------------------