nodeViews with contentDOM stops the cursor movement for a node with "text*" content

I made an example at https://glitch.com/edit/#!/sprinkle-hazel-meadowlark?path=index.js%3A18%3A17

You can move the cursor downwards with keyboard (myblock -> mytag -> other stuff). And when you try to move the cursor upwards instead, you will find it stops at mytag.

And if you replace the content of mytag from text* to paragraph, the issue disappears.

But I want to keep the content as text*, while no problem for the cursor movement. How could I make it?

Sorry, the glitch link no longer appears to work, and there’s not enough context in the message to reconstruct what you may be doing. Could you fix/update/recreate the glitch page?

OK, it is now here https://glitch.com/edit/#!/temporal-quixotic-dandelion?path=index.js%3A40%3A0

1 Like

Really sorry, but both those links cause Glitch to fail with “Well, you found a glitch” when I try to open them (both when logged in and when logged out). Other glitches work for some unfathomable reason. Could you paste your code on https://gist.github.com/ or something so that I can get at it?

I came across the same issue. This is my NodeSpec and NodeView

// NodeSpec
const tag = {
  content: "text*",
  parseDOM: [
    {
      tag: 'div.tag',
    },
  ],
  toDOM: () => ['div', {class: 'tag'}, 0],
}
// NodeView for `tag`
class View {
  constructor(node, view, getPos) {
    const dom = document.createElement('div')
    const label = document.createElement('label')
    label.innerText = 'tag'
    this.contentDOM = document.createElement('div')
    dom.appendChild(label)
    dom.appendChild(this.contentDOM)
    this.dom = dom
  }
}

And I have several tag nodes in my document. The cursor cannot be moved upwards.

p.s. gist.github.com or glitch.com is not accessible from my country :sob:

https://codesandbox.io/ is a great alternative to glitch, does that work in your country ?

And if you replace the content of mytag from text* to paragraph, the issue disappears.

I had the exact same issue in this example for my library and changing the text* to paragraph fixed it.

I narrowed the problem to the ignoreMutation handler of the nodeView. From what I understand, this handler tells Prosemirror to handle the mutation event which itself creates an empty text node in response to the mutation event.

Here is my ignoreMutation handler, pay attention to if (mutation.target === this.contentDOM) { clause:

ignoreMutation(mutation) {
    // For PM an atom node is a black box, what happens inside it are of no concern to PM
    // and should be ignored.
    if (this._node.type.isAtom) {
      return true;
    }

    // donot ignore a selection type mutation
    if (mutation.type === 'selection') {
      return false;
    }

    // if a child of this.dom (the one handled by PM)
    // has any mutation, do not ignore it
    if (this.dom.contains(mutation.target)) {
      return false;
    }

    // <!---THIS CONDITION FIXES THE PROBLEM -->
    // if the this.dom itself was the target
    // do not ignore it. This is important for schema where
    // content: 'inline*' and you end up deleting all the content with backspace
    // PM needs to step in and create an empty node for us.
    if (mutation.target === this.contentDOM) {
      return false;
    }

    return true;
  }

you can see full code here

Yes, changing the text* to paragraph fixed the issue, with the resulting content wrapped in a paragraph node. Though I can post-process it, I’d like keep it text*.
And then I tried your ignoreMutation, it did not help.

p.s. I made a demo at https://codesandbox.io/s/prosemirror-example-forked-8uixe?file=/src/index.js

Setting contentEditable=false on the label seems to solve the cursor problem. Generally, if you’re going to add non-content DOM structure in a node view, you have to make sure you set it uneditable, or the browser will move the cursor into it (and then ProseMirror will move it out again because it doesn’t consider that position a valid selection endpoint).

Nice to know it. Thank you.

BTW, I can not select all the content by Ctrl+A any more with those labels. Is this an expected behavior of Prosemirror?

As in, the labels don’t show up as selected, or the actual selection doesn’t span the entire document? The latter would be a bug—are you using the selectAll command or relying on some native behavior from a menu? (If so, which platform/menu?)

It does not span the entire document. In fact I tried to copy the whole document after hitting Ctrl-A, nothing copied. I did not use the selectAll command. I am on MacOS with the latest chrome.

The base keymap binds Cmd-A to selectAll. Are you including that binding?

Yes, I can do it after removing those labels.