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

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 insertEmbed was called
  • Calling insertEmbed immediately 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

  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
  • /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