Paste image from clipboard #404
-
First of all, thanks for the great plugin! Is there any ability to paste an image directly into the text (without using a modal), or any way to integrate the file-handler extension? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
This has been brought up a couple of times, but it's not a straight forward integration. I'm open to PRs, but it's still has to work with curator too. |
Beta Was this translation helpful? Give feedback.
-
Here is a raw example of custom extension: extensions.js import EventHandler from "./eventHandler.js";
window.TiptapEditorExtensions = {
eventHandler: [EventHandler],
} eventHandler.js import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from '@tiptap/pm/state'
const ALLOWED_MIME_TYPES = [
'image',
'application/msword', // .doc
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // docx
'application/pdf', // pdf
'application/vnd.ms-powerpoint', // ppt
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // pptx
'application/rtf', // rtf
'text/plain', // txt
'application/vnd.ms-excel', // xls
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // xlsx
]
const EventHandler = Extension.create({
name: 'eventHandler',
addProseMirrorPlugins() {
return [
new Plugin({
editor: this.editor,
key: new PluginKey('eventHandler'),
props: {
handlePaste(view, event) {
const items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (const item of items) {
event.preventDefault();
this.props._processFile(view, item.getAsFile());
}
},
handleDrop(view, event) {
const hasFiles =
event.dataTransfer &&
event.dataTransfer.files &&
event.dataTransfer.files.length
if (!hasFiles) {
return;
}
event.preventDefault();
Array.from(event.dataTransfer.files).forEach(image => {
this.props._processFile(view, image);
})
},
_isFileValid(file) {
let valid = false;
ALLOWED_MIME_TYPES.forEach((type) => {
if (file?.type?.indexOf(type) === 0) {
valid = true;
}
});
return valid;
},
_processFile(view, file) {
if (! this.props._isFileValid(file)) {
return;
}
console.log('File valid');
const {schema} = view.state;
const wire = Livewire.all().filter(instance => instance.name === 'YOUR_LIVEWIRE_COMPONENT_NAME')[0]?.$wire;
let saved = false;
const reader = new FileReader()
const isImage = file.type.indexOf('image') === 0;
if (!wire && isImage) {
reader.onload = readerEvent => {
const node = schema.nodes.image.create({
src: readerEvent.target.result,
});
const transaction = view.state.tr.replaceSelectionWith(node);
view.dispatch(transaction)
};
reader.readAsDataURL(image)
return;
}
if (wire) {
wire.upload('file', file, () => {
wire.dispatchSelf('tiptap-file-uploaded')
wire.on('tiptap-file-saved', (params) => {
if (saved) return;
const data = params[0];
let node;
if (data.is_image) {
node = schema.nodes.image.create({
src: data.url,
});
const transaction = view.state.tr.replaceSelectionWith(node);
view.dispatch(transaction);
} else {
this.spec.editor.commands.insertContent(
`<a href="${data.url}" target="_blank">${file.name}</a>`
);
}
saved = true;
})
})
}
}
},
}),
]
},
})
export default EventHandler
` |
Beta Was this translation helpful? Give feedback.
Here is a raw example of custom extension:
extensions.js
eventHandler.js