Commit d75b3139 authored by Lê Bảo Hồng Đức's avatar Lê Bảo Hồng Đức

fix: rich-text-editor paste listener crash on admin page

Use JoditEditor's editorRef callback to attach the native paste listener
to the correct HTMLElement (jodit.editor) instead of casting the IJodit
instance to HTMLElement, which caused "t.addEventListener is not a
function" runtime error.

Also resolve uploaded image URLs via resolveUploadUrl so previews render
inside the editor, and ignore the Windows reserved-name "nul" file.

Generated with [Devin](https://devin.ai)
Co-Authored-By: 's avatarDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent 12458600
...@@ -42,3 +42,6 @@ next-env.d.ts ...@@ -42,3 +42,6 @@ next-env.d.ts
#vscode #vscode
.vscode/ .vscode/
# Windows reserved device name files (cannot be deleted normally)
nul
\ No newline at end of file
...@@ -239,6 +239,36 @@ export function AdminRichTextEditor({ ...@@ -239,6 +239,36 @@ export function AdminRichTextEditor({
const recentlyFormattedRef = useRef(false); const recentlyFormattedRef = useRef(false);
// Flag set by the native paste handler — only true right after a real paste event // Flag set by the native paste handler — only true right after a real paste event
const pasteDetectedRef = useRef(false); const pasteDetectedRef = useRef(false);
// Holds the cleanup function for the paste listener so we can remove it
// when the editor instance is replaced or the component unmounts.
const pasteCleanupRef = useRef<(() => void) | null>(null);
// Called by JoditEditor once the IJodit instance is ready. We use this to
// attach a native paste listener to the editor's editable DOM element.
const handleEditorRef = React.useCallback((jodit: { editor?: HTMLElement }) => {
// Clean up any previous listener
pasteCleanupRef.current?.();
pasteCleanupRef.current = null;
const editorEl = jodit?.editor;
if (!editorEl) return;
const handlePaste = () => {
pasteDetectedRef.current = true;
};
editorEl.addEventListener("paste", handlePaste);
pasteCleanupRef.current = () => {
editorEl.removeEventListener("paste", handlePaste);
};
}, []);
React.useEffect(() => {
return () => {
pasteCleanupRef.current?.();
pasteCleanupRef.current = null;
};
}, []);
const handleFormat = React.useCallback((html: string) => { const handleFormat = React.useCallback((html: string) => {
setIsFormatting(true); setIsFormatting(true);
...@@ -287,25 +317,6 @@ export function AdminRichTextEditor({ ...@@ -287,25 +317,6 @@ export function AdminRichTextEditor({
onChange(html); onChange(html);
}, [handleFormat, onChange]); }, [handleFormat, onChange]);
// Attach a native paste listener to the editor container so we can detect
// real clipboard paste events instead of guessing from HTML content.
React.useEffect(() => {
const container = editor.current as unknown as HTMLElement | null;
if (!container) return;
const editorEl = container.querySelector?.(".jodit-wysiwyg") as HTMLElement | null;
const target = editorEl ?? container;
const handlePaste = () => {
pasteDetectedRef.current = true;
};
target.addEventListener("paste", handlePaste);
return () => {
target.removeEventListener("paste", handlePaste);
};
}, [localValue]);
const config: JoditEditorProps["config"] = useMemo( const config: JoditEditorProps["config"] = useMemo(
() => ({ () => ({
readonly: readOnly, readonly: readOnly,
...@@ -565,6 +576,7 @@ export function AdminRichTextEditor({ ...@@ -565,6 +576,7 @@ export function AdminRichTextEditor({
<div className="editor-wrapper"> <div className="editor-wrapper">
<JoditEditor <JoditEditor
ref={editor} ref={editor}
editorRef={handleEditorRef}
value={localValue} value={localValue}
config={config} config={config}
onBlur={(nextContent) => { onBlur={(nextContent) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment