ngx-store
Version:
Angular decorators to automagically keep variables in HTML5 LocalStorage, SessionStorage, cookies; injectable services for managing and listening to data changes and a bit more.
1,061 lines (1,039 loc) • 36.7 kB
JavaScript
import { Debugger } from 'ts-debug';
import { filter, delay, map } from 'rxjs/operators';
import merge from 'lodash.merge';
import { Subject, interval, merge as merge$1, fromEvent } from 'rxjs';
import { Injectable, NgModule } from '@angular/core';
const CONFIG_PREFIX = 'NGX-STORE_';
class ConfigHelper {
static getItem(key) {
return localStorage.getItem(CONFIG_PREFIX + key);
}
static setItem(key, item) {
return localStorage.setItem(CONFIG_PREFIX + key, item);
}
}
const DefaultConfig = {
prefix: 'ngx_',
previousPrefix: 'angular2ws_',
clearType: 'prefix',
mutateObjects: true,
cookiesScope: '',
cookiesCheckInterval: 0,
debugMode: false,
};
let ConfigFills = {};
const localStoragePrefix = ConfigHelper.getItem('prefix');
if (typeof NGXSTORE_CONFIG === 'object') {
ConfigFills = Object.assign({}, NGXSTORE_CONFIG);
}
if (localStoragePrefix !== undefined && localStoragePrefix !== null) {
ConfigFills.previousPrefix = localStoragePrefix;
}
else if (ConfigFills.previousPrefix === undefined) {
ConfigFills.previousPrefix = DefaultConfig.previousPrefix;
}
// merge default config, deprecated config and global config all together
const Config = Object.assign({}, DefaultConfig, ConfigFills);
const debug = new Debugger(console, Config.debugMode, '[ngx-store] ');
ConfigHelper.setItem('prefix', Config.prefix);
const isEqual = require('lodash.isequal');
class Cache {
static getCacheFor(cacheCandidate) {
let cacheItem = Cache.get(cacheCandidate.key);
if (!cacheItem) {
cacheItem = new CacheItem(cacheCandidate);
debug.log(`Created new CacheItem for ${cacheCandidate.name} for ${cacheItem.utilities[0].utility.getStorageName()}`);
Cache.set(cacheItem);
return cacheItem;
}
debug.log(`Loaded prior CacheItem of ${cacheItem.name}
for ${cacheCandidate.utilities[0].utility.getStorageName()}`);
cacheItem.addTargets(cacheCandidate.targets);
cacheItem.addServices(cacheCandidate.services);
cacheItem.addUtilities(cacheCandidate.utilities);
Cache.set(cacheItem);
return cacheItem;
}
static remove(cacheItem) {
return Cache.items.delete(cacheItem.key);
}
static get(key) {
return Cache.items.get(key);
}
static set(cacheItem) {
if (!Cache.get(cacheItem.key)) {
debug.log('CacheItem for ' + cacheItem.key, cacheItem);
}
Cache.items.set(cacheItem.key, cacheItem);
}
}
Cache.items = new Map();
// tslint:disable:only-arrow-functions
class CacheItem {
constructor(cacheItem) {
this.name = '';
this.targets = [];
this.services = [];
this.utilities = [];
this.currentTarget = {};
this.proxy = null;
this._key = '';
this.initializedTargets = new Set();
this._key = cacheItem.key;
this.name = cacheItem.name;
this.addTargets(cacheItem.targets);
this.addServices(cacheItem.services);
this.addUtilities(cacheItem.utilities);
}
get key() {
return this._key;
}
saveValue(value, config = {}) {
debug.groupCollapsed('CacheItem#saveValue for ' + this.key + ' in ' + this.currentTarget.constructor.name);
debug.log('new value: ', value);
// if (value === false && this.readValue() === true) debugger;
debug.log('previous value: ', this.readValue());
debug.log('targets.length: ', this.targets.length);
debug.log('currentTarget:', this.currentTarget);
debug.groupEnd();
// prevent overwriting value by initializators
if (!this.initializedTargets.has(this.currentTarget)) {
this.initializedTargets.add(this.currentTarget);
let readValue = this.readValue();
if (config.migrateKey) {
this.migrate(config, this.utilities[0].utility);
readValue = this.readValue();
}
const savedValue = (readValue !== null && readValue !== undefined) ? readValue : value;
let proxy = this.getProxy(savedValue, config);
proxy = (proxy !== null) ? proxy : value;
debug.log('initial value for ' + this.key + ' in ' + this.currentTarget.constructor.name, proxy);
this.propagateChange(savedValue);
return proxy;
}
this.propagateChange(value);
return this.getProxy(value, config);
}
getProxy(value, config = {}) {
if (value === undefined && this.proxy) {
return this.proxy;
} // return cached proxy if value hasn't changed
value = (value === undefined) ? this.readValue() : value;
if (typeof value !== 'object' || value === null) {
this.proxy = value;
return value;
}
if ((!Config.mutateObjects && !config.mutate) || config.mutate === false) {
return value;
}
const _self = this; // alias to use in standard function expressions
const prototype = Object.assign(new value.constructor(), value.__proto__);
prototype.save = function () {
_self.saveValue(value, config);
};
// TODO set prototype for Array.prototype or something
if (Array.isArray(value)) { // handle methods that could change value of array
const methodsToOverwrite = [
'pop', 'push', 'reverse', 'shift', 'unshift', 'splice',
'filter', 'forEach', 'map', 'fill', 'sort', 'copyWithin',
];
for (const method of methodsToOverwrite) {
prototype[method] = function () {
const readValue = _self.readValue();
// @ts-ignore
const result = Array.prototype[method].apply(readValue, arguments);
debug.log('Saving value for ' + _self.key + ' by method '
+ prototype.constructor.name + '.' + method);
_self.saveValue(readValue, config);
return result;
};
}
}
Object.setPrototypeOf(value, prototype);
this.proxy = value;
return value;
}
readValue(config = {}) {
const entry = this.utilities[0];
const value = entry ? entry.utility.get(this.key, entry.config) : null;
return (typeof value !== 'object') ? value : JSON.parse(JSON.stringify(this.getProxy(value, entry.config)));
}
addTargets(targets) {
targets.forEach(target => {
if (this.targets.indexOf(target) === -1) {
if (typeof target === 'object') { // handle Angular Component destruction
const originalFunction = target.ngOnDestroy;
const _self = this;
target.ngOnDestroy = function () {
if (typeof originalFunction === 'function') {
originalFunction.apply(this, arguments);
}
target.ngOnDestroy = originalFunction || function () { };
_self.initializedTargets.delete(target);
_self.targets = _self.targets.filter(t => t !== target);
if (!_self.targets.length) {
_self.services.forEach(service => {
service.keys = service.keys.filter(key => key !== _self._key);
});
_self.resetProxy();
Cache.remove(_self);
}
debug.groupCollapsed(`${_self.key} OnDestroy handler:`);
debug.log('removed target:', target.constructor.name);
debug.log('remaining targets:', _self.targets);
debug.log('cacheItem:', Cache.get(_self.key));
debug.groupEnd();
};
this.targets.push(target);
}
}
});
}
addServices(services) {
services.forEach(service => {
if (this.services.indexOf(service) === -1) {
service.keys.push(this._key);
this.services.push(service);
}
});
}
addUtilities(utilityEntries) {
utilityEntries.forEach(entry => {
if (this.utilities.findIndex(e => e.utility === entry.utility) === -1) {
this.utilities.push(entry);
entry.utility.set(this.key, this.readValue());
}
});
}
resetProxy() {
this.proxy = null;
}
propagateChange(value, source) {
if (isEqual(value, this.readValue())) {
return;
}
this.utilities.forEach(entry => {
const utility = entry.utility;
// updating service which the change came from would affect in a cycle
if (utility === source) {
return;
}
debug.log(`propagating change on ${this.key} to:`, utility);
utility.set(this._key, value, entry.config);
});
}
migrate(config, utility) {
const prefix = (config.prefix || Config.prefix) || '';
const keyExists = (key) => key in utility.getStorage();
const migrateKey = keyExists(prefix + config.migrateKey)
? prefix + config.migrateKey
: config.migrateKey;
if (!keyExists(migrateKey)) {
return;
}
debug.log('Migrating', migrateKey, 'to', config.key, 'in', utility.getStorageName());
const value = utility.get(migrateKey, Object.assign(Object.assign({}, config), { prefix: '' }));
utility.set(this._key, value);
utility.remove(migrateKey, { prefix: '' });
}
}
class NgxStorageEvent {
constructor(type, key, storageArea) {
this.type = type;
this.key = key;
this.storageArea = storageArea;
this.timeStamp = (Date.now() - NgxStorageEvent.initTimeStamp);
this.bubbles = false;
this.cancelBubble = false;
this.cancelable = false;
this.composed = false;
this.currentTarget = window;
this.defaultPrevented = false;
this.eventPhase = 2;
this.isTrusted = true;
this.path = [window];
this.returnValue = true;
this.srcElement = window;
this.target = window;
this.url = window.location.href;
this.isInternal = true;
}
/**
* Methods below exist only to satisfy TypeScript compiler
*/
// tslint:disable:typedef
get initEvent() {
return StorageEvent.prototype.initEvent.bind(this);
}
get preventDefault() {
return StorageEvent.prototype.preventDefault.bind(this);
}
get stopImmediatePropagation() {
return StorageEvent.prototype.stopImmediatePropagation.bind(this);
}
get stopPropagation() {
return StorageEvent.prototype.stopPropagation.bind(this);
}
get composedPath() {
return StorageEvent.prototype.composedPath.bind(this);
}
get AT_TARGET() {
return StorageEvent.prototype.AT_TARGET;
}
get BUBBLING_PHASE() {
return StorageEvent.prototype.BUBBLING_PHASE;
}
get CAPTURING_PHASE() {
return StorageEvent.prototype.BUBBLING_PHASE;
}
}
NgxStorageEvent.initTimeStamp = Date.now();
const _get = require('lodash.get');
const _set = require('lodash.set');
const _merge = require('lodash.merge');
class Resource {
constructor(service, key) {
this.service = service;
this.key = key;
this._defaultValue = null;
this._path = [];
this._prefix = Config.prefix;
}
/**
* Returns default value
* @returns {T}
*/
get defaultValue() {
return this._defaultValue;
}
/**
* Returns current path as a string
* @returns {string}
*/
get path() {
return this.pathString;
}
/**
* Returns currently set prefix
* @returns {string}
*/
get prefix() {
return this._prefix || '';
}
/**
* Returns value taking path into account
* @returns {T}
*/
get value() {
return this.considerDefault(this.readValue());
}
get fullValue() {
return this.considerDefault(this.service.utility.get(this.key, { prefix: this._prefix }));
}
get pathString() {
return this._path.join('.');
}
/**
* Sets path of object property
* @param {string} path
* @returns {this}
*/
setPath(path) {
this._path = path.split('.');
return this;
}
/**
* Appends current path
* e.g. if path('key') and appendPath('nested'), the path will be "key.nested"
* @param {string} path
* @returns {this}
*/
appendPath(path) {
this._path.push(path);
return this;
}
/**
* Removes last item of path
* e.g. if path('key.nested') and truncatePath(), the path will be "key"
* @returns {this}
*/
truncatePath() {
this._path.pop();
return this;
}
/**
* Resets set path
* @returns {this}
*/
resetPath() {
this._path = [];
return this;
}
/**
* Sets prefix
* @param {string} prefix
* @returns {this}
*/
setPrefix(prefix) {
this._prefix = prefix;
return this;
}
/**
* Moves storage item to new key using given prefix
* @param {string} prefix
* @returns {this}
*/
changePrefix(prefix) {
this.service.utility.set(this.key, this.fullValue, { prefix });
this.service.utility.remove(this.key, { prefix: this._prefix });
return this.setPrefix(prefix);
}
/**
* Sets default value for both reading and saving operations
* @param defaultValue
* @returns {this}
*/
setDefaultValue(defaultValue) {
this._defaultValue = defaultValue;
const value = this.readValue();
if (this.isNullOrUndefined(value)) {
this.save(defaultValue);
}
return this;
}
/**
* Creates or overrides value as a new entry or existing object property depending on path
* @param value
* @returns {this}
*/
save(value) {
if (this.pathString) {
value = _set(this.fullValue, this.pathString, this.considerDefault(value));
}
this.service.utility.set(this.key, this.considerDefault(value), { prefix: this._prefix });
return this;
}
/**
* Updates existing object property using current path
* @param {T} value
* @returns {this}
*/
update(value) {
return this.save(_merge(this.readValue(), value));
}
/**
* Removes item stored under current key
* @returns {this}
*/
remove() {
this.service.utility.remove(this.key);
return this;
}
considerDefault(value) {
return this.isNullOrUndefined(value) ? this._defaultValue : value;
}
isNullOrUndefined(value) {
return (value === null || value === undefined);
}
readValue() {
const value = this.service.utility.get(this.key, { prefix: this._prefix });
if (this.pathString) {
return _get(value, this.pathString);
}
return value;
}
}
// const merge = require('lodash.merge');
class WebStorageService {
constructor(utility) {
this.utility = utility;
}
/**
* Gets keys for stored variables created by ngx-store,
* ignores keys that have not been created by decorators and have no prefix at once
*/
get keys() {
// get prefixed key if prefix is defined
const prefixKeys = this.utility.keys.filter(key => {
if (this.utility.prefix && this.utility.prefix.length) {
return key.startsWith(this.utility.prefix);
}
return true;
});
const decoratorKeys = this.constructor.keys;
return prefixKeys.concat(decoratorKeys);
}
get config() {
return Config;
}
get(key) {
return this.utility.get(key);
}
/**
* Returns new data Resource for given key exposing builder design pattern
* designed for complex nested data structures
*/
load(key) {
return new Resource(this, key);
}
set(key, value) {
return this.utility.set(key, value);
}
update(key, changes) {
const value = this.get(key);
if (value !== undefined && typeof value !== 'object') {
debug.throw(new Error(`Value stored under "${key}" key is not an object and tried to be updated.`));
return value;
}
return this.set(key, merge({}, value, changes));
}
// TODO return true if item existed and false otherwise (?)
remove(key) {
return this.utility.remove(key);
}
observe(key, exactMatch) {
return this._changes.pipe(filter((event) => {
var _a;
if (!key) {
return true;
}
if (exactMatch) {
if (Config.prefix && key.startsWith(Config.prefix)) {
return event.key === key;
}
return event.key === Config.prefix + key;
}
else {
return ((_a = event.key) === null || _a === void 0 ? void 0 : _a.indexOf(key)) !== -1;
}
}), delay(30));
}
/**
* Clears chosen data from Storage
* @param clearType 'prefix' | 'decorators' | 'all'
* @param prefixOrClass defines the prefix or class (not its instance) whose decorators should be cleared
*/
clear(clearType, prefixOrClass) {
clearType = clearType || Config.clearType;
if (clearType === 'decorators') {
let keys = [];
if (typeof prefixOrClass === 'object') {
keys = this.keys.filter(key => Cache.get(key).targets.includes(prefixOrClass));
debug.log(this.utility.getStorageName() + ' > Removing decorated data from '
+ prefixOrClass.constructor.name + ':', keys);
}
else {
keys = this.keys;
debug.log(this.utility.getStorageName() + ' > Removing decorated data:', keys);
}
keys.forEach(key => this.remove(key));
}
else if (clearType === 'prefix') {
prefixOrClass = prefixOrClass || this.utility.prefix;
this.utility.forEach((value, key) => {
if (key.startsWith(prefixOrClass)) {
this.remove(this.utility.trimPrefix(key));
}
});
}
else if (clearType === 'all') {
this.utility.clear();
}
}
generateEvent(key, newValue, oldValue) {
const type = this.utility.getStorageName().charAt(0).toLowerCase() + this.utility.getStorageName().slice(1);
const event = new NgxStorageEvent(type, key, this.utility.getStorage());
event.oldValue = (oldValue !== undefined) ? oldValue : this.get(key);
event.newValue = newValue;
return event;
}
mapNativeEvent(ev) {
const event = this.generateEvent(ev.key, this.utility.getGettable(ev.newValue), this.utility.getGettable(ev.oldValue));
event.isInternal = false;
return event;
}
}
WebStorageService.keys = [];
class WebStorageUtility {
constructor(storage, prefix = '', previousPrefix) {
this._prefix = '';
this._changes = new Subject();
this._storage = storage;
this._prefix = prefix;
// handle previousPrefix for backward-compatibility and safe config changes below
if (prefix === previousPrefix) {
return;
}
if (previousPrefix === null) {
return;
}
if (previousPrefix === undefined) {
return;
}
debug.log(this.getStorageName() + ' > Detected prefix change from ' + previousPrefix + ' to ' + prefix);
this.forEach((value, key) => {
// ignore config settings when previousPrefix = ''
if (key.startsWith(previousPrefix) && !key.startsWith(CONFIG_PREFIX)) {
const nameWithoutPrefix = this.trimPrefix(key);
this.set(nameWithoutPrefix, this._storage.getItem(key));
if (previousPrefix !== '') {
this._storage.removeItem(key);
}
}
});
}
get prefix() {
return this._prefix;
}
get changes() {
return this._changes.asObservable();
}
get keys() {
const keys = [];
this.forEach((value, key) => keys.push(key));
return keys;
}
static getSettable(value) {
return JSON.stringify(value);
}
static getGettable(value) {
if (value === 'undefined') {
return null;
}
try {
return JSON.parse(value);
}
catch (e) {
return value;
}
}
getStorage() {
return this._storage;
}
getStorageKey(key, prefix) {
prefix = (typeof prefix === 'string') ? prefix : this.prefix;
return `${prefix}${key}`;
}
getStorageName() {
return this._storage.type || ((this._storage === localStorage) ? 'localStorage' : 'sessionStorage');
}
get(key, config = {}) {
const storageKey = this.getStorageKey(key, config.prefix);
const value = this._storage.getItem(storageKey);
// TODO return undefined if no key
/*if (value === null && !(storageKey in this._storage)) {
return undefined;
}*/
return this.getGettable(value);
}
set(key, value, config = {}) {
if (value === null || value === undefined) {
this.remove(key);
return null;
}
try {
const storageKey = this.getStorageKey(key, config.prefix);
const storable = this.getSettable(value);
this.emitEvent(key, value);
this._storage.setItem(storageKey, storable, config.expires);
const cacheItem = Cache.get(key);
if (cacheItem) {
debug.log(`updating following CacheItem from ${this.constructor.name}:`, cacheItem);
cacheItem.resetProxy();
cacheItem.propagateChange(value, this);
}
}
catch (error) {
console.warn(`[ngx-store] ${this.getStorageName()}:
following error occurred while trying to save ${key} =`, value);
console.error(error);
}
return value;
}
// TODO return true if item existed and false otherwise (?)
remove(key, config = {}) {
const storageKey = this.getStorageKey(key, config.prefix);
this._storage.removeItem(storageKey);
const cacheItem = Cache.get(key);
if (cacheItem) {
cacheItem.resetProxy();
}
}
clear() {
this.emitEvent(null, null, null);
this.forEach((value, key) => {
if (key.startsWith(CONFIG_PREFIX)) {
return;
}
this.remove(key, { prefix: '' });
});
}
forEach(callbackFn) {
if (typeof this._storage.forEach === 'function') {
return this._storage.forEach((value, key) => {
callbackFn(this.getGettable(value), key);
});
}
Object.keys(this._storage).forEach((key) => {
callbackFn(this.getGettable(this._storage[key]), key);
});
}
getSettable(value) {
return WebStorageUtility.getSettable(value);
}
getGettable(value) {
return WebStorageUtility.getGettable(value);
}
trimPrefix(key) {
return key.replace(this.prefix, '');
}
emitEvent(key, newValue, oldValue) {
const event = new NgxStorageEvent(this.getStorageName(), key, this._storage);
event.oldValue = (oldValue !== undefined) ? oldValue : this.get(key);
event.newValue = newValue;
this._changes.next(event);
}
}
// TODO: in the future use ES6 Proxy to handle indexers
class NgxStorage {
constructor() {
this.externalChanges = new Subject();
}
emitEvent(key, newValue, oldValue) {
var _a;
const event = new NgxStorageEvent(this.type, key, this);
event.oldValue = (oldValue !== undefined) ? oldValue : this.getItem(key);
event.newValue = newValue;
event.isInternal = false;
(_a = this.externalChanges) === null || _a === void 0 ? void 0 : _a.next(event);
}
}
class CookiesStorage extends NgxStorage {
constructor() {
super();
this.cachedCookieString = '';
this.cachedItemsMap = new Map();
this.getAllItems();
if (Config.cookiesCheckInterval) {
interval(Config.cookiesCheckInterval)
.subscribe(() => {
var _a;
if (!((_a = this.externalChanges) === null || _a === void 0 ? void 0 : _a.observers.length)) {
return; // don't run if there are no set subscriptions
}
this.getAllItems();
});
}
}
get type() {
return 'cookiesStorage';
}
get length() {
return this.getAllKeys().length;
}
key(index) {
return this.getAllKeys()[index];
}
getItem(key) {
return this.getAllItems().get(key);
}
removeItem(key) {
if (typeof document === 'undefined') {
return;
}
let domain = this.resolveDomain(Config.cookiesScope);
domain = (domain) ? 'domain=' + domain + ';' : '';
document.cookie = key + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;' + domain;
this.cachedItemsMap.delete(key);
}
/**
* @param key
* @param value
* @param expirationDate passing null affects in lifetime cookie
*/
setItem(key, value, expirationDate) {
if (typeof document === 'undefined') {
return;
}
let domain = this.resolveDomain(Config.cookiesScope);
debug.log('Cookies domain:', domain);
domain = (domain) ? 'domain=' + domain + ';' : '';
let utcDate = '';
if (expirationDate instanceof Date) {
utcDate = expirationDate.toUTCString();
}
else if (expirationDate === null) {
utcDate = 'Fri, 18 Dec 2099 12:00:00 GMT';
}
const expires = utcDate ? '; expires=' + utcDate : '';
const cookie = key + '=' + value + expires + ';path=/;' + domain;
debug.log('Cookie`s set instruction:', cookie);
this.cachedItemsMap.set(key, value);
document.cookie = cookie;
}
clear() {
this.getAllKeys().forEach(key => this.removeItem(key));
}
forEach(callbackFn) {
return this.getAllItems().forEach((value, key) => callbackFn(value, key));
}
getAllKeys() {
return Array.from(this.getAllItems().keys());
}
// TODO: consider getting cookies from all paths
getAllItems() {
if (this.cachedCookieString === document.cookie) { // No changes
return this.cachedItemsMap;
}
const map = new Map();
if (typeof document === 'undefined') {
return map;
}
const cookies = document.cookie.split(';');
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
const eqPos = cookie.indexOf('=');
const key = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
const value = eqPos > -1 ? cookie.substr(eqPos + 1, cookie.length) : cookie;
map.set(key, value);
}
// detect changes and emit events
if (this.cachedItemsMap) {
map.forEach((value, key) => {
let cachedValue = this.cachedItemsMap.get(key);
cachedValue = (cachedValue !== undefined) ? cachedValue : null;
if (value !== cachedValue) {
this.emitEvent(key, WebStorageUtility.getGettable(value), WebStorageUtility.getGettable(cachedValue));
}
});
this.cachedItemsMap.forEach((value, key) => {
if (!map.has(key)) {
this.emitEvent(key, null, WebStorageUtility.getGettable(value));
}
});
}
this.cachedCookieString = document.cookie;
return this.cachedItemsMap = map;
}
/**
* domain.com + path="." = .domain.com
* domain.com + path=".sub." = .sub.domain.com
* sub.domain.com + path="sub." = sub.domain.com
* www.sub.domain.com + path="." = .sub.domain.com
* localhost + path=".whatever." = localhost
* @param path
*/
resolveDomain(path) {
if (!path) {
return '';
}
const hostname = document.domain;
if ((hostname.match(/\./g) || []).length < 1) {
return '';
}
const www = (path[0] !== '.' && hostname.indexOf('www.') === 0) ? 'www.' : '';
return www + path + this.getDomain();
}
/**
* This function determines base domain by setting cookie at the highest level possible
* @url http://rossscrivener.co.uk/blog/javascript-get-domain-exclude-subdomain
*/
getDomain() {
let i = 0;
let domain = document.domain;
const domainParts = domain.split('.');
const s = '_gd' + (new Date()).getTime();
while (i < (domainParts.length - 1) && document.cookie.indexOf(s + '=' + s) === -1) {
domain = domainParts.slice(-1 - (++i)).join('.');
document.cookie = s + '=' + s + ';domain=' + domain + ';';
}
document.cookie = s + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;domain=' + domain + ';';
return domain;
}
}
const cookiesStorage = new CookiesStorage();
class SharedStorageUtility extends WebStorageUtility {
getSettable(value) {
return value;
}
getGettable(value) {
return value;
}
}
class SharedStorage extends NgxStorage {
constructor() {
super();
this.sharedMap = new Map();
delete this.externalChanges;
}
get type() {
return 'sharedStorage';
}
get length() {
return this.getAllKeys().length;
}
key(index) {
return this.getAllKeys()[index];
}
getItem(key) {
const value = this.sharedMap.get(key);
return (value !== undefined) ? value : null;
}
removeItem(key) {
this.sharedMap.delete(key);
}
setItem(key, value) {
this.sharedMap.set(key, value);
}
clear() {
this.sharedMap.clear();
}
forEach(func) {
return this.sharedMap.forEach((value, key) => func(value, key));
}
getAllKeys() {
return Array.from(this.sharedMap.keys());
}
}
const sharedStorage = new SharedStorage();
const localStorageUtility = new WebStorageUtility(localStorage, Config.prefix, Config.previousPrefix);
const sessionStorageUtility = new WebStorageUtility(sessionStorage, Config.prefix, Config.previousPrefix);
const cookiesStorageUtility = new WebStorageUtility(cookiesStorage, Config.prefix, Config.previousPrefix);
const sharedStorageUtility = new SharedStorageUtility(sharedStorage, Config.prefix, Config.prefix);
class LocalStorageService extends WebStorageService {
constructor() {
super(localStorageUtility);
this._changes =
merge$1(fromEvent(window, 'storage')
.pipe(filter((event) => event.storageArea === localStorage), map((event) => this.mapNativeEvent(event))), localStorageUtility.changes);
}
}
LocalStorageService.keys = [];
LocalStorageService.decorators = [
{ type: Injectable }
];
LocalStorageService.ctorParameters = () => [];
class SessionStorageService extends WebStorageService {
constructor() {
super(sessionStorageUtility);
this._changes =
merge$1(fromEvent(window, 'storage')
.pipe(filter((event) => event.storageArea === sessionStorage), map((event) => this.mapNativeEvent(event))), sessionStorageUtility.changes);
}
}
SessionStorageService.keys = [];
SessionStorageService.decorators = [
{ type: Injectable }
];
SessionStorageService.ctorParameters = () => [];
class CookiesStorageService extends WebStorageService {
constructor() {
var _a;
super(cookiesStorageUtility);
this._changes = !cookiesStorage.externalChanges ? cookiesStorageUtility.changes
: merge$1((_a = cookiesStorage.externalChanges) === null || _a === void 0 ? void 0 : _a.asObservable(), cookiesStorageUtility.changes);
}
set(key, value, expirationDate) {
return this.utility.set(key, value, { expires: expirationDate });
}
}
CookiesStorageService.keys = [];
CookiesStorageService.decorators = [
{ type: Injectable }
];
CookiesStorageService.ctorParameters = () => [];
class SharedStorageService extends WebStorageService {
constructor() {
super(sharedStorageUtility);
this._changes = sharedStorageUtility.changes;
}
}
SharedStorageService.keys = [];
SharedStorageService.decorators = [
{ type: Injectable }
];
SharedStorageService.ctorParameters = () => [];
// tslint:disable:only-arrow-functions
function LocalStorage(keyOrConfig, config) {
return WebStorage(localStorageUtility, LocalStorageService, keyOrConfig, config);
}
function SessionStorage(keyOrConfig, config) {
return WebStorage(sessionStorageUtility, SessionStorageService, keyOrConfig, config);
}
function CookieStorage(keyOrConfig, config) {
return WebStorage(cookiesStorageUtility, CookiesStorageService, keyOrConfig, config);
}
function SharedStorage$1(keyOrConfig, config) {
return WebStorage(sharedStorageUtility, SharedStorageService, keyOrConfig, config);
}
function WebStorage(webStorageUtility, service, keyOrConfig, config = {}) {
return (target, propertyName) => {
let key = '';
if (typeof keyOrConfig === 'object') {
key = keyOrConfig.key || '';
config = keyOrConfig;
}
else if (typeof keyOrConfig === 'string') {
key = keyOrConfig;
}
key = key || config.key || propertyName;
let cacheItem = Cache.getCacheFor({
key,
name: propertyName,
targets: [target],
services: [service],
utilities: [{
utility: webStorageUtility,
config,
}],
});
Object.defineProperty(target, propertyName, {
get: function () {
return cacheItem.getProxy(undefined, config);
},
set: function (value) {
if (!Cache.get(cacheItem.key)) {
cacheItem = Cache.getCacheFor(cacheItem);
}
cacheItem.addTargets([target]);
cacheItem.currentTarget = target;
cacheItem.saveValue(value, config);
},
configurable: true,
});
return target;
};
}
class NgxStoreModule {
// methods for future use
static forRoot() {
return {
ngModule: NgxStoreModule,
};
}
static forChild() {
return NgxStoreModule;
}
}
NgxStoreModule.decorators = [
{ type: NgModule, args: [{
declarations: [],
imports: [],
exports: [],
providers: [
LocalStorageService,
SessionStorageService,
CookiesStorageService,
SharedStorageService,
],
},] }
];
/*
* Public API Surface of ngx-store
*/
/**
* Generated bundle index. Do not edit.
*/
export { CookieStorage, CookiesStorageService as CookieStorageService, CookiesStorageService, LocalStorage, LocalStorageService, Resource as NgxResource, NgxStorageEvent, NgxStoreModule, SessionStorage, SessionStorageService, SharedStorage$1 as SharedStorage, SharedStorageService, SharedStorage$1 as TempStorage, SharedStorageService as TempStorageService, NgxStoreModule as WebStorageModule, WebStorageService, WebStorageUtility as ɵa };
//# sourceMappingURL=ngx-store.js.map