Prosemirror: ContentEditable=false with NodeViews causing wierd selection behavior

Created on 7 Feb 2017  路  14Comments  路  Source: ProseMirror/prosemirror

I have a NodeView that's a block element, it has no contentDOM and does not use setSelection in order to manipulate cursors.

As far as I can tell, according to this line: https://github.com/ProseMirror/prosemirror-view/blob/master/src/viewdesc.js#L429, a node like that will have its topmost div set to contenteditable=false (this is also what I see)

This causes the cursor to skip over it as you move down (just repeatedly press the down arrow for example). I've replicated this cursor behavior in plain HTML here: https://jsfiddle.net/4f94LbmL/

This is unexpected because it becomes it skips over being a selection.

I'm not sure what the ideal fix is, setting contentEditable=true in a nodeview will lead to weird behavior, but at the same time, not allowing the node to get selected through arrow keys is unintuitive. Ideally there would be some programmatic way to force the selection to happen?

Most helpful comment

I disagree, you should be able to select content that is non-editable through using the keyboard cursor. This is generally accepted behavior in editors, for example see this example in Medium: http://recordit.co/CQjPhFWafJ

I am able to select the image just by moving up and down, even though the image itself is not something you would edit (the only operation being delete to remove it)

All 14 comments

Which browser are you seeing the problem in (in ProseMirror, not in the reduced demo, since ProseMirror has another kludge which, in the cases I tested, works around this issue in Chrome)?

It's in Chrome! This GIF should show it: http://recordit.co/Hb8x2ySMjx

The actual nodeview code can be found here: https://github.com/pubpub/pubpub-editor/blob/master/packages/pubpub-prose/src/nodeviews/embedView.js

The relevant schema looks like this. In this case I've chosen not to put a contentDOM in and render the caption myself.

  embed: {
    content: "caption?",
    attrs: {
            filename: {default: ''},
            url: {default: ''},
            figureName: {default: ''},
            size: {default: ''},
            align: {default: ''},
    },
     inline: false,
    group: 'block',
    draggable: false,
  },

  caption: {
    content: "inline<_>*",
    group: "block",
    parseDOM: [{tag: "p"}],
    toDOM() { return ["p", 0] }
  },

This is unexpected because it becomes it skips over being a selection.

I'm not sure what you mean here. When you create a custom node view without a contentDOM property, you're declaring that that node isn't edited in the regular contentEditable way, so having its contentEditable attribute set to false is intentional.

Having a cursor in non-editable content is not supported (and probably not a good idea in general).

I disagree, you should be able to select content that is non-editable through using the keyboard cursor. This is generally accepted behavior in editors, for example see this example in Medium: http://recordit.co/CQjPhFWafJ

I am able to select the image just by moving up and down, even though the image itself is not something you would edit (the only operation being delete to remove it)

I would also agree with @ThariqS. I would expect non-editable to mean that you just can't edit the content within -- that the non-editable content would behave like a single character. So you can move the cursor before it, after it, select across it, and delete it when the selection is deleted but there is no going inside it.

@jbsulli That is pretty much what happens here -- the non-editable node is a block node, so if you can't put the cursor inside it, the cursor will skip it. That's how contentEditable deals with uneditable block nodes, and I think it is appropriate.

Ah, that works for me. I guess @ThariqS is advocating that when you move the cursor -- say from before the non-editable element with the right arrow key -- that the element would be selected instead of jumping to the position after?

^yes this is what I mean, maybe this functionality is supposed to work but I can't seem to get it to.

@marijnh Is that something that would be doable with a plugin?

Selecting the whole element when you arrow onto it is definitely doable with a plugin. This is the default behavior for leaf nodes, but since yours has content, that logic doesn't apply to it. It might be worthwhile to have another flag, directlySelectable or so, for cases like this. If you, as a test, remove the nearestDesc.node.isLeaf test from the readFromDOM method in prosemirror-view/dist/selection.js, is the resulting behavior what you want?

Hmm, would love a sketch of how to do it in a plugin.

I just tried editing readFromDOM and logging a few things. That change doesn't give the desired behavior, I think because the block I want to select and the paragraph node of the text that is selected are siblings instead of the block being within the paragraph. nearestDesc just returns the enclosing paragraph of the text and that is selected.

It seems like the desired behavior could be done if you check if the origin of the change is undefined (seems to be the closest approximation to keyboard selection), and check whether the node has a sibling that is not editable but selectable. But directionality is also important, (i.e. did you get to to this node from moving up or down), ideally the origin flag could give that directionality information.

No, you'd want to do this on the key binding level -- add a handler for the arrow keys with an extra keymap, and in that handler, check whether the cursor is about to hit such a node. If it is, select the node and return true, otherwise, let other handlers handle it.

I've made a bunch of changes (not released yet) which allow you to set an atom property on a node spec, which makes the node count as an atom (which leaf nodes do by default), and changed the selection logic over to using that property, rather than isLeaf. With that feature, you should be able to simply mark nodes that will render as uneditable as atoms, and have them be selectable with the default selection logic.

Okay, thanks! That makes sense. Will look out for the atom functionality.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eshvedai picture eshvedai  路  5Comments

marijnh picture marijnh  路  6Comments

thomasWajs picture thomasWajs  路  6Comments

SamyPesse picture SamyPesse  路  3Comments

stevemao picture stevemao  路  5Comments