Option name | Type | Description |
---|---|---|
keyPrefix | String | prefix that will be added to all keys followed by |
sessionOnly | Boolean | true to use sessionStorage. localStorage will be used by default. |
win | Window | window to work in |
DOMStorage class to simplify storage and retrieval of multiple items with types preservation to DOM storage (localStorage and sessionStorage).
Types will be stored in the key created from value keys with appended milo.config.domStorage.typeSuffix
function DOMStorage(keyPrefix, sessionOnly, win) {
if (typeof window == 'undefined') return;
win = win || window;
keyPrefix = config.domStorage.root +
(keyPrefix
? keyPrefix + config.domStorage.prefixSeparator
: '');
_.defineProperties(this, {
keyPrefix: keyPrefix,
sessionOnly: !! sessionOnly,
window: win,
_storage: sessionOnly ? win.sessionStorage : win.localStorage,
_typeSuffix: config.domStorage.typeSuffix,
_keys: {}
}, _.WRIT);
}
_.extendProto(DOMStorage, {
get: DOMStorage$get,
set: DOMStorage$set,
remove: DOMStorage$remove,
hasItem: DOMStorage$hasItem,
getItem: DOMStorage$getItem,
setItem: DOMStorage$setItem,
removeItem: DOMStorage$removeItem,
_storageKey: DOMStorage$_storageKey,
_domStorageKey: DOMStorage$_domStorageKey,
getAllKeys: DOMStorage$getAllKeys,
getAllItems: DOMStorage$getAllItems,
createMessenger: DOMStorage$createMessenger,
destroy: DOMStorage$destroy
});
Expose Mesenger and MessageSource methods on DOMStorage
Messenger.useWith(DOMStorage, '_messenger', Messenger.defaultMethods);
StorageMessageSource.useWith(DOMStorage, '_messageSource', ['trigger']);
var _sessionStorage = new DOMStorage('', true)
, _localStorage = new DOMStorage('', false);
var _domStorage = {
true: _sessionStorage,
false: _localStorage
};
_.extend(DOMStorage, {
registerDataType: DOMStorage$$registerDataType,
local: _localStorage,
session: _sessionStorage,
storage: _domStorage,
_storedKeys: _storedKeys // exposed for testing
});
Option name | Type | Description |
---|---|---|
data | Object | single object can be passed in which case keys will be used as keys in local storage. |
arguments | List | alternatively just the list of arguments can be passed where arguments can be sequentially used as keys and values. |
Sets data to DOM storage. this.keyPrefix
is prepended to keys.
function DOMStorage$set(data) { // or arguments
if (typeof data == 'object')
_.eachKey(data, function(value, key) {
this.setItem(key, value);
}, this);
else {
var argsLen = arguments.length;
if (argsLen % 2)
throw new Error('DOMStorage: set should have even number of arguments or object');
for (var i = 0; i < argsLen; i++) {
var key = arguments[i]
, value = arguments[++i];
this.setItem(key, value);
}
}
}
Option name | Type | Description |
---|---|---|
arguments | List | keys can be passed as strings or arrays of strings |
Gets data from DOM storage. this.keyPrefix
is prepended to passed keys, but returned object will have keys without root keys.
function DOMStorage$get() { // , ... arguments
var data = {};
_.deepForEach(arguments, function(key) {
data[key] = this.getItem(key);
}, this);
return data;
}
Option name | Type | Description |
---|---|---|
arguments | List | keys can be passed as strings or arrays of strings |
Removes keys from DOM storage. this.keyPrefix
is prepended to passed keys.
function DOMStorage$remove() { //, ... arguments
_.deepForEach(arguments, function(key) {
this.removeItem(key);
}, this);
}
Option name | Type | Description |
---|---|---|
key | String | |
return | Boolean |
Check for presence of single item in DOM storage. this.keyPrefix
is prepended to passed key.
function DOMStorage$hasItem(key) {
var pKey = this._storageKey(key);
return this._storage.getItem(pKey) != null;
}
Option name | Type | Description |
---|---|---|
key | String | |
return | Any |
Gets single item from DOM storage prepending this.keyPrefix
to passed key.
Reads type of the originally stored value from key + this._typeSuffix
and converts data to the original type.
function DOMStorage$getItem(key) {
var pKey = this._storageKey(key);
var dataType = _getKeyDataType.call(this, pKey);
var valueStr = this._storage.getItem(pKey);
var value = _parseData(valueStr, dataType);
return value;
}
Option name | Type | Description |
---|---|---|
key | String | |
return | Any |
Sets single item to DOM storage prepending this.keyPrefix
to passed key.
Stores type of the stored value to key + this._typeSuffix
.
function DOMStorage$setItem(key, value) {
var pKey = this._storageKey(key);
var dataType = _setKeyDataType.call(this, pKey, value);
var valueStr = _serializeData(value, dataType);
try {
this._storage.setItem(pKey, valueStr);
} catch(e) {
if (e.name == 'QuotaExceededError') {
var cfg = config.domStorage.quotaExceeded;
if (cfg.message)
milo.mail.postMessage('quotaexceedederror', value);
if (cfg.throwError)
throw e;
} else
throw e;
}
this._keys[key] = true;
_domStorage[this.sessionOnly]._keys[pKey] = true;
}
Option name | Type | Description |
---|---|---|
key | String | |
return | Any |
Removes single item from DOM storage prepending this.keyPrefix
to passed key.
Type of the stored value (in key + this._typeSuffix
key) is also removed.
function DOMStorage$removeItem(key) {
var pKey = this._storageKey(key);
this._storage.removeItem(pKey);
_removeKeyDataType.call(this, pKey);
delete this._keys[key];
delete _domStorage[this.sessionOnly]._keys[pKey];
}
Returns the array of all keys stored by this instance of DOMStorage
function DOMStorage$getAllKeys() {
var storedKeys = Object.keys(this._keys);
var keysInStorage = storedKeys.filter(function(key) {
if (this.hasItem(key)) return true;
else delete this._keys[key];
}, this);
return keysInStorage;
}
Returns the map with all keys and values (deserialized) stored using this instance of DOMStorage
function DOMStorage$getAllItems() {
return this.get(this.getAllKeys());
}
Option name | Type | Description |
---|---|---|
key | String | |
return | String |
Returns prefixed key for DOM storage for given unprefixed key.
function DOMStorage$_storageKey(key) {
return this.keyPrefix + key;
}
Option name | Type | Description |
---|---|---|
storageKey | String | actual key in local/session storage |
return | String |
Returns unprefixed key to be used with this instance of DOMStorage fir given actual key in storage
If key has different prefix from the keyPrefix returns undefined
function DOMStorage$_domStorageKey(storageKey) {
if (storageKey.indexOf(this._typeSuffix) >= 0) return;
return _.unPrefix(storageKey, this.keyPrefix);
}
Option name | Type | Description |
---|---|---|
pKey | String | prefixed key of stored value |
return | String |
Gets originally stored data type for given (prefixed) key
.
function _getKeyDataType(pKey) {
pKey = _dataTypeKey.call(this, pKey);
return this._storage.getItem(pKey);
}
Option name | Type | Description |
---|---|---|
pKey | String | prefixed key of stored value |
value | Any | |
return | String |
Stores data type for given (prefixed) key
and value
.
Returns data type for value
.
function _setKeyDataType(pKey, value) {
var dataType = _getValueType(value);
pKey = _dataTypeKey.call(this, pKey);
this._storage.setItem(pKey, dataType);
return dataType;
}
Option name | Type | Description |
---|---|---|
pKey | String | prefixed key of stored value |
Removes stored data type for given (prefixed) key
.
function _removeKeyDataType(pKey) {
pKey = _dataTypeKey.call(this, pKey);
this._storage.removeItem(pKey);
}
Option name | Type | Description |
---|---|---|
pKey | String | prefixed key of stored value |
return | String |
Returns the key to store data type for given (prefixed) key
.
function _dataTypeKey(pKey) {
return pKey + this._typeSuffix;
}
Option name | Type | Description |
---|---|---|
value | Any | |
return | String |
Returns type of value as string. Class name returned for objects ('null' for null).
function _getValueType(value) {
var valueType = typeof value
, className = value && value.constructor.name
, dataType = valuesDataTypes[className];
return dataType || (
valueType != 'object'
? valueType
: value == null
? 'null'
: value.constructor.name);
}
var valuesDataTypes = {
// can be registered with `registerDataType`
};
Option name | Type | Description |
---|---|---|
value | Any | value to be serialized |
valueType | String | optional data type to define serializer, _getValueType is used if not passed. |
return | String |
Serializes value to be stored in DOM storage.
function _serializeData(value, valueType) {
valueType = valueType || _getValueType(value);
var serializer = dataSerializers[valueType];
return serializer
? serializer(value, valueType)
: value && value.toString == Object.prototype.toString
? JSON.stringify(value)
: '' + value;
}
var dataSerializers = {
'Array': JSON.stringify
};
Option name | Type | Description |
---|---|---|
valueStr | String | |
valueType | String | data type that defines parser. Original sring will be returned if parser is not defined. |
return | Any |
Parses string retrieved from DOM storage.
function _parseData(valueStr, valueType) {
var parser = dataParsers[valueType];
return parser
? parser(valueStr, valueType)
: valueStr;
}
var dataParsers = {
Object: _.jsonParse,
Array: _.jsonParse,
Date: function(valStr) { return new Date(valStr); },
boolean: function(valStr) { return valStr == 'true'; },
number: Number,
function: _.toFunction,
RegExp: _.toRegExp
};
Option name | Type | Description |
---|---|---|
valueType | String | class (constructor) name or the string returned by typeof. |
serializer | Function | optional serializer for this type |
parser | Function | optional parser for this type |
[storeAsDataType] | String | optional name of stored data type if different from valueType |
Registers data type to be saved in DOM storage. Class name can be used or result of typeof
operator for non-objects to override default conversions.
function DOMStorage$$registerDataType(valueType, serializer, parser, storeAsDataType) {
if (serializer) dataSerializers[valueType] = serializer;
if (parser) dataParsers[valueType] = parser;
valuesDataTypes[valueType] = storeAsDataType || valueType;
}
function DOMStorage$createMessenger() {
var storageMessageSource = new StorageMessageSource(this);
var messenger = new Messenger(this, undefined, storageMessageSource);
_.defineProperties(this, {
_messenger: messenger,
_messageSource: storageMessageSource
}, _.WRIT);
}
function DOMStorage$destroy() {
this._storage = undefined;
this.window = undefined;
if (this._messenger) this._messenger.destroy();
this._destroyed = true;
}