mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 19:49:54 +02:00
editor: add support for bypassing cors when downloading images
This commit is contained in:
committed by
Abdullah Atta
parent
2966962016
commit
91ae351129
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user