diff --git a/apps/web/src/common/attachments.js b/apps/web/src/common/attachments.ts
similarity index 59%
rename from apps/web/src/common/attachments.js
rename to apps/web/src/common/attachments.ts
index 50add2ed4..e0f54cc7f 100644
--- a/apps/web/src/common/attachments.js
+++ b/apps/web/src/common/attachments.ts
@@ -20,8 +20,8 @@ along with this program. If not, see .
import FS from "../interfaces/fs";
import { db } from "./db";
-export async function downloadAttachment(hash) {
- const attachment = db.attachments.attachment(hash);
+async function download(hash: string) {
+ const attachment = db.attachments?.attachment(hash);
if (!attachment) return;
const downloadResult = await db.fs.downloadFile(
attachment.metadata.hash,
@@ -31,9 +31,17 @@ export async function downloadAttachment(hash) {
);
if (!downloadResult) throw new Error("Failed to download file.");
- const key = await db.attachments.decryptKey(attachment.key);
+ const key = await db.attachments?.decryptKey(attachment.key);
if (!key) throw new Error("Invalid key for attachment.");
+ return { key, attachment };
+}
+
+export async function saveAttachment(hash: string) {
+ const response = await download(hash);
+ if (!response) return;
+
+ const { attachment, key } = response;
await FS.saveFile(attachment.metadata.hash, {
key,
iv: attachment.iv,
@@ -43,46 +51,51 @@ export async function downloadAttachment(hash) {
});
}
-export async function downloadAttachmentForPreview(hash) {
- const attachment = db.attachments.attachment(hash);
- if (!attachment) return;
- const downloadResult = await db.fs.downloadFile(
- attachment.metadata.hash,
- attachment.metadata.hash,
- attachment.chunkSize,
- attachment.metadata
- );
- if (!downloadResult) throw new Error("Failed to download file.");
+type OutputTypeToReturnType = {
+ blob: Blob;
+ base64: string;
+ text: string;
+};
+export async function downloadAttachment<
+ TType extends "blob" | "base64" | "text",
+ TOutputType = OutputTypeToReturnType[TType]
+>(hash: string, type: TType): Promise {
+ const response = await download(hash);
+ if (!response) return;
+ const { attachment, key } = response;
- const key = await db.attachments.decryptKey(attachment.key);
- if (!key) throw new Error("Invalid key for attachment.");
+ if (type === "base64" || type === "text")
+ return (await db.attachments?.read(hash, type)) as TOutputType;
- return await FS.decryptFile(attachment.metadata.hash, {
+ const blob = await FS.decryptFile(attachment.metadata.hash, {
key,
iv: attachment.iv,
name: attachment.metadata.filename,
type: attachment.metadata.type,
isUploaded: !!attachment.dateUploaded
});
+
+ if (!blob) return;
+ return blob as TOutputType;
}
-export async function checkAttachment(hash) {
- const attachment = db.attachments.attachment(hash);
+export async function checkAttachment(hash: string) {
+ const attachment = db.attachments?.attachment(hash);
if (!attachment) return { failed: "Attachment not found." };
try {
const size = await FS.getUploadedFileSize(hash);
if (size <= 0) return { failed: "File length is 0." };
} catch (e) {
- return { failed: e.message };
+ return { failed: e instanceof Error ? e.message : "Unknown error." };
}
return { success: true };
}
const ABYTES = 17;
-export function getTotalSize(attachments) {
+export function getTotalSize(attachments: any[]) {
let size = 0;
- for (let attachment of attachments) {
+ for (const attachment of attachments) {
size += attachment.length + ABYTES;
}
return size;
diff --git a/apps/web/src/components/attachment/index.tsx b/apps/web/src/components/attachment/index.tsx
index e0ac818d9..5e63f6df0 100644
--- a/apps/web/src/components/attachment/index.tsx
+++ b/apps/web/src/components/attachment/index.tsx
@@ -47,7 +47,7 @@ import {
} from "../../common/dialog-controller";
import { store } from "../../stores/attachment-store";
import { db } from "../../common/db";
-import { downloadAttachment } from "../../common/attachments";
+import { saveAttachment } from "../../common/attachments";
import { reuploadAttachment } from "../editor/picker";
import { Multiselect } from "../../common/multi-select";
import { Menu } from "../../hooks/use-menu";
@@ -303,7 +303,7 @@ const AttachmentMenuItems: MenuItem[] = [
const isDownloading = status?.type === "download";
if (isDownloading) {
await db.fs.cancel(attachment.metadata.hash, "download");
- } else await downloadAttachment(attachment.metadata.hash);
+ } else await saveAttachment(attachment.metadata.hash);
}
},
{
diff --git a/apps/web/src/components/editor/index.tsx b/apps/web/src/components/editor/index.tsx
index 843b4d371..890f5f37f 100644
--- a/apps/web/src/components/editor/index.tsx
+++ b/apps/web/src/components/editor/index.tsx
@@ -41,10 +41,7 @@ import Header from "./header";
import { Attachment } from "../icons";
import { useEditorInstance } from "./context";
import { attachFile, AttachmentProgress, insertAttachment } from "./picker";
-import {
- downloadAttachment,
- downloadAttachmentForPreview
-} from "../../common/attachments";
+import { saveAttachment, downloadAttachment } from "../../common/attachments";
import { EV, EVENTS } from "@notesnook/core/common";
import { db } from "../../common/db";
import useMobile from "../../hooks/use-mobile";
@@ -57,6 +54,7 @@ import { Lightbox } from "../lightbox";
import ThemeProviderWrapper from "../theme-provider";
import { Allotment } from "allotment";
import { PdfPreview } from "../pdf-preview";
+import { showToast } from "../../utils/toast";
type PreviewSession = {
content: { data: string; type: string };
@@ -408,14 +406,17 @@ export function Editor(props: EditorProps) {
}}
onContentChange={onContentChange}
onChange={onEditorChange}
- onDownloadAttachment={(attachment) =>
- downloadAttachment(attachment.hash)
- }
+ onDownloadAttachment={(attachment) => saveAttachment(attachment.hash)}
onPreviewAttachment={async ({ hash, dataurl }) => {
const attachment = db.attachments?.attachment(hash);
if (attachment && attachment.metadata.type.startsWith("image/")) {
const container = document.getElementById("dialogContainer");
if (!(container instanceof HTMLElement)) return;
+
+ dataurl = dataurl || (await downloadAttachment(hash, "base64"));
+ if (!dataurl)
+ return showToast("error", "This image cannot be previewed.");
+
ReactDOM.render(
({
},
hash: getDataAttribute("hash"),
filename: getDataAttribute("filename"),
- type: getDataAttribute("mime"),
+ mime: getDataAttribute("mime"),
size: getDataAttribute("size")
};
},
diff --git a/packages/editor/src/extensions/image/component.tsx b/packages/editor/src/extensions/image/component.tsx
index 03e149fff..521446a45 100644
--- a/packages/editor/src/extensions/image/component.tsx
+++ b/packages/editor/src/extensions/image/component.tsx
@@ -83,7 +83,7 @@ export function ImageComponent(
setSource(url);
editor.current?.commands.updateImage(
{ src },
- { src: await toDataURL(blob), size, type }
+ { src: await toDataURL(blob), size, mime: type }
);
}
} catch (e) {
diff --git a/packages/editor/src/extensions/image/image.ts b/packages/editor/src/extensions/image/image.ts
index 0af9f1182..24e2ffa4e 100644
--- a/packages/editor/src/extensions/image/image.ts
+++ b/packages/editor/src/extensions/image/image.ts
@@ -138,7 +138,7 @@ export const ImageNode = Node.create({
hash: getDataAttribute("hash"),
filename: getDataAttribute("filename"),
- type: getDataAttribute("mime"),
+ mime: getDataAttribute("mime"),
size: getDataAttribute("size"),
aspectRatio: {
default: undefined,
@@ -209,6 +209,7 @@ export const ImageNode = Node.create({
insertImage:
(options) =>
({ commands }) => {
+ console.log(options);
return commands.insertContent({
type: this.name,
attrs: options
diff --git a/packages/editor/src/toolbar/popups/image-upload.tsx b/packages/editor/src/toolbar/popups/image-upload.tsx
index 9fd2d0032..9b7800b3c 100644
--- a/packages/editor/src/toolbar/popups/image-upload.tsx
+++ b/packages/editor/src/toolbar/popups/image-upload.tsx
@@ -53,7 +53,7 @@ export function ImageUploadPopup(props: ImageUploadPopupProps) {
url,
downloadOptions
);
- onInsert({ src: await toDataURL(blob), size, type });
+ onInsert({ src: await toDataURL(blob), size, mime: type });
} catch (e) {
if (e instanceof Error) setError(e.message);
} finally {
diff --git a/packages/editor/src/toolbar/tools/attachment.tsx b/packages/editor/src/toolbar/tools/attachment.tsx
index c09de5154..68d066f19 100644
--- a/packages/editor/src/toolbar/tools/attachment.tsx
+++ b/packages/editor/src/toolbar/tools/attachment.tsx
@@ -61,15 +61,7 @@ export function DownloadAttachment(props: ToolProps) {
/>
);
}
-const previewableFileExtensions = ["pdf"];
-function canPreviewAttachment(attachment: Attachment) {
- if (!attachment) return false;
- const extension = attachment.filename?.split(".").pop();
- if (!extension) return false;
-
- return previewableFileExtensions.indexOf(extension) > -1;
-}
export function PreviewAttachment(props: ToolProps) {
const { editor } = props;
const attachmentNode =
@@ -105,3 +97,17 @@ export function RemoveAttachment(props: ToolProps) {
/>
);
}
+
+const previewableFileExtensions = ["pdf"];
+const previewableMimeTypes = ["application/pdf"];
+
+function canPreviewAttachment(attachment: Attachment) {
+ if (!attachment) return false;
+ if (previewableMimeTypes.some((mime) => attachment.mime.startsWith(mime)))
+ return true;
+
+ const extension = attachment.filename?.split(".").pop();
+ if (!extension) return false;
+
+ return previewableFileExtensions.indexOf(extension) > -1;
+}