feat: handle upload image by drop event

This commit is contained in:
boojack 2021-12-17 08:11:02 +08:00
parent 3fc74490de
commit 494c4f4578
4 changed files with 60 additions and 40 deletions

View File

@ -1,14 +1,13 @@
import { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef } from "react"; import { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef } from "react";
import TinyUndo from "tiny-undo"; import TinyUndo from "tiny-undo";
import toastHelper from "../Toast";
import appContext from "../../stores/appContext"; import appContext from "../../stores/appContext";
import resourceService from "../../services/resourceService";
import { storage } from "../../helpers/storage"; import { storage } from "../../helpers/storage";
import useRefresh from "../../hooks/useRefresh"; import useRefresh from "../../hooks/useRefresh";
import Only from "../common/OnlyWhen"; import Only from "../common/OnlyWhen";
import "../../less/editor.less"; import "../../less/editor.less";
export interface EditorRefActions { export interface EditorRefActions {
element: HTMLTextAreaElement;
focus: FunctionType; focus: FunctionType;
insertText: (text: string) => void; insertText: (text: string) => void;
setContent: (text: string) => void; setContent: (text: string) => void;
@ -56,42 +55,6 @@ const Editor = forwardRef((props: Props, ref: React.ForwardedRef<EditorRefAction
editorRef.current.value = initialContent; editorRef.current.value = initialContent;
refresh(); refresh();
} }
const handlePasteEvent = async (event: ClipboardEvent) => {
if (event.clipboardData && event.clipboardData.files.length > 0) {
const file = event.clipboardData.files[0];
const { type } = file;
if (!type.startsWith("image")) {
return;
}
event.preventDefault();
try {
if (!editorRef.current) {
return;
}
const image = await resourceService.upload(file);
const url = `/r/${image.id}/${image.filename}`;
const prevValue = editorRef.current.value;
editorRef.current.value =
prevValue.slice(0, editorRef.current.selectionStart) + url + prevValue.slice(editorRef.current.selectionStart);
handleContentChangeCallback(editorRef.current.value);
refresh();
} catch (error: any) {
toastHelper.error(error);
}
}
};
editorRef.current.addEventListener("paste", handlePasteEvent);
return () => {
editorRef.current?.removeEventListener("paste", handlePasteEvent);
};
}, []); }, []);
useEffect(() => { useEffect(() => {
@ -135,6 +98,7 @@ const Editor = forwardRef((props: Props, ref: React.ForwardedRef<EditorRefAction
useImperativeHandle( useImperativeHandle(
ref, ref,
() => ({ () => ({
element: editorRef.current as HTMLTextAreaElement,
focus: () => { focus: () => {
editorRef.current?.focus(); editorRef.current?.focus();
}, },

View File

@ -1,6 +1,6 @@
import { useCallback, useContext, useEffect, useMemo, useRef } from "react"; import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
import appContext from "../stores/appContext"; import appContext from "../stores/appContext";
import { globalStateService, locationService, memoService } from "../services"; import { globalStateService, locationService, memoService, resourceService } from "../services";
import utils from "../helpers/utils"; import utils from "../helpers/utils";
import { storage } from "../helpers/storage"; import { storage } from "../helpers/storage";
import toastHelper from "./Toast"; import toastHelper from "./Toast";
@ -33,6 +33,57 @@ const MemoEditor: React.FC<Props> = () => {
prevGlobalStateRef.current = globalState; prevGlobalStateRef.current = globalState;
}, [globalState.markMemoId, globalState.editMemoId]); }, [globalState.markMemoId, globalState.editMemoId]);
useEffect(() => {
if (!editorRef.current) {
return;
}
const handleUploadFile = async (file: File) => {
const { type } = file;
if (!type.startsWith("image")) {
return;
}
try {
if (!editorRef.current) {
return;
}
const image = await resourceService.upload(file);
const url = `/r/${image.id}/${image.filename}`;
editorRef.current.insertText(url);
} catch (error: any) {
toastHelper.error(error);
}
};
const handlePasteEvent = async (event: ClipboardEvent) => {
if (event.clipboardData && event.clipboardData.files.length > 0) {
event.preventDefault();
const file = event.clipboardData.files[0];
handleUploadFile(file);
}
};
const handleDropEvent = async (event: DragEvent) => {
if (event.dataTransfer && event.dataTransfer.files.length > 0) {
event.preventDefault();
const file = event.dataTransfer.files[0];
handleUploadFile(file);
}
};
editorRef.current.element.addEventListener("paste", handlePasteEvent);
editorRef.current.element.addEventListener("drop", handleDropEvent);
return () => {
editorRef.current?.element.removeEventListener("paste", handlePasteEvent);
editorRef.current?.element.removeEventListener("drop", handleDropEvent);
};
}, []);
const handleSaveBtnClick = useCallback(async (content: string) => { const handleSaveBtnClick = useCallback(async (content: string) => {
if (content === "") { if (content === "") {
toastHelper.error("内容不能为空呀"); toastHelper.error("内容不能为空呀");

View File

@ -3,5 +3,6 @@ import locationService from "./locationService";
import memoService from "./memoService"; import memoService from "./memoService";
import queryService from "./queryService"; import queryService from "./queryService";
import userService from "./userService"; import userService from "./userService";
import resourceService from "./resourceService";
export { globalStateService, locationService, memoService, userService, queryService }; export { globalStateService, locationService, memoService, queryService, userService, resourceService };

View File

@ -12,6 +12,10 @@ export default defineConfig({
target: "https://memos.justsven.top/", target: "https://memos.justsven.top/",
changeOrigin: true, changeOrigin: true,
}, },
"/r": {
target: "https://memos.justsven.top/",
changeOrigin: true,
},
}, },
}, },
}); });