tiptap: Dragging a Custom Node creates a duplicate

I created a custom Image Node (with a Vue Component) to be able to create resizable images. It all works fine, but when dragging / moving the image to another location in the document it creates a duplicate instead of moving the original…

`import {Node, Plugin} from ‘tiptap’; import ResizableImageComponent from ‘@/components/Editor/ResizableImageComponent.vue’;

export default class ResizableImage extends Node { public get name() { return ‘resizableImage’; }

public get schema() {
    return {
        attrs: {
            src: {
                default: null,
            },
            width: {
                default: '400px',
            },
        },
        group: 'inline',
        inline: true,
        draggable: true,
        selectable: false,
        // parseDOM and toDOM is still required to make copy and paste work
        parseDOM: [{
            tag: 'img',
            getAttrs: (dom: any) => ({
                src: dom.getAttribute('src'),
                width: dom.getAttribute('width'),
            }),
        }],
        toDOM: (node: any) => ['img', {
            src: node.attrs.src,
            width: node.attrs.width,
        }],
    };
}

public commands({type}: { type: any }) {
    return (attrs: any) => (state: any, dispatch: any) => {
        const {selection} = state;
        const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos;
        const node = type.create(attrs);
        const transaction = state.tr.insert(position, node);
        dispatch(transaction);
    };
}

public get plugins() {
    return [
        new Plugin({
            props: {
                handleDOMEvents: {
                    drop(view: any, event: any) {
                        const hasFiles = event.dataTransfer
                            && event.dataTransfer.files
                            && event.dataTransfer.files.length;

                        if (!hasFiles) {
                            return;
                        }

                        const images = (Array
                            .from(event.dataTransfer.files) as File[])
                            .filter((file) => (/image/i).test(file.type));

                        if (images.length === 0) {
                            return;
                        }

                        event.preventDefault();

                        const {schema} = view.state;
                        const coordinates = view.posAtCoords({left: event.clientX, top: event.clientY});

                        images.forEach((image) => {
                            const reader = new FileReader();

                            reader.onload = (readerEvent) => {
                                const node = schema.nodes.resizableImage.create({
                                    src: (readerEvent.target as any).result,
                                });
                                const transaction = view.state.tr.insert(coordinates.pos, node);
                                // noinspection JSIgnoredPromiseFromCall
                                view.dispatch(transaction);
                            };
                            reader.readAsDataURL(image);
                        });
                    },
                },
            },
        }),
    ];
}

// return a vue component
// this can be an object or an imported component
public get view() {
    return ResizableImageComponent;
}

}

`

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (2 by maintainers)

Most upvoted comments

The provided codesandbox doesn’t work at all for me. Probably it’s too old. I’m closing this here for now.