Form input inside an image node view

So my image is a node view. And the image has a form and text input to update the src value.

I’m trying to have the form behaves like a native HTML form where, for example, entering in the text input will automatically submit the form(this got me to messing in the stopEvent() to no avail…haha)

I’m currently trying the method as demonstrated in the footnote example. Main thing I’m now trying to achieve is to pre-populate the src value when creating the innerView:

class Image {
    constructor(node, view, getPos) {
           // ...

           const { src, alt } = node.attrs;
           const textInput = document.createElement("div"); // this element is appended to the form element

           this.innerView = new EditorView(textInput, {
            state: EditorState.create({
                doc: this.node,
                // doc: Node.fromJSON(schema, doc),
                plugins: [
                    keymap({
                        "Mod-z": () => undo(this.outerView.state, this.outerView.dispatch),
                        "Mod-y": () => redo(this.outerView.state, this.outerView.dispatch),
                    }),
                ],
            }),
            dispatchTransaction: this.dispatchInner.bind(this),
        });

I can’t find out a way to populate the src value to the this.node. So I tried to create the doc manually with Node.fromJSON(schema, doc):

        const doc = {
            type: "doc",
            content: [
                {
                    type: "paragraph",
                    content: [{ type: "text", text: src }],
                },
            ],
        };

Which manages to show my src. But, unlike passing the this.node to the doc, the undo and redo commands don’t seem to do anything inside the input.

Am I on the right track to building such use case inside a node view? I could use some pointers…

Alright creating a standalone editor just for the text input seems to work:

       this.innerView = new EditorView(textInput, {
            state: EditorState.create({
                doc: Node.fromJSON(schema, doc),
                schema,
                plugins: [
                    keymap({
                        "Mod-z": undo,
                        "Mod-y": redo,
                    }),
                    history(),
                ],
            }),
        });

Pretty sure this is not the leanest way but for now this got me out of a rut :slight_smile:

OK I got it! Things look pretty stable now.

Here are some notes in case someone in future found them helpful:

  1. I reverted the method in the footnote example and went back to solely this.dom. I was using this.contentDOM too but node.descendants() was unexpectedly giving the child contents as nodes as well.
  2. I removed draggable: true from my image schema spec. Seems like image still draggable regardless.
  3. I needed to include the selectNode() to have my text input be responsive.
    selectNode() {
        this.dom.classList.add("ProseMirror-selectednode");
    }

    deselectNode() {
        // i had to do this to prevent the image from losing focus when i interact with the form...
        if (!this.isEditing) {
            this.dom.classList.remove("ProseMirror-selectednode");
        }
    }
  1. My form is hidden initially. Then when I click the toolbar buttons to show the form, I have to call this.view.focus(); to have the text input responsive. Not sure why :sweat_smile:
  2. My stopEvent() looks like this:
    stopEvent(event) {
        // need this line so the selectNode() can work
        if (event.target.tagName === "IMG") return false;

        return true;
    }

ok that’s all i got. Sorry for all the noise haha