From 91ae3511293ffb2f9fcacdaf1756632cb81e707c Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Mon, 9 Jan 2023 12:46:53 +0500 Subject: [PATCH] editor: add support for bypassing cors when downloading images --- packages/editor/src/index.ts | 24 ++++++++++++------- .../src/toolbar/popups/image-upload.tsx | 7 +++++- .../src/toolbar/stores/toolbar-store.ts | 8 +++++++ packages/editor/src/utils/downloader.ts | 6 ++++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index d4efd5538..69c4746ba 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -75,6 +75,7 @@ import { OpenLink, OpenLinkOptions } from "./extensions/open-link"; import HorizontalRule from "@tiptap/extension-horizontal-rule"; import { KeyMap } from "./extensions/key-map"; import { WebClipNode, WebClipOptions } from "./extensions/web-clip"; +import { DownloadOptions } from "./utils/downloader"; const CoreExtensions = Object.entries(TiptapCoreExtensions) // we will implement our own customized clipboard serializer @@ -85,6 +86,7 @@ type TiptapOptions = EditorOptions & Omit & Omit & OpenLinkOptions & { + downloadOptions?: DownloadOptions; theme: Theme; isMobile?: boolean; isKeyboardOpen?: boolean; @@ -104,6 +106,7 @@ const useTiptap = ( onOpenAttachmentPicker, onOpenLink, onBeforeCreate, + downloadOptions, ...restOptions } = options; const PortalProviderAPI = usePortalProvider(); @@ -111,19 +114,16 @@ const useTiptap = ( const setTheme = useToolbarStore((store) => store.setTheme); const closeAllPopups = useToolbarStore((store) => store.closeAllPopups); const setIsKeyboardOpen = useToolbarStore((store) => store.setIsKeyboardOpen); + const setDownloadOptions = useToolbarStore( + (store) => store.setDownloadOptions + ); useEffect(() => { setIsMobile(isMobile || false); setTheme(theme); setIsKeyboardOpen(isKeyboardOpen || false); - }, [ - isMobile, - theme, - isKeyboardOpen, - setIsMobile, - setTheme, - setIsKeyboardOpen - ]); + setDownloadOptions(downloadOptions); + }, [isMobile, theme, isKeyboardOpen, downloadOptions]); useEffect(() => { closeAllPopups(); @@ -260,7 +260,13 @@ const useTiptap = ( return editor; }; -export { useTiptap, Toolbar, usePermissionHandler, getHTMLFromFragment }; +export { + useTiptap, + Toolbar, + usePermissionHandler, + getHTMLFromFragment, + type DownloadOptions +}; export * from "./types"; export * from "./extensions/react"; export * from "./toolbar"; diff --git a/packages/editor/src/toolbar/popups/image-upload.tsx b/packages/editor/src/toolbar/popups/image-upload.tsx index fa4fe25b5..9d972684c 100644 --- a/packages/editor/src/toolbar/popups/image-upload.tsx +++ b/packages/editor/src/toolbar/popups/image-upload.tsx @@ -23,6 +23,7 @@ import { Flex, Text } from "@theme-ui/components"; import { ImageAttributes } from "../../extensions/image"; import { Popup } from "../components/popup"; import { downloadImage, toDataURL } from "../../utils/downloader"; +import { useToolbarStore } from "../stores/toolbar-store"; export type ImageUploadPopupProps = { onInsert: (image: ImageAttributes) => void; @@ -33,6 +34,7 @@ export function ImageUploadPopup(props: ImageUploadPopupProps) { const [isDownloading, setIsDownloading] = useState(false); const [error, setError] = useState(); const [url, setUrl] = useState(""); + const downloadOptions = useToolbarStore((store) => store.downloadOptions); return ( . import { Theme } from "@notesnook/theme"; import create from "zustand"; +import { DownloadOptions } from "../../utils/downloader"; export type ToolbarLocation = "top" | "bottom"; @@ -26,6 +27,8 @@ export type PopupRef = { id: string; group: string }; interface ToolbarState { theme?: Theme; setTheme: (theme?: Theme) => void; + downloadOptions?: DownloadOptions; + setDownloadOptions: (options?: DownloadOptions) => void; isKeyboardOpen: boolean; setIsKeyboardOpen: (isKeyboardOpen: boolean) => void; isMobile: boolean; @@ -42,9 +45,14 @@ interface ToolbarState { export const useToolbarStore = create((set, get) => ({ theme: undefined, + downloadOptions: undefined, isMobile: false, isKeyboardOpen: true, openedPopups: {}, + setDownloadOptions: (options) => + set((state) => { + state.downloadOptions = options; + }), setIsKeyboardOpen: (isKeyboardOpen) => set((state) => { state.isKeyboardOpen = isKeyboardOpen; diff --git a/packages/editor/src/utils/downloader.ts b/packages/editor/src/utils/downloader.ts index 8b5e62058..210382ef7 100644 --- a/packages/editor/src/utils/downloader.ts +++ b/packages/editor/src/utils/downloader.ts @@ -16,8 +16,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +export type DownloadOptions = { + corsHost: string; +}; -export async function downloadImage(url: string) { +export async function downloadImage(url: string, options?: DownloadOptions) { + if (options?.corsHost) url = `${options.corsHost}/${url}`; const response = await fetch(url); if (!response.ok) throw new Error(`invalid status code ${response.status}`);