diff --git a/apps/client/src/types-pdfjs.d.ts b/apps/client/src/types-pdfjs.d.ts index 12756778e..3a4b3f16d 100644 --- a/apps/client/src/types-pdfjs.d.ts +++ b/apps/client/src/types-pdfjs.d.ts @@ -45,6 +45,10 @@ interface WithContext { interface PdfDocumentModifiedMessage extends WithContext { type: "pdfjs-viewer-document-modified"; +} + +interface PdfDocumentBlobResultMessage extends WithContext { + type: "pdfjs-viewer-blob"; data: Uint8Array; } @@ -113,4 +117,5 @@ type PdfMessageEvent = MessageEvent< | PdfViewerThumbnailMessage | PdfViewerAttachmentsMessage | PdfViewerLayersMessage + | PdfDocumentBlobResultMessage >; diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 1063def55..17efcc275 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -174,7 +174,7 @@ export function useBlobEditorSpacedUpdate({ note, noteType, noteContext, getData noteType: NoteType; note: FNote, noteContext: NoteContext | null | undefined, - getData: () => Promise | Blob | undefined, + getData: () => Promise | Blob | undefined, onContentChange: (newBlob: FBlob) => void, dataSaved?: (savedData: Blob) => void, updateInterval?: number; diff --git a/apps/client/src/widgets/type_widgets/file/Pdf.tsx b/apps/client/src/widgets/type_widgets/file/Pdf.tsx index cbd34eef8..60d6f2059 100644 --- a/apps/client/src/widgets/type_widgets/file/Pdf.tsx +++ b/apps/client/src/widgets/type_widgets/file/Pdf.tsx @@ -16,14 +16,28 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: { }) { const iframeRef = useRef(null); const historyConfig = useViewModeConfig(note, "pdfHistory"); - const dataRef = useRef(new Blob()); const spacedUpdate = useBlobEditorSpacedUpdate({ note, noteType: "file", noteContext, getData() { - return dataRef.current; + if (!iframeRef.current?.contentWindow) return undefined; + + return new Promise((resolve) => { + const onMessageReceived = (event: PdfMessageEvent) => { + if (event.data.type !== "pdfjs-viewer-blob") return; + if (event.data.noteId !== note.noteId || event.data.ntxId !== noteContext.ntxId) return; + const blob = new Blob([event.data.data as Uint8Array], { type: note.mime }); + window.removeEventListener("message", onMessageReceived); + resolve(blob); + }; + + window.addEventListener("message", onMessageReceived); + iframeRef.current?.contentWindow?.postMessage({ + type: "trilium-request-blob", + }); + }); }, onContentChange() { if (iframeRef.current?.contentWindow) { @@ -35,9 +49,7 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: { useEffect(() => { function handleMessage(event: PdfMessageEvent) { if (event.data?.type === "pdfjs-viewer-document-modified") { - const blob = new Blob([event.data.data as Uint8Array], { type: note.mime }); if (event.data.noteId === note.noteId && event.data.ntxId === noteContext.ntxId) { - dataRef.current = blob; spacedUpdate.resetUpdateTimer(); spacedUpdate.scheduleUpdate(); } diff --git a/packages/pdfjs-viewer/src/custom.ts b/packages/pdfjs-viewer/src/custom.ts index c58e4104b..d78560122 100644 --- a/packages/pdfjs-viewer/src/custom.ts +++ b/packages/pdfjs-viewer/src/custom.ts @@ -55,35 +55,41 @@ function getCustomAppOptions(urlParams: URLSearchParams) { function manageSave() { const app = window.PDFViewerApplication; const storage = app.pdfDocument.annotationStorage; - let timeout = null; - function debouncedSave() { - if (timeout) { - clearTimeout(timeout); - } - timeout = setTimeout(async () => { - if (!storage) return; + function onChange() { + if (!storage) return; + window.parent.postMessage({ + type: "pdfjs-viewer-document-modified", + ntxId: window.TRILIUM_NTX_ID, + noteId: window.TRILIUM_NOTE_ID + } satisfies PdfDocumentModifiedMessage, window.location.origin); + storage.resetModified(); + } + + window.addEventListener("message", async (event) => { + if (event.origin !== window.location.origin) return; + + if (event.data?.type === "trilium-request-blob") { + const app = window.PDFViewerApplication; const data = await app.pdfDocument.saveDocument(); window.parent.postMessage({ - type: "pdfjs-viewer-document-modified", + type: "pdfjs-viewer-blob", data, ntxId: window.TRILIUM_NTX_ID, noteId: window.TRILIUM_NOTE_ID - } satisfies PdfDocumentModifiedMessage, window.location.origin); - storage.resetModified(); - timeout = null; - }, 2_000); - } + } satisfies PdfDocumentBlobResultMessage, window.location.origin) + } + }); - app.pdfDocument.annotationStorage.onSetModified = debouncedSave; // works great for most cases, including forms. - app.eventBus.on("annotationeditorcommit", debouncedSave); - app.eventBus.on("annotationeditorparamschanged", debouncedSave); + app.pdfDocument.annotationStorage.onSetModified = onChange; // works great for most cases, including forms. + app.eventBus.on("annotationeditorcommit", onChange); + app.eventBus.on("annotationeditorparamschanged", onChange); app.eventBus.on("annotationeditorstateschanged", evt => { // needed for detecting when annotations are moved around. const { activeEditorId } = evt; // When activeEditorId becomes null, an editor was just committed if (activeEditorId === null) { - debouncedSave(); + onChange(); } }); }