marcuswestin / store.js Goto Github PK
View Code? Open in Web Editor NEWCross-browser storage for all use cases, used across the web.
License: MIT License
Cross-browser storage for all use cases, used across the web.
License: MIT License
Hi,
I would be interested in implementing 'sync with server' functionality for a Key/Value store such as Redis/Memcached, possibly even MongoDB/CouchDB too.
Why? One of the main uses of localStorage is to hold user inputted data locally incase of an unexpected interrupt that forces the browser or input device to crash. Holding the data in localStorage then allows the user to quickly resume to what they were doing without loosing already inputted data.
I feel providing a sync helper method that produces a PUT/POST RESTful request to a URL would be fantastic functionality for this library.
Jacob.
Use encryption for storing data for non-public app areas.
As far as I know, browsers store DOM storage on disk in unencrypted files, DOM storage is accessible from all domain paths (except IE UserData) and doesn't expire.
This may be considered as security issue on shared workstations in cases when client-side app doesn't clear user data (browser crash/ closed window) or browser decides to keep them (temporary files).
I see the simplest solution in encrypting storage data after serializing to JSON and decrypt before deserializing.
It's up to the developer to come up with idea how to obtain secure key/ token; assuming encrypted storage makes sense for non-public areas (user is logged in), one can possibly use server-side unique session token.
Once server-side session expires, token is not available anymore. When there is no token, previously saved data theoretically become undecryptable junk (and may be removed client-side on next execution).
This should limit access to user data.
Drawback: Storage values take quite more space (depends on encoding);
Inspiration: dojo.storage.encrypted
Configuration for Crypto.js, but any crypt library with methods encrypt( value )
and decrypt( encrypted )
should work:
store.crypt = {
key: App.token, // ie. 'c015dc1d6028a6815ac944c8512c10db',
encrypt: function( plaintext ) {
return CryptoJS.AES.encrypt( plaintext, this.key ).toString();
},
decrypt: function( encrypted ) {
return CryptoJS.AES.decrypt( encrypted, this.key ).toString( CryptoJS.enc.Utf8 );
}
}
Proposed changes to store.js code (didn't test):
store.serialize = function(value) {
var serialized = JSON.stringify( value );
if ( store.crypt ) { serialized = store.crypt.encrypt( serialized ); }
return serialized;
}
store.deserialize = function(value) {
if ( typeof value !== 'string' ) { return undefined; }
if ( store.crypt )
{
try {
value = store.crypt.decrypt( value );
} catch (e) {
return undefined;
}
}
return JSON.parse( value );
}
I'd like to discuss this idea with more proficient developers as I don't have much experience with client-side encryption.
The IE version of the store.forEach function uses an undeclared "ret" variable when calling the callback (at about line 146).
Regards
/ Fredrik Blomqvist
It seems Private Browsing makes localStorage read only:
http://spin.atomicobject.com/2013/01/23/ios-private-browsing-localstorage/
When loading store.js, I get this error:
QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota.
I saw these lines in the lib:
try {
store.set(namespace, namespace)
if (store.get(namespace) != namespace) { store.disabled = true }
store.remove(namespace)
} catch(e) {
store.disabled = true
}
Maybe there's something to improve there…
If you include store.js after require.js, you get the require.js error: http://requirejs.org/docs/errors.html#mismatch
I didn't spend much time fussing with it, but I thought it worth jotting down.
Does someone know if store.js supports the old Android browsers? It would be good to know since Android 2.3 still has 38% market share (see http://developer.android.com/about/dashboards/index.html). I run the test page on my phone (HTC Desire HD, Android 2.3.5) and the tests passed. Does anyone have more test results?
According to this: http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
The max per document is 128kb for IE6 and 7. But in your documentation you state the limit as 1MB.
Do you do something behind the scenes or is it a missprint?
Thanks!
/J
In modernizr, I first used the detection you've got, but found it breaks in FF in some cases.
As a result i've switched to what you'll see here:
http://github.com/Modernizr/Modernizr/blob/master/modernizr.js#L622
Would be nice to find a way to use JSON.stringify & JSON.parse internally to allow for something like the following:
store.set('user', {name: 'jeff'});
var myobj = store.get('user');
set could detect whether the value is an object and then JSON.stringify
get could attempt a JSON.parse and simply return a string on an exception.
In any case, nice lib :-)
It appears that the userData
method used in IE6 and IE7 only stores data associated with the current path, i.e. data stored when on www.example.com/path1 is not accessible from www.example.com/path2 and vice-versa. Additionally, data stored at www.example.com/path1 is not available to subpaths (e.g. www.example.com/path1/subpath1).
There may be a way around this using the document body of an ActiveXObject("htmlfile")
instead of the current document body. In the meantime, this caveat seems important enough to note in the README for IE6/IE7 storage.
I'm aware that it isn't listed under supported browsers.
But I'm still hoping for support. It DOES work for Chrome 11 and that's not listed either.
I do get the following when running tests.html in FireFox4:
tests for store.js
first pass bad assert: Tests should not throw: "{"message":"store is not defined","fileName":"file:///Users/Jocke/Sites/peka/test.html","lineNumber":33,"stack":"doFirstPass()@file:///Users/Jocke/Sites/peka/test.html:33\u000a()@file:///Users/Jocke/Sites/peka/test.html:95\u000a@file:///Users/Jocke/Sites/peka/test.html:17\u000a"}"
Thanks!
/J
Hi there,
Testing this in IE7 on Vista (VPC environment downloaded from MS http://www.microsoft.com/download/en/details.aspx?id=11575) I get "Permission denied". Could it be that the workaround for the path limitation of UserData behavior, isn't working on IE7?
Callstack:
at http://xx.x.x.xxx/storejstest/store.js [xxx]
JScript anonymous function
code: storageOwner.appenChild(storage)
at [2]
JScript global code
code: store.set('testkey', 'test value')
I think it would be useful to have .get take an optional param which is returned iff the requested key is missing (or has an undefined value).
Agree?
There's no license file at http://github.com/marcuswestin/store.js/raw/master/LICENSE although package.json claims so. Looks like this is MIT but having a LICENSE file would clarify the situation.
Is there any interest from anyone else in support for sessionStorage as an alternative to localStorage?
There are times when I just want to keep the data for the browser session. Mostly logged-in user info for a client side app.
Hello,
Could we improve store.js creating a wrapper through defineGetter and defineSetter for code like this?
store.user = {name:'Foo'}
// Open browser
alert(store.user.name); // Show's 'Foo'
I have tried with this:
store.__defineGetter__('user',function(){return this.get('user')});
store.__defineSetter__('user',function(val){return this.set('user',val)});
You could add these definitions in get and set functions.
What do you think?
Thanks!
It seems the initialisation of the store is really slow on Safari/iOS
How to reproduce:
=> On Chrome, the page is "instant" I only see a little flicks
=> On iPad3 / Safari, I have to wait 4 seconds until the page is updated
=> Next get/set are fast
According to this article (http://hacks.mozilla.org/2012/03/there-is-no-simple-solution-for-local-storage/) local storage is slow but I didn't think so much ??
I'm getting error "HierarchyRequestError" in Internet Explorer 10 on Windows 7.
Console shows that error occured on line 98.
The statement is shown below.
storageOwner.appendChild(storage)
Thought I'd post a heads up for an issue I stumbled upon when browsing the Amplifiy store component.
"Failing storage tests on IE for Windows Phone 7"
mikehostetler/amplify#17
Though I haven't verified this myself yet.
Right now looking at the code I have to guess which browser was implementing what code in the source. Would be nice to add comment per segment for ease of future modifications.
Is there a reason for closing iframe
tag with frame
on line 77 of store.js?
<iframe src="/favicon.ico"></frame>
This causes trouble in IE7 - it hangs while loading page.
Tried changing first tag to frame
and it works, but I'm not sure if there was some reason for doing it with different tags?
the getAll function fails in IE7
test reports the error message
first pass bad assert: Tests should not throw: "{"message":"Object doesn't support this property or method","number":-2146827850,"description":"Object doesn't support this property or method"}"
I added some tracing to narrow it down and it gets to getAll call but in the getAll function the typeof storage.load is unknown
I finally found store.js while researching strange Javascript errors that I've encountered in my logs for some time now.
It seems like some quite popular Chrome plugin uses store.js, so it gets executed on my site even though I do not use store.js myself.
The problem is that store.js breaks my site! It confuses Dojo's AMD loader (and probably any other AMD loader too) when being loaded via a script tag in an AMD environment.
So when a page or browser plugin includes it via <script src="store.min.js"></script>
when e.g. the Dojo Toolkit was loaded before, store.js will call define(store)
, but the AMD loader will be unable to find out where that define came from and cannot determine any module ID. It will then fall back to the last used module ID, which can break things quite heavily.
So define(store)
should be changed to define('store', store)
to provide an explicit module ID.
Right now, this is false in Chrome:
store.set('x', 1) == store.get('x')
because Number 1, when stored, is coerced to a string. (Similarly, objects are coerced to "[object Object]".
How about testing for a JSON object and serializing with that?
IE fails if the key starts with a number!
Please add the following line to the ieKeyFix
:
.replace(/^d/, '___$&')
Say I've done the following:
store.set('123456', { name: 'marcus', likes: 'javascript' })
store.set('222222', { name: 'george', likes: 'ruby' })
Is it possible to search all items where the name matches 'george'? Thanks!
It would be useful to have a store.exists("somekey") function that returns true/false. Getter function can be used but it includes parsing.
Would it be possible to add a way to hook into the HTML5 storage
event with this library?
Demo of the functionality I'm looking for (but doesn't use store.js, obviously).
I'm thinking something like:
// All Windows / Tabs:
store.on('keyName', function(s){
console.log(s.newValue);
});
// Window / Tab 1:
store.set('keyName', 'testValue');
// All other Windows / Tabs:
// 'testValue' is logged.
I'm implementing my own solution for this with the following code:
// All Windows / Tabs:
// Hook into the storage event
$(window).on('storage', function(e){
// Keys we actually care about.
var keys = ['timeStamp', 'key', 'oldValue', 'newValue', 'url'], newEvent = {};
e = e.originalEvent; // jQuery puts the original event here
for (var i in keys) {
i = keys[i];
if (i.substr(3) === 'Value') {
// Get the value back just like we put it into store.set()
newEvent[i] = store.deserialize(e[i]);
} else {
newEvent[i] = e[i];
}
}
// Send the event to global listeners that want to know about all storage changes.
newEvent.type = 'localStorage';
$(document).trigger(newEvent);
// Send the event to listeners for this key only.
newEvent.type = newEvent.key + '.localStorage';
$(document).trigger(newEvent);
});
$(document).on('keyName.localStorage', function(e){console.log(e.newValue);});
// Window / Tab 1:
store.set('keyName', 'testValue');
// All other Windows / Tabs:
// 'testValue' is logged.
This seems like the perfect addition to this library. It would make cross-window/tab communication with store.js dead-simple. Want all of your web app tabs to know you just got a new message in the current tab? Just call store.set('newMessage', 'hey!');
.
Of course, it would only work when localStorage is supported, but it would be easy enough to indicate in the .on()
function's return value whether or not listening is enabled.
I can submit a pull request if you're interested.
I suppose it actually uses window.name
. If so, that should be made clearer. Also some code may rely on changing window.name
, and such behavior supposedly will break store.js.
For debugging purposes.
First, thanks for a great lib!
Maybe not an issue with store.js per se but is it correct that IE9 + store.js can't persist data between closing/starting browser?
localStorage["foo"] = "bar" in IE9 console isn't persisted if I close the browser either so I guess that's just how IE9 works.. which is kind of bad. Do you know anything more about this or maybe a possible way around it?
The test page http://marcuswestin.github.io/store.js/test.html shows an error when run on Android 4.2 / Chrome 27:
first pass bad assert: Tests should not throw: "{}"
Do you need further information? Could someone test with chrome 27 on a computer? Maybe its a Chrome 27 problem and has nothing to do with Android...
Do you need more information? I could try to connect the developer console with Chrome on my device.
thanks.
This is not easy to reproduce. I had your library working fine, and then at some point it started to crash on my every time I use the set method. It is clearly an IE issue and not an issue with your library because an FF-IE8-only-library that I was using before was also ocasinally the same behavior. I though people using local storage should be aware of a potential problem with IE.
If you attempt to use a number, or a string starting with a number, as a key, then IE 7 will throw an error, e.g.
This name may not begin with the '1' character
I’m not sure if using numbers or strings starting with numbers as keys is meant to be supported, but it seems to work in IE 8 and other browsers.
Test page:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="store.js"></script>
<title>Test store.js</title>
</head>
<body>
<button onclick="store.set('string', 'value');"><code>store.set('string', 'value')</code></button>
<button onclick="store.set('123456', 'value');"><code>store.set('123456', 'value')</code></button>
<button onclick="store.set(123456, 'value');"><code>store.set(123456, 'value')</code></button>
<br>
<br>
<button onclick="alert(store.get('string', 'value'));"><code>store.get('string', 'value')</code></button>
<button onclick="alert(store.get('123456', 'value'));"><code>store.get('123456', 'value')</code></button>
<button onclick="alert(store.get(123456, 'value'));"><code>store.get(123456, 'value')</code></button>
</body>
</html>
I’ve worked around the issue by patching store.js to append 'string_' to the key within the get(), set() and remove() functions passed to withIEStorage(), but I’m not sure if this is optimal.
on line 16 did you mean to call api.set instead of store.set, or was there a reason for calling store.set?
fiddlejs.net in ie7
store.set('/blah', [1,2,3]);
store.get('/blah');
i cache json search results in my site by the request path. if you'd like me to submit a fix, I can.
When I call
var user = store.get("user");
if(user !== undefined) {do stuff}
without previously calling
store.set("user", {});
javascript stops and nothing happens. That is annoying.
Hi Marcus,
Line 49 in Store.js
49 if (localStorageName in win && win[localStorageName]) {
crashes with "Security error code: 1000" if the following option is set in About:Config
dom.storage.enabled : false
Specifically, it is the segment
win[localStorageName]
that causes this to barf.
So we need a more reliable way to test for this.
I admit I'm tremendously stupid for using one of those minified files without checking wether they are uptodate, but please could you update them for all those other careless code monkeys?
where is tag v1.3.4 and v1.3.5?
please tag it.
Hello!
The storage capacities/restrictions per browser you can see on http://dev-test.nemikor.com/web-storage/support-test/
try {
localStorage.setItem('foo', 'bar');
} catch (e) {
console.log(e);
}
}
Apparently this is by design. When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage is available, but trying to call .setItem throws an exception.
store.js line 73
"QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."
What happens is that the window object still exposes localStorage in the global namespace, but when you call setItem, this exception is thrown. Any calls to .removeItem are ignored.
I believe the simplest fix (although I haven't tested this cross browser yet) would be to alter the function isLocalStorageNameSupported() to test that you can also set some value.
currently:
function isLocalStorageNameSupported() {
try { return (localStorageName in win && win[localStorageName]) }
catch(err) { return false }
}
proposed:
function isLocalStorageNameSupported() {
try {
var supported = (localStorageName in win && win[localStorageName]);
if (supported) { localStorage.setItem("storage", ""); localStorage.removeItem("storage");
return supported;
}
catch(err) { return false }
}
Of course it's kind of silly to call this every time you want to check that storage is supported, so you could memoize it, but you get the idea.
Those browsers are expired and it's not worth the byte tax you're forcing on everyone else :)
--- a/vendor/store.js
+++ b/vendor/store.js
@@ -44,7 +44,7 @@ var store = (function(){
return JSON.stringify(value)
}
api.deserialize = function(value) {
- if (typeof value != 'string') { return undefined }
+ if (typeof value != 'string' || !value) { return undefined }
return JSON.parse(value)
}
I'm getting error "Unable to get property 'appendChild' of undefined or null reference" in Internet Explorer 10 on Windows 8 ... seems to be an issue with the frame storage detection.
It'd be really awesome if we could completely drop the need for localStorage.getItem/setItem and store.get/set.
Looking at https://gist.github.com/384583, it looks like it'd be possible to bind an object directly to localStorage. In practice, you could simply associate a few objects with their localStorage keys and then have a field day; no need to worry about get/store ever again. All you'd need to know is that it's an object and it's always up to date.
In other words, this would be unfathomably awesome.
Perhaps you could use one of the node localStorage options, like https://github.com/coolaj86/node-localStorage or https://github.com/lmaccherone/node-localstorage ?
Getting this error in Bower:
mismatch The version specified in the component.json of package store.js mismatches the tag (1.3.8 vs 1.3.7)
mismatch You should report this problem to the package author
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.