Has anyone implemented a drag and drop image functionality with prosemirror?
I am looking to implement a function that allows the user to drag an image file onto the editor, which will then upload the image to a server and insert an image preview into the editor on the current cursor position.
I would be great if you could give me some pointers on where I should look in order to implement this functionality.
That should insert the image at the current cursor position. Not sure how drag&drop cursor position and prosemirror’s cursor interact though. You may have to do something special to get prosemirrors current position to be equal to where the user drops the image.
You can start by getting the execCommand working with a hardcoded url. I’ve used the dev tools console to play with it. Once you get that, try getting a drop handler to exececute a hardcoded image insert. Once you got that working you’ll need to have the drop handler do the upload and set the src on the command.
It’s not published anywhere yet, but I’m working on something similar. Here’s the code for your viewing. This implementation does not upload the image, but scales it in the browser and inserts it with a data: URL. On the call to scaleImage might be a good place to insert some kind of upload.
Also, it waits for all images to load before inserting them into the document, this is to at least try to preserve order. Otherwise, you could just pm.tr.insert each image node directly.
I have implemented the drag & drop with upload similar to what @linus does. However, the problem I’m having right now is that when the editor replaces the preview image with the actual image, the preview image disappear for a moment before the real image is reloaded, which is not very nice. Does anyone know how I could make it such that the replacement is unnoticeable by the user?
Right now I’m replacing the whole image element. Would it be better to just replace the href?
pm.on('drop', function(e) {
var files = e.dataTransfer.files;
if (files.length > 0) {
e.preventDefault();
var file = files[0];
var reader = new FileReader();
reader.onload = function(e) {
let imgAttr = {
class: 'uploading',
src: e.target.result
}
let image = mySchema.node('image', imgAttr);
pm.tr.insertInline(pm.selection.anchor, image).apply();
let currentSel = pm.selection;
let newAnchor = pm.selection.anchor.move(-1);
let mr = pm.markRange( newAnchor, currentSel.anchor, {className: 'marked'});
let moveToSelection = new TextSelection(newAnchor);
pm.setSelection(moveToSelection);
options.imageUploader(file, function(err, data){
if (err) return console.error(err);
let image = mySchema.node('image', {
src: data.imageUrl
});
let newSel = new TextSelection(mr.from, mr.to)
pm.setSelection(newSel);
pm.tr.replaceSelection(image, false).apply();
});
}
reader.readAsDataURL(file);
}
});