editor: add support for bypassing cors when downloading images

This commit is contained in:
Abdullah Atta
2023-01-09 12:46:53 +05:00
committed by Abdullah Atta
parent 2966962016
commit 91ae351129
4 changed files with 34 additions and 11 deletions

View File

@@ -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<AttachmentOptions, "HTMLAttributes"> &
Omit<WebClipOptions, "HTMLAttributes"> &
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";

View File

@@ -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<string>();
const [url, setUrl] = useState<string>("");
const downloadOptions = useToolbarStore((store) => store.downloadOptions);
return (
<Popup
@@ -47,7 +49,10 @@ export function ImageUploadPopup(props: ImageUploadPopupProps) {
setError(undefined);
try {
const { blob, size, type } = await downloadImage(url);
const { blob, size, type } = await downloadImage(
url,
downloadOptions
);
onInsert({ src: await toDataURL(blob), size, type });
} catch (e) {
if (e instanceof Error) setError(e.message);

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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<ToolbarState>((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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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}`);