mirror of
https://github.com/dbgate/dbgate
synced 2024-11-08 12:47:25 +00:00
162 lines
4.1 KiB
TypeScript
162 lines
4.1 KiB
TypeScript
import _ from 'lodash';
|
|
import { writable, derived } from 'svelte/store';
|
|
import { onMount, onDestroy } from 'svelte';
|
|
import localforage from 'localforage';
|
|
import { changeTab } from '../utility/common';
|
|
|
|
function getParsedLocalStorage(key) {
|
|
const value = localStorage.getItem(key);
|
|
if (value != null) {
|
|
try {
|
|
const res = JSON.parse(value);
|
|
return res;
|
|
} catch (e) {
|
|
// console.log('FAILED LOAD FROM STORAGE', e);
|
|
// console.log('VALUE', value);
|
|
localStorage.removeItem(key);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const saveHandlersList = [];
|
|
|
|
export default function useEditorData({ tabid, reloadToken = 0, loadFromArgs = null, onInitialData = null }) {
|
|
const localStorageKey = `tabdata_editor_${tabid}`;
|
|
let changeCounter = 0;
|
|
let savedCounter = 0;
|
|
|
|
const editorState = writable({
|
|
errorMessage: null,
|
|
isLoading: true,
|
|
value: null,
|
|
});
|
|
|
|
const editorValue = derived(editorState, $state => $state.value);
|
|
|
|
let value = null;
|
|
|
|
// const valueRef = React.useRef(null);
|
|
|
|
const initialLoad = async () => {
|
|
if (loadFromArgs) {
|
|
try {
|
|
const init = await loadFromArgs();
|
|
changeTab(tabid, tab => ({
|
|
...tab,
|
|
props: _.omit(tab.props, ['initialArgs']),
|
|
}));
|
|
editorState.update(x => ({
|
|
...x,
|
|
value: init,
|
|
}));
|
|
if (onInitialData) onInitialData(init);
|
|
value = init;
|
|
// mark as not saved
|
|
changeCounter += 1;
|
|
} catch (err) {
|
|
const message = (err && err.response && err.response.data && err.response.data.error) || 'Loading failed';
|
|
editorState.update(x => ({
|
|
...x,
|
|
errorMessage: message,
|
|
}));
|
|
console.error(err.response);
|
|
}
|
|
} else {
|
|
const initFallback = getParsedLocalStorage(localStorageKey);
|
|
if (initFallback != null) {
|
|
editorState.update(x => ({
|
|
...x,
|
|
value: initFallback,
|
|
}));
|
|
if (onInitialData) onInitialData(initFallback);
|
|
value = initFallback;
|
|
// move to local forage
|
|
await localforage.setItem(localStorageKey, initFallback);
|
|
localStorage.removeItem(localStorageKey);
|
|
} else {
|
|
const init = await localforage.getItem(localStorageKey);
|
|
if (init) {
|
|
editorState.update(x => ({
|
|
...x,
|
|
value: init,
|
|
}));
|
|
if (onInitialData) onInitialData(init);
|
|
value = init;
|
|
}
|
|
}
|
|
}
|
|
editorState.update(x => ({
|
|
...x,
|
|
isLoading: false,
|
|
}));
|
|
};
|
|
|
|
const saveToStorageIfNeeded = async () => {
|
|
if (savedCounter == changeCounter) return; // all saved
|
|
await saveToStorage();
|
|
};
|
|
|
|
const saveToStorage = async () => {
|
|
if (value == null) return;
|
|
try {
|
|
await localforage.setItem(localStorageKey, value);
|
|
localStorage.removeItem(localStorageKey);
|
|
savedCounter = changeCounter;
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
};
|
|
|
|
const saveToStorageSync = () => {
|
|
if (value == null) return;
|
|
if (savedCounter == changeCounter) return; // all saved
|
|
// on window unload must be synchronous actions, save to local storage instead
|
|
localStorage.setItem(localStorageKey, JSON.stringify(value));
|
|
};
|
|
|
|
const saveToStorageDebounced = _.debounce(saveToStorage, 5000);
|
|
|
|
const setEditorData = newValue => {
|
|
if (_.isFunction(newValue)) {
|
|
value = newValue(value);
|
|
} else {
|
|
if (newValue != null) value = newValue;
|
|
}
|
|
editorState.update(x => ({
|
|
...x,
|
|
value,
|
|
}));
|
|
|
|
changeCounter += 1;
|
|
saveToStorageDebounced();
|
|
};
|
|
|
|
onMount(() => {
|
|
window.addEventListener('beforeunload', saveToStorageSync);
|
|
initialLoad();
|
|
saveHandlersList.push(saveToStorageIfNeeded);
|
|
});
|
|
|
|
onDestroy(() => {
|
|
saveToStorage();
|
|
window.removeEventListener('beforeunload', saveToStorageSync);
|
|
_.remove(saveHandlersList, x => x == saveToStorageIfNeeded);
|
|
});
|
|
|
|
return {
|
|
editorState,
|
|
editorValue,
|
|
setEditorData,
|
|
saveToStorage,
|
|
saveToStorageSync,
|
|
initialLoad,
|
|
};
|
|
}
|
|
|
|
export async function saveAllPendingEditorData() {
|
|
for (const item of saveHandlersList) {
|
|
await item();
|
|
}
|
|
}
|