/**
* @class JsBrowserCache
* JsBrowserCache je trida na ukladani a ziskavani dat z localStorage a sessionStorage s moznosti expirace zaznamu ve storage
*/
export default class JsBrowserCache {
/**
* @constructor
* @param {Object} options nastaveni
* @example
* {
* prefix: 'cache-', // Nasatveni prefixu. Defaultni hodnota je 'cache-'.Prefix se bude pridavat k ID zaznamu, ktery se bude ukladat do storage
* storage: 'session', // Nasatveni typu uloziste. Defaultni hodnota je 'local'. 'local' je pro nastaveni localStorage a 'session' je pro nastaveni sessionStorage
* }
*/
constructor(options) {
console.info('Creat object JsBrowserCache');
/**
* nastaveni tridy
* @private
* @type {Object}
*/
this._options = Object.assign({}, {
prefix : 'cache-',
storage: 'local'
}, options || {});
/**
* pomocna promena pro prepocet z milisekund na sekundy
* @private
* @type {Number}
*/
this._seconds = 1*1000;
//nastavim storage
this._setStorage();
//otestuji podporu storage
this.testSupportsStorage()
}
/**
* metoda testuje prohlizec na podporu storage
* @public
* @returns {Boolean}
*/
testSupportsStorage() {
//vytvorim unikatni klic
let key = 'j8EiBTWwQV',
value = key;
//pokud jsem jiz testoval, tak nemusim znova
if (this._supportsStorage !== undefined) {
return this._supportsStorage;
}
//otestuji jestli existuje kurzor na storage
if (!this._storage) {
return this._supportsStorage = false;
}
try {
//spravnou funkcnost otestuji zapisem a ctenim z storage
this._setItem(key, value);
this._removeItem(key);
this._supportsStorage = true; //pokud projde zapis a cteni nastavim podporu na true
} catch (e) {
console.warn(e);
//otestuji jestli neni storage plna
if (this._IsExceptionOutOfSpace(e) && this._storage.length) {
this._supportsStorage = true;
} else {
this._supportsStorage = false;
}
}
return this._supportsStorage;
}
/**
* vrati true pokud prohlizec podporuje storage
* @public
* @returns {Boolean}
*/
isSupportsStorage() {
if (!this._supportsStorage) {
console.warn('Browser does not support storage');
}
return this._supportsStorage;
}
/**
* zapise hodnotu do storage
*
* @public
*
* @param {String} key unikatni klic zaznamu ve storage
* @param {String|Array|Object|Number} value hodnota muze byt String, Array, Json, Number
* @param {Number} expiration je nepovinny parametr a udava se v sekundach.
*
* @example
* var cache = new JsBrowserCache();
* cache.setItem('test1', 'test string');
* cache.setItem('test2', 'test string', 60); //expire 60 seconds
*
* @returns {Bool} vrati hodntu true pokud se hodnota zapise do storage
*/
setItem(key, value, expiration) {
let record,
actualTimeStamp = new Date().getTime();
//otestuji jestli je podporovana storage
if(!this.isSupportsStorage()) {
return false;
}
console.info('Actual time stamp: ' + actualTimeStamp);
console.info('Expire: ' + (expiration ? actualTimeStamp + expiration*1*this._seconds : ''));
record = {
value: this._jsonToString(value),
create: actualTimeStamp,
expire: expiration ? actualTimeStamp + expiration*1*this._seconds : ''
}
console.info(record);
try {
this._removeItem(key);
this._setItem(key, this._jsonToString(record));
return true;
} catch (e) {
console.warn(e);
//zachytavam vyjimku pro pripad ze jeplna storage
if (this._IsExceptionOutOfSpace(e) && this._storage.length) {
this.clearExpirate();
this._setItem(key, this._jsonToString(record));
//a otestuji jestli se zapsala a vratim Bool
return !!this._getItem(key);
} else {
return false;
}
}
}
/**
* vrati hodnotu ze storage na zaklade zadaneho klice.
* @public
* @param {String} key klic zaznamu
*
* @example
* var cache = new JsBrowserCache();
* cache.getItem('test');
*
* @returns {String|Array|Object|Number|Null} pokud klic neexistuje vratí null jinak vrati zapsanou hodnotu ve storage
*/
getItem(key) {
let record;
//otestuji jestli je podporovana storage
if(!this.isSupportsStorage()) {
return null;
}
//ziskam zaznma ze storage
record = this._getItem(key);
console.info(record);
//zjistim jestli polozka existuje
if(!record) {
return null;
}
//prevedu string na json
record = this._stringToJson(record);
console.info(record);
//otestuji jestli je polozka expirovana
if(record.expire && new Date().getTime() > record.expire) {
console.log('Item "' + key + '" is expired. Item is removed.');
this._removeItem(key);
return null;
} else {
return this._stringToJson(record.value);
}
}
/**
* vymaze expirovane zaznamy ze storage
* @public
*
* @example
* var cache = new JsBrowserCache();
* cache.clearExpired();
*
*/
clearExpired() {
let keys;
//otestuji jestli je podporovana storage
if(!this.isSupportsStorage()) {
return null;
}
//pokud je neco v storage, tak pokracuji
if (this._storage.length > 0) {
//ziskam vsechny klice ktere odpovidaji prefixu
keys = Object.keys(this._storage).filter( v => v.indexOf(this._options.prefix)===0 );
if (keys.length > 0) {
for (let i = 0, length = keys.length; i < length; i++){
let key = keys[i].replace(this._options.prefix,''), //odeberu u klice prefix
record = this._stringToJson(this._getItem(key));
//otestuji jestli je polozka expirovana
if(record.expire && new Date().getTime() > record.expire) {
console.info('Item "' + key + '" is expired. Item is removed.');
this._removeItem(key);
}
}
}
}
}
/**
* nastavi storage (local|session) local = localStorage, session = sessionStorage
* @private
* @param {String} storage nazev storage (local|session)
*/
_setStorage(storageName) {
try {
this._storage = storageName !== 'session' ? localStorage : sessionStorage;
} catch(e) {
this._storage = false;
}
}
/**
* ulozi zaznam do storage
* @private
* @param {String} key klic
* @param {String} value hodnota klice
*/
_setItem(key, value) {
this._storage.setItem(this._options.prefix + key, value);
}
/**
* vrati zaznam ze storage
* @private
* @param {String} key klic
* @returns {String|Null} vrati hodntou klice jako string. Pokud klic neexistuje vrati Null
*/
_getItem(key) {
return this._storage.getItem(this._options.prefix + key);
}
/**
* smaze zaznam ve storage
* @private
* @param {String} key
*/
_removeItem(key) {
this._storage.removeItem(this._options.prefix + key);
}
/**
* prevede json na string
* @private
* @param {Object} json
* @returns {String}
*/
_jsonToString(json) {
return JSON.stringify(json);
}
/**
* prevede string na json
* @private
* @param {String} string
* @returns {Object}
*/
_stringToJson(string) {
return JSON.parse(string);
}
/**
* otestuje jestli je vyvolaná vyjímka na plný storge
* @private
* @param {Object} e exception
* @returns {Bool}
*/
_IsExceptionOutOfSpace(e) {
return (e && e.name === 'QUOTA_EXCEEDED_ERR' ||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED' ||
e.name === 'QuotaExceededError');
}
}