1 /* Copyright 2014 Yukkuri Games
2 Licensed under the terms of the GNU GPL v2 or later
3 @license http://www.gnu.org/licenses/gpl-2.0.html
4 @source: http://yukkurigames.com/yuu/
10 var yT
= this.yT
|| require('./yT');
12 var FakeStorage
= exports
.FakeStorage
= yT({
13 /** Fake, ephemeral storage roughly like Web Storage
15 This is the fallback storage when permission is denied or
16 otherwise busted. It just stores a dictionary for as long as
19 constructor: function () {
23 getItem: function (key
) {
24 return (key
in this._storage
) ? this._storage
[key
] : null;
27 setItem: function (key
, value
) {
28 this._storage
[key
] = value
.toString();
31 removeItem: function (key
) {
32 delete this._storage
[key
];
40 get: function () { return Object
.keys(this._storage
).length
; }
44 // Object.keys isn't guaranteed to have a consistent order
45 // even when nothing changes, so normalize it by sorting.
46 var keys
= Object
.keys(this._storage
).sort();
47 return (n
>= 0 && n
< keys
.length
) ? keys
[n
] : null;
51 var PrefixedStorage
= exports
.PrefixedStorage
= yT({
52 /** Per-application storage roughly like Web Storage
54 This storage prefixes all keys with a special token, so you
55 can run multiple applications on the same origin without
56 the risk of conflicting keys.
58 A caveat of this approach is clear() is not atomic.
61 constructor: function (storage
, prefix
) {
62 this._storage
= storage
;
63 this._prefix
= prefix
+ " -- ";
66 _key: function (key
) {
67 return this._prefix
+ key
;
70 _unkey: function (key
) {
71 return key
.substring(this._prefix
.length
);
74 _iskey: function (key
) {
75 return key
.startsWith(this._prefix
);
82 while ((key
= this._storage
.key(i
++)) !== null)
84 keys
.push(this._unkey(key
));
88 getItem: function (key
) {
89 return this._storage
.getItem(this._key(key
));
92 setItem: function (key
, value
) {
93 return this._storage
.setItem(this._key(key
), value
);
96 removeItem: function (key
) {
97 return this._storage
.removeItem(this._key(key
));
101 this._keys().forEach(this.removeItem
, this);
105 get: function () { return this._keys().length
; }
109 var keys
= this._keys().sort();
110 return (n
>= 0 && n
< keys
.length
) ? keys
[n
] : null;
114 var Storage
= exports
.Storage
= yT({
115 /** Higher-level access to Web Storage-esque things
117 Storage lets you store and retrieve JSON-serializable
118 objects inside a Web Storage container.
120 You can specify default values. If you retrieve an object
121 that hasn't been set, you get its default value.
123 Storage automatically falls back to an ephemeral storage
124 backend if a SecurityException occurs during startup.
127 constructor: function (storage
, defaults
) {
128 this._storage
= storage
|| new FakeStorage();
129 this._defaults
= defaults
|| {};
132 this.setFlag('__ystorage__');
134 this._storage
= new FakeStorage();
135 console
.error("Unable to use provided storage:", exc
);
139 getObject: function (key
, fallbackValue
) {
140 var v
= this._storage
.getItem(key
);
142 return (key
in this._defaults
)
143 ? this._defaults
[key
]
147 return JSON
.parse(v
);
149 console
.error("Malformed storage value:", key
, v
, exc
);
150 return (key
in this._defaults
)
151 ? this._defaults
[key
]
156 setObject: function (key
, value
) {
157 this._storage
.setItem(key
, JSON
.stringify(value
));
160 removeObject
: { proxy
: '_storage.removeItem' },
162 getFlag: function (key
) {
163 return !!this.getObject(key
, false);
166 setFlag: function (key
) {
167 return this.setObject(key
, true);
170 clearFlag: function (key
) {
171 return this.setObject(key
, false);
174 clear
: { proxy
: '_storage.clear' }
177 exports
.getStorage = function (prefix
, defaults
, backend
) {
178 /** Create a Storage with prefixed access to localStorage. */
181 (document
.documentElement
.getAttribute('data-appid')
183 backend
= backend
|| localStorage
;
184 return new Storage(new PrefixedStorage(backend
, prefix
), defaults
);
187 }).call(typeof exports
=== 'undefined' ? this : exports
,
188 typeof exports
=== 'undefined' ? (this.ystorage
= {}) : exports
);