Giter VIP home page Giter VIP logo

store.js's Introduction

Store.js

Cross-browser storage for all use cases, used across the web.

Circle CI npm version npm

Store.js has been around since 2010 (first commit, v1 release). It is used in production on tens of thousands of websites, such as cnn.com, dailymotion.com, & many more.

Store.js provides basic key/value storage functionality (get/set/remove/each) as well as a rich set of plug-in storages and extra functionality.

  1. Basic Usage
  2. Supported Browsers
  3. Plugins
  4. Builds
  5. Storages

Basic Usage

All you need to know to get started:

API

store.js exposes a simple API for cross-browser local storage:

// Store current user
store.set('user', { name:'Marcus' })

// Get current user
store.get('user')

// Remove current user
store.remove('user')

// Clear all keys
store.clearAll()

// Loop over all stored values
store.each(function(value, key) {
	console.log(key, '==', value)
})

Installation

Using npm:

npm i store
// Example store.js usage with npm
var store = require('store')
store.set('user', { name:'Marcus' })
store.get('user').name == 'Marcus'

Using script tag (first download one of the builds):

<!-- Example store.js usage with script tag -->
<script src="path/to/my/store.legacy.min.js"></script>
<script>
store.set('user', { name:'Marcus' })
store.get('user').name == 'Marcus'
</script>

Supported Browsers

All of them, pretty much :)

To support all browsers (including IE 6, IE 7, Firefox 4, etc.), use require('store') (alias for require('store/dist/store.legacy')) or store.legacy.min.js.

To save some kilobytes but still support all modern browsers, use require('store/dist/store.modern') or store.modern.min.js instead.

List of supported browsers

Plugins

Plugins provide additional common functionality that some users might need:

List of all Plugins

Using Plugins

With npm:

// Example plugin usage:
var expirePlugin = require('store/plugins/expire')
store.addPlugin(expirePlugin)

If you're using script tags, you can either use store.everything.min.js (which has all plugins built-in), or clone this repo to add or modify a build and run make build.

Write your own plugin

A store.js plugin is a function that returns an object that gets added to the store. If any of the plugin functions overrides existing functions, the plugin function can still call the original function using the first argument (super_fn).

// Example plugin that stores a version history of every value
var versionHistoryPlugin = function() {
	var historyStore = this.namespace('history')
	return {
		set: function(super_fn, key, value) {
			var history = historyStore.get(key) || []
			history.push(value)
			historyStore.set(key, history)
			return super_fn()
		},
		getHistory: function(key) {
			return historyStore.get(key)
		}
	}
}
store.addPlugin(versionHistoryPlugin)
store.set('foo', 'bar 1')
store.set('foo', 'bar 2')
store.getHistory('foo') == ['bar 1', 'bar 2']

Let me know if you need more info on writing plugins. For the moment I recommend taking a look at the current plugins. Good example plugins are plugins/defaults, plugins/expire and plugins/events.

Builds

Choose which build is right for you!

List of default builds

Make your own Build

If you're using npm you can create your own build:

// Example custom build usage:
var engine = require('store/src/store-engine')
var storages = [
	require('store/storages/localStorage'),
	require('store/storages/cookieStorage')
]
var plugins = [
	require('store/plugins/defaults'),
	require('store/plugins/expire')
]
var store = engine.createStore(storages, plugins)
store.set('foo', 'bar', new Date().getTime() + 3000) // Using expire plugin to expire in 3 seconds

Storages

Store.js will pick the best available storage, and automatically falls back to the first available storage that works:

List of all Storages

Storages limits

Each storage has different limits, restrictions and overflow behavior on different browser. For example, Android has has a 4.57M localStorage limit in 4.0, a 2.49M limit in 4.1, and a 4.98M limit in 4.2... Yeah.

To simplify things we provide these recommendations to ensure cross browser behavior:

Storage Targets Recommendations More info
all All browsers Store < 1 million characters (Except Safari Private mode)
all All & Private mode Store < 32 thousand characters (Including Safari Private mode)
localStorage Modern browsers Max 2mb (~1M chars) limits, android
sessionStorage Modern browsers Max 5mb (~2M chars) limits
cookieStorage Safari Private mode Max 4kb (~2K chars) limits
userDataStorage IE5, IE6 & IE7 Max 64kb (~32K chars) limits
globalStorage Firefox 2-5 Max 5mb (~2M chars) limits
memoryStorage All browsers, fallback Does not persist across pages!

Write your own Storage

Chances are you won't ever need another storage. But if you do...

See storages/ for examples. Two good examples are memoryStorage and localStorage.

Basically, you just need an object that looks like this:

// Example custom storage
var storage = {
	name: 'myStorage',
	read: function(key) { ... },
	write: function(key, value) { ... },
	each: function(fn) { ... },
	remove: function(key) { ... },
	clearAll: function() { ... }
}
var store = require('store').createStore(storage)

store.js's People

Contributors

afc163 avatar aimwhy avatar blq avatar deepred5 avatar jackfranklin avatar jakobud avatar jrbotros avatar kafene avatar krizzu avatar lfac-pt avatar m19c avatar marcuswestin avatar matthewmueller avatar mjpizz avatar mortonfox avatar mosch avatar paladox avatar per-gron avatar prayagverma avatar rmg avatar robinator avatar ryankirkman avatar stevenblack avatar termosa avatar tombyrer avatar tschaub avatar w33ble avatar whitehat101 avatar willium avatar xuefeng-zhu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

store.js's Issues

test fails in IE7

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

Feature Request: Object Watching

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.

Any plans for FireFox 4 support?

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

AMD implementation breaks sites

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.

git tag

where is tag v1.3.4 and v1.3.5?

please tag it.

store.get('randomKey') fails because JSON.parse('') raises syntax error

--- 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)
        }

Performance issue on Safari/iOS iPad 3

It seems the initialisation of the store is really slow on Safari/iOS

How to reproduce:

  • I create a basic page cached with appcache
  • onLoad I call store.get() and update a using innerHTML.

=> 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 ??

  • Is there best practices ?
  • Is there a tips on iOS ?
  • May be the first access of appcache slow down the process ?

Using the set method on IE8 sometimes results in a crash (forced browser shutdown)

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.

set and get w/ JSON enhancement

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 :-)

Wrapper through __defineGetter__ and __defineSetter__

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!

IE10 Failing

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.

Add hook for storage event

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.

Closing iframe with frame tag?

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?

store.js and IE9

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?

Error in line 49 in FF 3.6.13

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.

Issues with Safari (iOS and Mac) when in Private Browsing mode

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…

IE 7 throws error if number, or string starting with number, is used as key

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.

IE10 Failing by HierarchyRequestError

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)

Support for sessionStorage?

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.

Update store.min.js and store+json2 files

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?

Safari Private browsing mode appears to support localStorage, but doesn't

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.

Feature request: Encrypted storage

Goal

Use encryption for storing data for non-public app areas.

Description

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

Implementation

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.

.get returning default

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?

exists(key) function

It would be useful to have a store.exists("somekey") function that returns true/false. Getter function can be used but it includes parsing.

Type munge

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?

IE6/IE7 data storage cannot be shared among pages on different paths of the same domain

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.

Synchronisation with server

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.