Commit 8b8ac608 authored by Sean Hammond's avatar Sean Hammond Committed by GitHub

Merge pull request #443 from hypothesis/local-storage-decaf

Convert localStorage service to JS
parents e1388ab4 5e1c1910
module.exports = ['$window', ($window) ->
# Detection is needed because we run often as a third party widget and
# third party storage blocking often blocks cookies and local storage
# https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js
storage = do ->
key = 'hypothesis.testKey'
try
$window.localStorage.setItem key, key
$window.localStorage.removeItem key
$window.localStorage
catch
memoryStorage = {}
getItem: (key) ->
if key of memoryStorage then memoryStorage[key] else null
setItem: (key, value) ->
memoryStorage[key] = value
removeItem: (key) ->
delete memoryStorage[key]
return {
getItem: (key) ->
storage.getItem key
getObject: (key) ->
json = storage.getItem key
return JSON.parse json if json
null
setItem: (key, value) ->
storage.setItem key, value
setObject: (key, value) ->
repr = JSON.stringify value
storage.setItem key, repr
removeItem: (key) ->
storage.removeItem key
}
]
'use strict';
/**
* Fallback in-memory store if `localStorage` is not read/writable.
*/
class InMemoryStorage {
constructor() {
this._store = {};
}
getItem(key) {
return (key in this._store) ? this._store[key] : null;
}
setItem(key, value) {
this._store[key] = value;
}
removeItem(key) {
delete this._store[key];
}
}
/**
* A wrapper around the `localStorage` API which provides a fallback to
* in-memory storage in browsers that block access to `window.localStorage`.
* in third-party iframes.
*/
// @ngInject
function localStorage($window) {
var storage = $window.localStorage;
try {
// Test whether we can read/write localStorage.
var key = 'hypothesis.testKey';
$window.localStorage.setItem(key, key);
$window.localStorage.getItem(key);
$window.localStorage.removeItem(key);
} catch (e) {
storage = new InMemoryStorage();
}
return {
getItem(key) {
return storage.getItem(key);
},
getObject(key) {
var item = storage.getItem(key);
return item ? JSON.parse(item) : null;
},
setItem(key, value) {
storage.setItem(key, value);
},
setObject(key, value) {
var repr = JSON.stringify(value);
storage.setItem(key, repr);
},
removeItem(key) {
storage.removeItem(key);
},
};
}
module.exports = localStorage;
{module, inject} = angular.mock
describe 'localStorage', ->
fakeWindow = null
sandbox = null
before ->
angular.module('h', [])
.service('localStorage', require('../local-storage'))
beforeEach module('h')
describe 'memory fallback', ->
localStorage = null
key = null
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
fakeWindow = {
localStorage: {}
}
$provide.value '$window', fakeWindow
return
afterEach ->
sandbox.restore()
beforeEach inject (_localStorage_) ->
localStorage = _localStorage_
key = 'test.memory.key'
it 'sets/gets Item', ->
value = 'What shall we do with a drunken sailor?'
localStorage.setItem key, value
actual = localStorage.getItem key
assert.equal value, actual
it 'removes item', ->
localStorage.setItem key, ''
localStorage.removeItem key
result = localStorage.getItem key
assert.isNull result
it 'sets/gets Object', ->
data = {'foo': 'bar'}
localStorage.setObject key, data
stringified = localStorage.getItem key
assert.equal stringified, JSON.stringify data
actual = localStorage.getObject key
assert.deepEqual actual, data
describe 'browser localStorage', ->
localStorage = null
beforeEach module ($provide) ->
sandbox = sinon.sandbox.create()
fakeWindow = {
localStorage: {
getItem: sandbox.stub()
setItem: sandbox.stub()
removeItem: sandbox.stub()
}
}
$provide.value '$window', fakeWindow
return
afterEach ->
sandbox.restore()
beforeEach inject (_localStorage_) ->
localStorage = _localStorage_
it 'uses window.localStorage functions to handle data', ->
key = 'test.storage.key'
data = 'test data'
localStorage.setItem key, data
assert.calledWith fakeWindow.localStorage.setItem, key, data
'use strict';
var angular = require('angular');
describe('sidebar.localStorage', () => {
var fakeWindow;
before(() =>
angular.module('h', [])
.service('localStorage', require('../local-storage'))
);
context('when browser localStorage is *not* accessible', () => {
var localStorage = null;
var key = null;
beforeEach(() => {
angular.mock.module('h', {
$window: {
localStorage: {},
},
});
});
beforeEach(angular.mock.inject((_localStorage_) => {
localStorage = _localStorage_;
key = 'test.memory.key';
}));
it('sets/gets Item', () => {
var value = 'What shall we do with a drunken sailor?';
localStorage.setItem(key, value);
var actual = localStorage.getItem(key);
assert.equal(value, actual);
});
it('removes item', () => {
localStorage.setItem(key, '');
localStorage.removeItem(key);
var result = localStorage.getItem(key);
assert.isNull(result);
});
it('sets/gets Object', () => {
var data = {'foo': 'bar'};
localStorage.setObject(key, data);
var stringified = localStorage.getItem(key);
assert.equal(stringified, JSON.stringify(data));
var actual = localStorage.getObject(key);
assert.deepEqual(actual, data);
});
});
context('when browser localStorage is accessible', () => {
var localStorage;
beforeEach(() => {
fakeWindow = {
localStorage: {
getItem: sinon.stub(),
setItem: sinon.stub(),
removeItem: sinon.stub(),
},
};
angular.mock.module('h', {
$window: fakeWindow,
});
});
beforeEach(() => {
angular.mock.inject(_localStorage_ => localStorage = _localStorage_);
});
it('uses window.localStorage functions to handle data', () => {
var key = 'test.storage.key';
var data = 'test data';
localStorage.setItem(key, data);
assert.calledWith(fakeWindow.localStorage.setItem, key, data);
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment