@livelybone/storage
Version:
A module for localStorage, support custom solution of quota exceeded. When localStorage is not supported by browser, it will be degrading to use Cookie or Map
502 lines (446 loc) • 12.1 kB
JavaScript
/**
* Bundle of @livelybone/storage
* Generated: 2020-06-03
* Version: 1.7.2
* License: MIT
* Author: 2631541504@qq.com
*/
import { singletonObj } from '@livelybone/singleton';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
/**
* @typedef { undefined|null|String|Number|Boolean|Object|Array } StorageValue
* */
/**
* @desc JSON stringify
* @param { StorageValue } val
* */
function stringifyJSON(val) {
if (typeof val === 'number') {
if (isNaN(val)) return 'NaN';
if (!isFinite(val)) return 'Infinity';
}
return JSON.stringify(val);
}
/**
* @desc JSON parse
* @param { String } val
* */
function parseJSON(val) {
try {
if (val === 'undefined') return undefined;
if (val === 'NaN') return NaN;
if (val === 'Infinity') return Infinity;
return JSON.parse(val);
} catch (e) {
return val;
}
}
function isStorageExceeded(err) {
return err.code === 22 || err.name.toLowerCase().indexOf('quota') >= 0;
}
function storageAvailable() {
try {
var storage = window.localStorage;
var x = 'storage-available';
storage.setItem(x, x);
var isAvailable = storage.getItem(x) === x;
storage.removeItem(x);
return isAvailable;
} catch (e) {
// If the error is QUOTA_EXCEEDED_ERROR
// and length of localStorage is greater than 0
// return true
return isStorageExceeded(e) && window.localStorage.length > 0;
}
}
function cookieAvailable() {
try {
return document.cookie || true;
} catch (e) {
return false;
}
}
var utils = /*#__PURE__*/Object.freeze({
stringifyJSON: stringifyJSON,
parseJSON: parseJSON,
isStorageExceeded: isStorageExceeded,
storageAvailable: storageAvailable,
cookieAvailable: cookieAvailable
});
var Cookie = /*#__PURE__*/function () {
function Cookie() {
_classCallCheck(this, Cookie);
}
_createClass(Cookie, null, [{
key: "keys",
value: function keys() {
return document.cookie.match(/[^\s=;]+(?==)/g) || [];
}
}, {
key: "values",
value: function values() {
return Cookie.keys().map(function (key) {
return Cookie.get(key);
});
}
}, {
key: "entries",
value: function entries() {
return Cookie.keys().map(function (key) {
return [key, Cookie.get(key)];
});
}
}, {
key: "forEach",
value: function forEach(callback) {
Cookie.keys().forEach(function (key) {
return callback(Cookie.get(key), key, Cookie);
});
}
/**
* @param { String } key
* @param { StorageValue } val
* @param { String|Number } [maxAgeMs]
* @param { String } [domain]
* @param { String } [secure]
* @param { String } [path]
* */
}, {
key: "set",
value: function set(key, val) {
var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
_ref$maxAgeMs = _ref.maxAgeMs,
maxAgeMs = _ref$maxAgeMs === void 0 ? 'Infinity' : _ref$maxAgeMs,
domain = _ref.domain,
secure = _ref.secure,
path = _ref.path;
var value = encodeURIComponent(stringifyJSON(val));
var cookie = "".concat(key, "=").concat(value);
var isSessionLevel = !maxAgeMs;
if (!isSessionLevel) {
var exp = new Date(); // Expired after {ms}ms
var ms = !isFinite(+maxAgeMs) ? 365 * 24 * 60 * 60 * 1000 : +maxAgeMs;
exp.setTime(exp.getTime() + ms);
var expires = exp.toUTCString(); // set expires, path, domain and secure of cookie
cookie += ";expires=".concat(expires);
}
cookie += ";path=".concat(path || '/');
if (domain) cookie += ";domain=".concat(domain);
if (secure) cookie += ";secure=".concat(secure ? 'secure' : '');
document.cookie = cookie;
}
}, {
key: "get",
value: function get(key) {
var reg = new RegExp("(^| )".concat(key, "=([^;]*)(;|$)"));
var arr = document.cookie.match(reg);
if (arr) {
return parseJSON(decodeURIComponent(arr[2]));
}
return null;
}
}, {
key: "has",
value: function has(key) {
return Cookie.keys().some(function (k) {
return k === key;
});
}
}, {
key: "delete",
value: function _delete(key) {
var has = Cookie.has(key);
if (has) {
Cookie.set(key, Cookie.get(key), {
maxAgeMs: -1
});
return true;
}
return false;
}
}, {
key: "clear",
value: function clear() {
Cookie.keys().forEach(function (key) {
Cookie.delete(key);
});
}
}, {
key: "size",
get: function get() {
return Cookie.keys().length;
}
}]);
return Cookie;
}();
var LocalStorage = /*#__PURE__*/function () {
function LocalStorage() {
_classCallCheck(this, LocalStorage);
}
_createClass(LocalStorage, null, [{
key: "keys",
value: function keys() {
return Object.keys(localStorage);
}
}, {
key: "values",
value: function values() {
return LocalStorage.keys().map(function (key) {
return LocalStorage.get(key);
});
}
}, {
key: "entries",
value: function entries() {
return LocalStorage.keys().map(function (key) {
return [key, LocalStorage.get(key)];
});
}
}, {
key: "forEach",
value: function forEach(callback) {
LocalStorage.keys().forEach(function (key) {
return callback(LocalStorage.get(key), key, LocalStorage);
});
}
}, {
key: "set",
value: function set(key, val) {
var value = stringifyJSON(val);
localStorage.setItem(key, value);
}
}, {
key: "get",
value: function get(key) {
return parseJSON(localStorage.getItem(key));
}
}, {
key: "has",
value: function has(key) {
return localStorage.getItem(key) !== null;
}
}, {
key: "delete",
value: function _delete(key) {
var has = LocalStorage.has(key);
if (has) {
localStorage.removeItem(key);
return true;
}
return false;
}
}, {
key: "clear",
value: function clear() {
localStorage.clear();
}
}, {
key: "addHandler",
value: function addHandler(storageHandler) {
if (window.addEventListener) {
var handler = function handler(e) {
storageHandler({
key: e.key,
oldValue: parseJSON(e.oldValue),
newValue: parseJSON(e.newValue),
event: e
});
};
window.addEventListener('storage', handler);
return handler;
}
return null;
}
}, {
key: "removeHandler",
value: function removeHandler(handlers) {
if (window.removeEventListener) {
var remove = function remove(handler) {
if (handler instanceof Function) window.removeEventListener('storage', handler);
};
if (handlers instanceof Array) {
handlers.forEach(remove);
} else {
remove(handlers);
}
}
}
}, {
key: "size",
get: function get() {
return LocalStorage.keys().length;
}
}]);
return LocalStorage;
}();
/**
* @class Storage
* */
var Storage = /*#__PURE__*/function () {
/**
* @typedef { Function } ExceededCallback
* @param { Error } error
* @param { Array } params params[0] => key; params[1] => value
* @param { Storage } storage
* */
/**
* @param { Boolean } useCookie Use cookie or not
* @param { ExceededCallback } [exceededCallback] Callback of QUOTA_EXCEEDED_ERROR,
* */
function Storage(useCookie, exceededCallback) {
_classCallCheck(this, Storage);
_defineProperty(this, "storage", void 0);
_defineProperty(this, "exceededCallback", void 0);
var getStorage = function getStorage() {
if (storageAvailable()) {
return LocalStorage;
}
if (typeof window !== 'undefined') {
console.warn(new Error("(Storage) The Object localStorage isn't supported in your client," + ' methods `addHandler` and `removeHandler` will do nothing when you call it'));
} // Fallback to use Cookie if useCookie is true
if (useCookie) {
var $cookieAvailable = cookieAvailable();
if ($cookieAvailable) {
return Cookie;
}
} // Fallback to use Map
return new Map();
};
this.storage = getStorage();
if (exceededCallback) this.exceededCallback = exceededCallback;
}
_createClass(Storage, [{
key: "keys",
value: function keys() {
return this.storage.keys();
}
}, {
key: "values",
value: function values() {
return this.storage.values();
}
}, {
key: "entries",
value: function entries() {
return this.storage.entries();
}
}, {
key: "forEach",
value: function forEach(callback) {
this.storage.forEach(callback);
}
}, {
key: "set",
value: function set(key, val) {
try {
this.storage.set(key, val);
} catch (e) {
if (isStorageExceeded(e) && this.exceededCallback) {
this.exceededCallback(e, [key, val], this);
} else throw e;
}
}
}, {
key: "get",
value: function get(key) {
return this.storage.get(key);
}
}, {
key: "has",
value: function has(key) {
return this.storage.has(key);
}
}, {
key: "delete",
value: function _delete(key) {
return this.storage.delete(key);
}
}, {
key: "clear",
value: function clear() {
this.storage.clear();
}
}, {
key: "addHandler",
value: function addHandler(storageHandler) {
if (this.storage.addHandler) {
return this.storage.addHandler(storageHandler);
}
return null;
}
}, {
key: "removeHandler",
value: function removeHandler(handlers) {
if (this.storage.removeHandler) this.storage.removeHandler(handlers);
}
}, {
key: "size",
get: function get() {
return this.storage.size;
}
}]);
return Storage;
}();
var StorageItem = /*#__PURE__*/function () {
function StorageItem(key, isCookie) {
_classCallCheck(this, StorageItem);
_defineProperty(this, "key", '');
_defineProperty(this, "storage", void 0);
this.key = key;
this.storage = isCookie ? Cookie : singletonObj('storage', function () {
return new Storage(StorageItem.StorageOptions.useCookie, StorageItem.StorageOptions.exceededCallback);
});
}
_createClass(StorageItem, [{
key: "set",
value: function set(val) {
this.storage.set(this.key, val);
}
}, {
key: "get",
value: function get() {
return this.storage.get(this.key);
}
}, {
key: "del",
value: function del() {
return this.storage.delete(this.key);
}
}]);
return StorageItem;
}();
_defineProperty(StorageItem, "StorageOptions", {
useCookie: true
});
export { Cookie, LocalStorage, Storage, StorageItem, utils as StorageUtils };