mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-03 18:22:57 +00:00
177 lines
5.7 KiB
Markdown
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
|