*
* @param {string} key Key of item to retrieve
* @return {string|null|boolean} String value, null if no value exists, or false
- * if localStorage is not available.
+ * if storage is not available.
*/
SafeStorage.prototype.get = function ( key ) {
try {
*
* @param {string} key Key name to store under
* @param {string} value Value to be stored
- * @return {boolean} Whether the save succeeded or not
+ * @return {boolean} The value was set
*/
SafeStorage.prototype.set = function ( key, value ) {
try {
* Remove a value from device storage.
*
* @param {string} key Key of item to remove
- * @return {boolean} Whether the save succeeded or not
+ * @return {boolean} Whether the key was removed
*/
SafeStorage.prototype.remove = function ( key ) {
try {
return false;
};
+ /**
+ * Retrieve JSON object from device storage.
+ *
+ * @param {string} key Key of item to retrieve
+ * @return {Object|null|boolean} Object, null if no value exists or value
+ * is not JSON-parseable, or false if storage is not available.
+ */
+ SafeStorage.prototype.getObject = function ( key ) {
+ var json = this.get( key );
+
+ if ( json === false ) {
+ return false;
+ }
+
+ try {
+ return JSON.parse( json );
+ } catch ( e ) {}
+
+ return null;
+ };
+
+ /**
+ * Set an object value in device storage by JSON encoding
+ *
+ * @param {string} key Key name to store under
+ * @param {Object} value Object value to be stored
+ * @return {boolean} The value was set
+ */
+ SafeStorage.prototype.setObject = function ( key, value ) {
+ var json;
+ try {
+ json = JSON.stringify( value );
+ return this.set( key, json );
+ } catch ( e ) {}
+ return false;
+ };
+
/**
* A wrapper for the HTML5 `localStorage` interface
* that is safe to call on all browsers.
( function () {
QUnit.module( 'mediawiki.storage' );
- QUnit.test( 'set/get with storage support', function ( assert ) {
- var stub = {
- setItem: this.sandbox.spy(),
- getItem: this.sandbox.stub()
- };
- stub.getItem.withArgs( 'foo' ).returns( 'test' );
- stub.getItem.returns( null );
+ QUnit.test( 'set/get(Object) with storage support', function ( assert ) {
+ var data = {},
+ object = { test: 'value' },
+ stub = {
+ setItem: function ( k, v ) {
+ data[ k ] = v;
+ return true;
+ },
+ getItem: function ( k ) {
+ return Object.prototype.hasOwnProperty.call( data, k ) ? data[ k ] : null;
+ },
+ removeItem: function ( k ) {
+ delete data[ k ];
+ return true;
+ }
+ };
+
this.sandbox.stub( mw.storage, 'store', stub );
- mw.storage.set( 'foo', 'test' );
- assert.ok( stub.setItem.calledOnce );
+ assert.strictEqual( mw.storage.set( 'foo', 'test' ), true, 'set returns true' );
+ assert.strictEqual( mw.storage.get( 'foo' ), 'test', 'Check value gets stored' );
+ assert.strictEqual( mw.storage.get( 'bar' ), null, 'Unset values are null' );
+ assert.strictEqual( mw.storage.remove( 'foo' ), true, 'remove returns true' );
+ assert.strictEqual( mw.storage.get( 'foo' ), null, 'Removed item is null' );
+
+ assert.strictEqual( mw.storage.setObject( 'baz', object ), true, 'setObject returns true' );
+ assert.deepEqual( mw.storage.getObject( 'baz' ), object, 'Check value gets stored' );
+ assert.notStrictEqual( mw.storage.getObject( 'baz' ), object, 'Retrieved value is a new object' );
+ assert.strictEqual( mw.storage.getObject( 'quux' ), null, 'Unset values are null' );
+ assert.strictEqual( mw.storage.remove( 'baz' ), true, 'remove returns true' );
+ assert.strictEqual( mw.storage.getObject( 'baz' ), null, 'Removed item is null' );
+
+ mw.storage.set( 'baz', 'Non-JSON' );
+ assert.strictEqual( mw.storage.getObject( 'baz' ), null, 'Non-JSON values are null' );
- assert.strictEqual( mw.storage.get( 'foo' ), 'test', 'Check value gets stored.' );
- assert.strictEqual( mw.storage.get( 'bar' ), null, 'Unset values are null.' );
} );
- QUnit.test( 'set/get with storage methods disabled', function ( assert ) {
+ QUnit.test( 'set/get(Object) with storage methods disabled', function ( assert ) {
// This covers browsers where storage is disabled
// (quota full, or security/privacy settings).
// On most browsers, these interface will be accessible with
assert.strictEqual( mw.storage.get( 'foo' ), false );
assert.strictEqual( mw.storage.set( 'foo', 'test' ), false );
- assert.strictEqual( mw.storage.remove( 'foo', 'test' ), false );
+ assert.strictEqual( mw.storage.remove( 'foo' ), false );
+
+ assert.strictEqual( mw.storage.getObject( 'bar' ), false );
+ assert.strictEqual( mw.storage.setObject( 'bar', { test: 'value' } ), false );
+ assert.strictEqual( mw.storage.remove( 'bar' ), false );
} );
- QUnit.test( 'set/get with storage object disabled', function ( assert ) {
+ QUnit.test( 'set/get(Object) with storage object disabled', function ( assert ) {
// On other browsers, these entire object is disabled.
// `'localStorage' in window` would be true (and pass feature test)
// but trying to read the object as window.localStorage would throw
assert.strictEqual( mw.storage.set( 'foo', 'test' ), false );
assert.strictEqual( mw.storage.remove( 'foo', 'test' ), false );
+ assert.strictEqual( mw.storage.getObject( 'bar' ), false );
+ assert.strictEqual( mw.storage.setObject( 'bar', { test: 'value' } ), false );
+ assert.strictEqual( mw.storage.remove( 'bar' ), false );
+
mw.storage.store = old;
} );