react-md-editor
react-md-editor copied to clipboard
THIS IS NOT AN ISSUE: HACK to Paste Image directly from clipboard
First of all, thank you very much for your excellent work.
Prepare your server
2 routes :
- Updload image /upload/new (formdata with the attribut "image" is used in this present case)
- server store image
- response (json):
{url: "[url to retrive image calling getImage], alt: "image name alternative"}
- get image /getImage/:imagename (for example)
UI
The process is as follows:
- copy the image to the clipboard
- focus on the markdown editor
- paste
- the manager tries to identify the context; if it is an image, it sends the image to the server
- the server returns the url from which the image can be accessed from the server
- the handler finishes by adding the context of the markdow :
image to the clipboard and the contents of the clipboard are pasted into the markdown editor - the markdown editor is refreshed and renders the image by calling the provided url
- +++
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,
`\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>
);
[...]
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>
),
};
thanks you so much, It helps me a lot
Can't thank you enough sir!