feat: handle upload image by drop event
This commit is contained in:
parent
3fc74490de
commit
494c4f4578
@ -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();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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("内容不能为空呀");
|
||||||
|
|||||||
@ -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 };
|
||||||
|
|||||||
@ -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,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user