uiwjs / react-md-editor

A simple markdown editor with preview, implemented with React.js and TypeScript.
https://uiwjs.github.io/react-md-editor
MIT License
2.03k stars 149 forks source link

THIS IS NOT AN ISSUE: HACK to Paste Image directly from clipboard #619

Open dhenry123 opened 5 months ago

dhenry123 commented 5 months ago

First of all, thank you very much for your excellent work.

Prepare your server

2 routes :

UI

The process is as follows:

With React, build your component

[...]

// Image upload to server
const imageUploadHandler = async (
    image: File
  ): Promise<{ alt: string; url: string } | null> => {
    if (image && image.size === 0) return null;
    const formData = new FormData();
    formData.append("image", image);
    //formData.append("what else you want", "your value");
    const response = await fetch('/upload/new', {
          method: 'POST',
          body: formData
        })
    return  (await response.json()) as { alt: string, url: string }
};

  const handlePaste = async (event: React.ClipboardEvent<HTMLDivElement>) => {
    // Access the clipboard data using event.clipboardData
    const clipboardData = event.clipboardData;
   // only if clipboard payload is file
    if (clipboardData.files.length === 1) {
      const myfile = clipboardData.files[0] as File;
     // you could perform some test: image size, type mime ....
      const url = await imageUploadHandler(myfile);
      event.preventDefault();
      if (url) {
       // change clipboard payload,
       // document execCommand is obsolete, you could replace with navigator.clipboard API but some browser
      // accept write() method only if the connexion is secure (https)...
        document.execCommand(
          "insertText",
          false,
          `![${url.alt}](${url.url})\n`
        );
      } else {
        document.execCommand(
          "insertText",
          false,
          "ERROR Image has not been stored on server"
        );
      }
    }
  };
 return (
    <div className={`MarkDownEditor`}>
      <MDEditor
       [...]
       // because the MDEditor interface is an extends of textarea props
       // you can use all the methods provided by this interface
      // e.g. add a method for dragging and dropping a file...
        onPaste={handlePaste}
       [...]
      />
    </div>
  );
[...]
BenchBadr commented 4 months ago

This works too

 useEffect(() => {
      const handlePaste = async (event) => {
        const clipboardData = event.clipboardData || window.clipboardData;
        if (clipboardData && clipboardData.items) {
          for (const item of clipboardData.items) {
            if (item.type.indexOf('image') !== -1) {
              const blob = item.getAsFile();
              const reader = new FileReader();
              reader.onload = () => {
                const base64Data = reader.result.split(',')[1];
                // console.log('Base64 Image Data:', base64Data);
                uploadImageToAPI(base64Data, event)
              };

              reader.readAsDataURL(blob);
            }
          }
        } else {
          // console.log('Text Data:', clipboardData.getData('text'));
        }
      };

      const textInput = document.querySelector('.w-md-editor-text-input');
      if (textInput) {
        textInput.addEventListener('paste', handlePaste);
      }

      return () => {
        if (textInput) {
          textInput.removeEventListener('paste', handlePaste);
        }
      };
    }, []);

I also added a little loader in the toolbar :

const upload = {
    name: "upload",
    keyCommand: "upload",
    buttonProps: { "aria-label": "Insert help" },
    icon: (
          <div className="material-icons-outlined" style={{fontSize:'12px',animation:'spin 2s linear infinite',display:['none','block'][uploading]}}>cached</div>
    ),
  };
AizenSosike commented 2 months ago

thanks you so much, It helps me a lot