5.7 KiB
Rich Text Editor Image Insertion Fix
Date: January 2025
Issue: Quill.js image insertion errors and image duplication on drag
Problems Fixed
1. Quill.js Emitter Error
Error Message: Uncaught TypeError: can't access property "emit", this.emitter is undefined
Root Cause:
- The Quill editor's internal state wasn't fully initialized when
insertEmbedwas called - Calling
insertEmbedimmediately after upload without ensuring the editor is ready caused the emitter to be undefined
Solution:
// Insert into editor
const quill = quillRef.current?.getEditor();
if (quill) {
// Ensure editor is focused and ready
quill.focus();
// Use setTimeout to ensure Quill's internal state is ready
setTimeout(() => {
try {
const range = quill.getSelection();
const index = range ? range.index : quill.getLength();
// Insert the image with 'api' source to prevent event loops
quill.insertEmbed(index, 'image', res.url, 'api');
// Move cursor after the image
quill.setSelection(index + 1, 0, 'api');
// Force content change to trigger re-render
onChangeRef.current(quill.root.innerHTML);
toast({ title: 'Obrázek vložen', status: 'success', duration: 2000 });
} catch (embedError) {
console.error('Error inserting image:', embedError);
toast({ title: 'Chyba při vkládání obrázku', description: String(embedError), status: 'error' });
}
}, 50);
}
Key Changes:
- Added
quill.focus()before insertion to ensure the editor has focus - Wrapped insertion in
setTimeout(50ms)to allow Quill's internal state to stabilize - Changed source parameter from
'user'to'api'to prevent triggering user-initiated event handlers - Added try-catch block for better error handling
- Force content update with
onChangeRef.current(quill.root.innerHTML)to trigger re-render
2. Image Not Showing After Insertion
Problem: After uploading and inserting an image, it didn't appear in the editor
Solution:
- Added explicit
onChangeRef.current(quill.root.innerHTML)call after insertion - This forces React to recognize the DOM change and re-render the component
- The
'api'source parameter prevents infinite loops while still triggering the necessary updates
3. Image Duplication on Drag
Problem: Dragging images created duplicates due to default browser drag-and-drop behavior
Solution (Multiple Layers):
A. Set draggable attribute on image selection
const selectImage = (img: HTMLImageElement) => {
// ... other code ...
// Prevent default drag behavior to avoid duplication
img.setAttribute('draggable', 'false');
createResizeHandle(img);
// ... rest of code ...
}
B. Added dragstart event listener
// Prevent default drag behavior on images
const handleDragStart = (e: DragEvent) => {
const target = e.target as HTMLElement;
if (target.tagName === 'IMG') {
e.preventDefault();
e.stopPropagation();
return false;
}
};
editor.root.addEventListener('dragstart', handleDragStart);
C. Added CSS to disable drag
img: {
cursor: 'pointer',
maxWidth: '100%',
height: 'auto',
display: 'block',
margin: '12px 0',
transition: 'all 0.2s ease',
borderRadius: '4px',
userSelect: 'none',
pointerEvents: 'auto',
WebkitUserDrag: 'none', // Disable WebKit drag
userDrag: 'none', // Disable standard drag
// ... hover styles ...
}
Files Modified
/frontend/src/components/common/CustomRichEditor.tsx
Lines 274-301: Image insertion with proper Quill initialization
Lines 523-524: Set draggable="false" on image selection
Lines 735-743: Added dragstart event handler
Lines 755: Added dragstart cleanup in useEffect return
Lines 1146-1147: Added CSS properties to disable drag
Testing Recommendations
-
Test Image Insertion:
- Open any admin page with rich text editor (Articles, Activities, About)
- Click "Vložit obrázek" button
- Upload an image and crop it
- Verify image appears immediately in the editor
- Check browser console for no errors
-
Test Image Drag Behavior:
- Insert an image in the editor
- Click to select the image (blue outline appears)
- Try to drag the image left/right
- Verify alignment changes but no duplicate is created
- Verify the image doesn't create a "ghost" drag preview
-
Test Image Resize:
- Select an image
- Grab the blue corner/edge handles
- Resize the image
- Verify smooth resizing without duplication
-
Test Multiple Images:
- Insert several images
- Interact with each one
- Verify no interference between images
Browser Compatibility
The fixes use standard web APIs and should work in:
- ✅ Chrome/Edge (Chromium-based)
- ✅ Firefox
- ✅ Safari (WebKit)
The -webkit-user-drag CSS property specifically targets WebKit browsers.
Known Limitations
- The 50ms delay in image insertion is a workaround for Quill's initialization timing
- If issues persist, the delay can be increased to 100ms, but this may cause noticeable lag
- The drag prevention is comprehensive but may interfere with future drag-and-drop features if needed
Related Files
/frontend/src/components/common/RichTextEditor.tsx- Wrapper component/frontend/src/services/imageProcessing.ts- Image upload/crop backend services/frontend/src/styles/custom-editor.css- Additional editor styles
Future Improvements
- Consider migrating to Quill 2.0 when stable (better event handling)
- Add loading state during image upload to prevent multiple insertions
- Add image compression options in the crop modal
- Consider lazy loading for large images