chore(client/pdf): use custom spaced update hook

This commit is contained in:
Elian Doran 2026-01-03 20:29:54 +02:00
parent f1f3e66537
commit 21cf5e1df7
No known key found for this signature in database
2 changed files with 84 additions and 10 deletions

View File

@ -170,6 +170,71 @@ export function useEditorSpacedUpdate({ note, noteType, noteContext, getData, on
return spacedUpdate;
}
export function useBlobEditorSpacedUpdate({ note, noteType, noteContext, getData, onContentChange, dataSaved, updateInterval }: {
noteType: NoteType;
note: FNote,
noteContext: NoteContext | null | undefined,
getData: () => Promise<Blob> | Blob | undefined,
onContentChange: (newBlob: FBlob) => void,
dataSaved?: (savedData: Blob) => void,
updateInterval?: number;
}) {
const parentComponent = useContext(ParentComponent);
const blob = useNoteBlob(note, parentComponent?.componentId);
const callback = useMemo(() => {
return async () => {
const data = await getData();
// for read only notes
if (data === undefined || note.type !== noteType) return;
protected_session_holder.touchProtectedSessionIfNecessary(note);
await server.upload(`notes/${note.noteId}/file`, new File([ data ], note.title, { type: note.mime }), parentComponent?.componentId);
dataSaved?.(data);
};
}, [ note, getData, dataSaved, noteType, parentComponent ]);
const stateCallback = useCallback<StateCallback>((state) => {
noteContext?.setContextData("saveState", {
state
});
}, [ noteContext ]);
const spacedUpdate = useSpacedUpdate(callback, updateInterval, stateCallback);
// React to note/blob changes.
useEffect(() => {
if (!blob) return;
spacedUpdate.allowUpdateWithoutChange(() => onContentChange(blob));
}, [ blob ]);
// React to update interval changes.
useEffect(() => {
if (!updateInterval) return;
spacedUpdate.setUpdateInterval(updateInterval);
}, [ updateInterval ]);
// Save if needed upon switching tabs.
useTriliumEvent("beforeNoteSwitch", async ({ noteContext: eventNoteContext }) => {
if (eventNoteContext.ntxId !== noteContext?.ntxId) return;
await spacedUpdate.updateNowIfNecessary();
});
// Save if needed upon tab closing.
useTriliumEvent("beforeNoteContextRemove", async ({ ntxIds }) => {
if (!noteContext?.ntxId || !ntxIds.includes(noteContext.ntxId)) return;
await spacedUpdate.updateNowIfNecessary();
});
// Save if needed upon window/browser closing.
useEffect(() => {
const listener = () => spacedUpdate.isAllSavedAndTriggerUpdate();
appContext.addBeforeUnloadListener(listener);
return () => appContext.removeBeforeUnloadListener(listener);
}, []);
return spacedUpdate;
}
export function useNoteSavedData(noteId: string | undefined) {
return useSyncExternalStore(
(cb) => noteId ? noteSavedDataStore.subscribe(noteId, cb) : () => {},

View File

@ -4,9 +4,8 @@ import appContext from "../../../components/app_context";
import type NoteContext from "../../../components/note_context";
import FBlob from "../../../entities/fblob";
import FNote from "../../../entities/fnote";
import server from "../../../services/server";
import { useViewModeConfig } from "../../collections/NoteList";
import { useTriliumEvent } from "../../react/hooks";
import { useBlobEditorSpacedUpdate, useTriliumEvent } from "../../react/hooks";
import PdfViewer from "./PdfViewer";
export default function PdfPreview({ note, blob, componentId, noteContext }: {
@ -17,13 +16,30 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
}) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const historyConfig = useViewModeConfig<HistoryData>(note, "pdfHistory");
const dataRef = useRef<Blob>(new Blob());
const spacedUpdate = useBlobEditorSpacedUpdate({
note,
noteType: "file",
noteContext,
getData() {
return dataRef.current;
},
onContentChange() {
if (iframeRef.current?.contentWindow) {
iframeRef.current.contentWindow.location.reload();
}
}
});
useEffect(() => {
function handleMessage(event: PdfMessageEvent) {
if (event.data?.type === "pdfjs-viewer-document-modified") {
const blob = new Blob([event.data.data as Uint8Array<ArrayBuffer>], { type: note.mime });
if (event.data.noteId === note.noteId && event.data.ntxId === noteContext.ntxId) {
server.upload(`notes/${note.noteId}/file`, new File([blob], note.title, { type: note.mime }), componentId);
dataRef.current = blob;
spacedUpdate.resetUpdateTimer();
spacedUpdate.scheduleUpdate();
}
}
@ -138,13 +154,6 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
};
}, [ note, historyConfig, componentId, blob, noteContext ]);
// Refresh when blob changes.
useEffect(() => {
if (iframeRef.current?.contentWindow) {
iframeRef.current.contentWindow.location.reload();
}
}, [ blob ]);
useTriliumEvent("customDownload", ({ ntxId }) => {
if (ntxId !== noteContext.ntxId) return;
iframeRef.current?.contentWindow?.postMessage({