mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
ui: migrate scratchpad drafts to IndexedDB
This commit is contained in:
1 parent
c25c1d5e89
commit
86d2a36731
3 files changed
+57
-21
No files matched your search
@@ -1,24 +1,9 @@
|
|||||||
let cacheKey = `${UserContext._id}/${UiContext.pdoc.domainId}/${UiContext.pdoc.docId}`;
|
|
||||||
if (UiContext.tdoc?._id) cacheKey += `@${UiContext.tdoc._id}`;
|
|
||||||
|
|
||||||
// TODO switch to indexeddb
|
|
||||||
export default function reducer(state = {
|
export default function reducer(state = {
|
||||||
lang: localStorage.getItem(`${cacheKey}#lang`) || UiContext.codeLang,
|
lang: UiContext.codeLang,
|
||||||
code: localStorage.getItem(cacheKey) || UiContext.codeTemplate,
|
code: UiContext.codeTemplate,
|
||||||
}, action: any = {}) {
|
}, action: any = {}) {
|
||||||
if (action.type === 'SCRATCHPAD_EDITOR_UPDATE_CODE') {
|
if (action.type === 'SCRATCHPAD_EDITOR_HYDRATE') return action.payload;
|
||||||
localStorage.setItem(cacheKey, action.payload);
|
if (action.type === 'SCRATCHPAD_EDITOR_UPDATE_CODE') return { ...state, code: action.payload };
|
||||||
return {
|
if (action.type === 'SCRATCHPAD_EDITOR_SET_LANG') return { ...state, lang: action.payload };
|
||||||
...state,
|
|
||||||
code: action.payload,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (action.type === 'SCRATCHPAD_EDITOR_SET_LANG') {
|
|
||||||
localStorage.setItem(`${cacheKey}#lang`, action.payload);
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
lang: action.payload,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { confirm } from 'vj/components/dialog';
|
import { confirm } from 'vj/components/dialog';
|
||||||
@@ -144,6 +145,34 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor
|
|||||||
const { default: ScratchpadApp } = await import('../components/scratchpad');
|
const { default: ScratchpadApp } = await import('../components/scratchpad');
|
||||||
const { default: ScratchpadReducer } = await import('../components/scratchpad/reducers');
|
const { default: ScratchpadReducer } = await import('../components/scratchpad/reducers');
|
||||||
const { Provider, store } = await loadReactRedux(ScratchpadReducer);
|
const { Provider, store } = await loadReactRedux(ScratchpadReducer);
|
||||||
|
let cacheKey = `${UserContext._id}/${UiContext.pdoc.domainId}/${UiContext.pdoc.docId}`;
|
||||||
|
if (UiContext.tdoc?._id) cacheKey += `@${UiContext.tdoc._id}`;
|
||||||
|
try {
|
||||||
|
const draft = await (await openDB).get('scratchpad-drafts', cacheKey);
|
||||||
|
if (draft) {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'SCRATCHPAD_EDITOR_HYDRATE',
|
||||||
|
payload: {
|
||||||
|
code: draft.code ?? UiContext.codeTemplate,
|
||||||
|
lang: draft.lang ?? UiContext.codeLang,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
let previousEditorState = store.getState().editor;
|
||||||
|
let write = Promise.resolve();
|
||||||
|
const saveDraft = _.debounce((code: string, lang: string) => {
|
||||||
|
write = write
|
||||||
|
.then(() => openDB.then((db) => db.put('scratchpad-drafts', { id: cacheKey, code, lang })))
|
||||||
|
.catch(() => { });
|
||||||
|
}, 400);
|
||||||
|
store.subscribe(() => {
|
||||||
|
const editor = store.getState().editor;
|
||||||
|
if (editor === previousEditorState) return;
|
||||||
|
previousEditorState = editor;
|
||||||
|
saveDraft(editor.code, editor.lang);
|
||||||
|
});
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
window.store = store;
|
window.store = store;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { openDB as _open } from 'idb';
|
import { openDB as _open } from 'idb';
|
||||||
import { alert } from 'vj/components/dialog';
|
import { alert } from 'vj/components/dialog';
|
||||||
|
|
||||||
export const openDB = _open('hydro', 2, {
|
const scratchpadCleanup: string[] = [];
|
||||||
|
|
||||||
|
export const openDB = _open('hydro', 3, {
|
||||||
upgrade(db, oldVersion) {
|
upgrade(db, oldVersion) {
|
||||||
if (oldVersion < 1) {
|
if (oldVersion < 1) {
|
||||||
const solutionStore = db.createObjectStore('solutions', { keyPath: 'id' });
|
const solutionStore = db.createObjectStore('solutions', { keyPath: 'id' });
|
||||||
@@ -18,6 +20,23 @@ export const openDB = _open('hydro', 2, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (oldVersion < 2) db.createObjectStore('domain-info', { keyPath: 'id' });
|
if (oldVersion < 2) db.createObjectStore('domain-info', { keyPath: 'id' });
|
||||||
|
if (oldVersion < 3) {
|
||||||
|
const scratchpadStore = db.createObjectStore('scratchpad-drafts', { keyPath: 'id' });
|
||||||
|
const drafts = new Map<string, { id: string, code?: string, lang?: string }>();
|
||||||
|
const scratchpadKey = /^(\d+\/[A-Za-z]\w{3,31}\/\d+(?:@[\dA-Fa-f]{24})?)(#lang)?$/;
|
||||||
|
for (const key of Object.keys(localStorage)) {
|
||||||
|
const match = key.match(scratchpadKey);
|
||||||
|
if (!match) continue;
|
||||||
|
const value = localStorage.getItem(key);
|
||||||
|
if (value === null) continue;
|
||||||
|
const draft = drafts.get(match[1]) || { id: match[1] };
|
||||||
|
if (match[2]) draft.lang = value;
|
||||||
|
else draft.code = value;
|
||||||
|
drafts.set(draft.id, draft);
|
||||||
|
scratchpadCleanup.push(key);
|
||||||
|
}
|
||||||
|
for (const draft of drafts.values()) scratchpadStore.put(draft);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
blocked(currentVersion, blockedVersion) {
|
blocked(currentVersion, blockedVersion) {
|
||||||
console.error('IDB Blocked by version', blockedVersion, 'want', currentVersion);
|
console.error('IDB Blocked by version', blockedVersion, 'want', currentVersion);
|
||||||
@@ -30,4 +49,7 @@ export const openDB = _open('hydro', 2, {
|
|||||||
terminated() {
|
terminated() {
|
||||||
console.error('IDB Terminated');
|
console.error('IDB Terminated');
|
||||||
},
|
},
|
||||||
|
}).then((db) => {
|
||||||
|
for (const key of scratchpadCleanup) localStorage.removeItem(key);
|
||||||
|
return db;
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user