labo-components
Version:
224 lines (192 loc) • 9.18 kB
JavaScript
import PropTypes from 'prop-types';
import LZString from 'lz-string'; //for compressing large search results that are put in local storage
export default class LocalStorageHandler {
//TODO add proper validation
static VALID_KEYS = {
//used to store a SearchResults object obtained after calling the SearchAPI
'stored-search-results': {type : "object", compress : true}, //SearchResults.toLocalStorageObject()
//used to store the priority query, so it can be run by passing the query=prio param (single search)
'stored-priority-query': {type : "object", compress : false}, //Query
//used to remember selected search results across the media suite
'stored-selections' : {type : "array", compress : false}, //containing objects with: key=resourceId value=SearchResult
//used to remember the active project across the media suite
'stored-active-project': {type : "object", compress : false}, //Project
//used when clicking on an item in the result list
'stored-visited-results': {type : "array", compress : false}, //containing strings
//whether the user wants to show/hide the time line on the search page
'state-show-timeline': {type : "boolean", compress : false},
//store active (if any has been selected) collection id.
'active-collection-id': {type : "string", compress : false},
//collections ids selected in Collection inspector.
'stored-cids': {type : "string", compress : false},
//queries selected for further query processing (see ProjectQueriesView)
'stored-query-selection' : {type : "object", compress : false},
//the amount of projects in your workspace
'stored-project-count' : {type : "number", compress : false},
//the amount of personal collections in your workspace
'stored-personal-collection-count' : {type : "number", compress : false}
};
static supportsHTML5Storage = () => {
try {
return 'localStorage' in window && window['localStorage'] !== null
} catch (e) {
return false
}
};
static checkLocalStorageKey = (key, mustExist) => {
if(key in LocalStorageHandler.VALID_KEYS){
if(!mustExist || (mustExist && localStorage.getItem(key))){
return true;
}
}
return false;
};
//TODO turn this into something that tries to construct & validate the actual object/class based on the stored JSON data
static checkProptype = (key, data) => {
let propType = '';
if(Array.isArray(data)){
propType = "array";
} else {
propType = typeof data;
}
return propType === LocalStorageHandler.VALID_KEYS[key].type;
};
/*--------------------------------------------------------------------------------
* ------------------------- CRUD OF JSON OBJECTS IN LOCALSTORAGE -----------------
---------------------------------------------------------------------------------*/
static deleteUnusedKeys = () => {
for (let i = 0; i < localStorage.length; i++) {
if(LocalStorageHandler.VALID_KEYS[localStorage.key(i)] === undefined) {
try { localStorage.removeItem(localStorage.key(i)); } catch (e) { }
}
}
};
static shouldCompress = key => {
return LocalStorageHandler.VALID_KEYS[key].compress;
}
//Note: localStorage stored class objects like a simple JSON structure without functions.
//When retrieving the object, don't expect the functions to be there, instead use Object.construct to recreate the original object
static storeJSONInLocalStorage = (key, data) => {
if(LocalStorageHandler.supportsHTML5Storage() && LocalStorageHandler.checkLocalStorageKey(key, false)) {
if(LocalStorageHandler.checkProptype(key, data)){
try {
if(data === null) {
localStorage.removeItem(key);
} else {
const dataToStore = LocalStorageHandler.shouldCompress(key) ?
LZString.compress(JSON.stringify(data)) :
JSON.stringify(data)
;
localStorage.setItem(key, dataToStore);
}
return true
} catch (e) {
console.error(e);
}
} else {
console.error('Trying to store the wrong kind of data for key: ' + key)
}
}
return false
};
//TODO possibly extend with an option to cast the JSON back to the original object (see the model package)
static getJSONFromLocalStorage = key => {
if(LocalStorageHandler.supportsHTML5Storage() && LocalStorageHandler.checkLocalStorageKey(key, true)) {
try {
let loadedData = localStorage.getItem(key);
loadedData = LocalStorageHandler.shouldCompress(key) ? LZString.decompress(loadedData) : loadedData;
return JSON.parse(loadedData);
} catch (e) {
console.error(e);
}
}
return null
};
static removeJSONByKeyInLocalStorage = key => {
if (LocalStorageHandler.supportsHTML5Storage() && LocalStorageHandler.checkLocalStorageKey(key, true)) {
try {
localStorage.removeItem(key);
return true
} catch (e) {
console.error(e);
}
}
return false
};
/*--------------------------------------------------------------------------------
* ------------------------- CRUD OF ARRAYS WITH OJECTS/IDS IN LOCALSTORAGE -------
---------------------------------------------------------------------------------*/
//if you are pushing an object to the stored array, make sure to supply the identifier field name (string) of that object
static pushItemToLocalStorage = (key, item, itemIdentifier=null) => {
if(LocalStorageHandler.checkLocalStorageKey(key, false)){
const currentDataOnStorage = LocalStorageHandler.getJSONFromLocalStorage(key);
let obj = null;
if(currentDataOnStorage === null) {
obj = [item];
this.storeJSONInLocalStorage(key, obj)
} else {
// if item is not in array then push it.
if(!currentDataOnStorage.find(val => {
if(itemIdentifier) { //for comparing objects
return val[itemIdentifier] === item[itemIdentifier];
} else {
return val === item;
}
})) {
currentDataOnStorage.push(item);
}
this.storeJSONInLocalStorage(key, currentDataOnStorage)
}
}
return null;
};
//if you are removing an object from the stored array, make sure to supply the identifier field name (string) of that object
static removeItemInLocalStorage = (key, item, itemIdentifier=null) => {
if(LocalStorageHandler.checkLocalStorageKey(key, false)){
const currentDataOnStorage = LocalStorageHandler.getJSONFromLocalStorage(key);
const index = currentDataOnStorage.findIndex(val => {
if(itemIdentifier) { //for comparing objects
return val[itemIdentifier] === item[itemIdentifier]
} else {
return val === item
}
});
currentDataOnStorage.splice(index, 1);
if(currentDataOnStorage.length > 0) {
this.storeJSONInLocalStorage(key, currentDataOnStorage);
} else {
this.removeJSONByKeyInLocalStorage(key);
}
}
};
/*--------------------------------------------------------------------------------
* ------------------------- HIGH-LEVEL CONVENIENCE FUNCTIONS ---------------------
---------------------------------------------------------------------------------*/
static storeQueries = (project, queryIds) => {
if(!project || !queryIds) return;
LocalStorageHandler.storeJSONInLocalStorage(
'stored-query-selection',
{
projectId : project.id,
queryIds : queryIds
}
);
};
static getStoredQueries = () => {
return LocalStorageHandler.getJSONFromLocalStorage('stored-query-selection');
};
static updateStoredQueries = (project, queriesToDelete) => {
if(!project || !queriesToDelete) return;
const queryData = LocalStorageHandler.getStoredQueries();
if(!queryData || !queryData.queryIds || queryData.projectId !== project.id) return;
queriesToDelete.forEach(nq => {
if(queryData.queryIds.includes(nq.query.id)) {
queryData.queryIds.splice(
queryData.queryIds.indexOf(nq.query.id),
1
);
}
})
LocalStorageHandler.storeQueries(project, queryData.queryIds);
};
};