Multiple events

Hello,

I have a (Video-like) plugin which render an iframe on which I’d like to prevent click on it if I’m in editable mode. My code looks like:

renderHTML({node, HTMLAttributes}) {       
    return [                 
        'iframe', 
        mergeAttributes({ class: "pointer-events-none"}, HTMLAttributes)
    ]                                                                          
},                           

addProseMirrorPlugins() {
    return [ 
        new Plugin({
            key: new PluginKey('handleClickVideo'),
            props: {
                handleClick(view, pos, event) {
                    const DOMnode = view.nodeDOM(pos)
                    if (DOMnode?.getAttribute('data-type') == 'youtube') {
                        const $pos = view.state.doc.resolve(pos)
                        const node = view.state.doc.nodeAt(pos)

                        if (node.type.name == 'video') {
                            nodeSelected.value = {
                                node: node,
                                pos: pos
                            }
                            nodeHover.value = {
                                node: node,
                                pos: pos
                            }

                            if (!view.editable) {
                                DOMnode.classList.remove('pointer-events-none')
                            }
                        }
                        return true
                    }
                }
            }
        })
    ]
}

It works more or less, but the problem is that I have another event handler in another plugin:

props: {

    /*
     * Handle DOM events to update nodeSelected and/or nodeHover.
     * For each event handler we have to find the ProseMirror Node at
     * "event.target" place. All what we have in the "event" is "raw" pure
     * DOM Node with no relationship to ProseMirror details. 
     * To retrieve ProseMirror Node we use the "postAtDOM" function (which
     * gives a document position that corresponds to the node you give it)
     */

    handleDOMEvents: {
        click(view, event) {
            event.preventDefault()
            const target = event.target
            const children = Array.from(target.parentNode?.childNodes || [])
            const offset = children.indexOf(target)
            let pos = Math.max(
                view.posAtDOM(target.parentElement, offset),
                0
            )

            let node = view.state.doc.nodeAt(pos)

            if (!node || node.isText) {
                const $pos = view.state.doc.resolve(pos)
                pos = $pos.before()
                node = view.state.doc.nodeAt(pos)
            }

            nodeSelected.value = {
                node: node,
                pos: pos
            }

            nodeHover.value = null
        }
},

Is there a way in the handleDOMEvents “click” event handler to '“check” if it has already been handled in the handleClick, or cancel it ..? What’s the proper way to handle or reorder things in event handlers?

Thanks!

ProseMirror runs handleDOMEvents handlers before specific ones like handleClick. Whenever a handler returns true or calls preventDefault on the event, no further handlers are ran.

Thanks! Curiously, the opposite happens: the handleClick runs before the handleDOMEvents click handler… I’ll try to understand why

Oh, right, handleClick gets dispatched on the mousedown event, which will precede the DOM click event. I wrote that assuming you were binding mousedown instead of click.

Right, thanks! Is there a proper/better way to handle interactions between event handlers (for example check is x has already been handled in some handler, etc) ?

If you return true on handling an event, further handlers will simply not be called. Handlers of the same type are called in the order in which they appear in your plugins array.