Files
MyClub/DOCS/RICH_TEXT_EDITOR_IMAGE_FIX.md
Tomas Dvorak 68e69e00cc dev day #65,5
2025-10-20 10:40:55 +02:00

177 lines
5.7 KiB
Markdown

# 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 `insertEmbed` was called
- Calling `insertEmbed` immediately after upload without ensuring the editor is ready caused the emitter to be undefined
**Solution**:
```typescript
// 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
```typescript
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
```typescript
// 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
```typescript
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
1. **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
2. **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
3. **Test Image Resize**:
- Select an image
- Grab the blue corner/edge handles
- Resize the image
- Verify smooth resizing without duplication
4. **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
1. Consider migrating to Quill 2.0 when stable (better event handling)
2. Add loading state during image upload to prevent multiple insertions
3. Add image compression options in the crop modal
4. Consider lazy loading for large images