Cursor position when moving between nodes


#1

Greetings,

That might be a silly question but I am stuck at implementing a working solution.

I have the following node structure

<parent>
<foo>AAAAA</foo><bar>BBBBB</bar><baz>CCCCC</baz>
</parent>

where the spec is as follows: parent - { content: ‘foo bar baz’, toDOM: node => [‘parent’, 0] }

foo - {
  content: 'text*',
  toDOM: node => ['foo', 0],
  inline: true
}

bar - {
  content: 'text*',
  toDOM: node => ['bar', 0],
  inline: true
}

baz- {
  content: 'text*',
  toDOM: node => ['baz', 0],
  inline: true
}

Upon moving the cursor position, I am not able to place it before the first “B” at the beginning of node. It moves directly after the first “B” as shown on the screenshot. That also makes impossible selecting the position before the first “B” manually - the cursor appears there but it is actually at the end of node image

Is the way I am implementing the schema wrong or is that the expected behaviour? I’ve found a possible solution using a zero-width non-break space but here comes the second question: How to insert it around the node in order to wrap it? Couldn’t find and example usage of inserting unicode chars ;(

Any suggestions would be appreciated! Thank you in advance!


#2

Inline nodes with content don’t really work well without a lot of custom scripting. See this thread.


#3

Thank you for the info regarding this topic!

While I was experimenting with different approaches to find a workaround for my issue, I came to the idea of

  1. inserting another inline node (let’s call it inline-separator) which contains a single space. That way when the cursor is pointed at the beginning of bar before the first “B”, it will be actually inside the inline-separator node after the space.
  2. creating a plugin with appendTransaction which moves the selection if it hits inside inline-separator to my next inline node.

const $cursor = newState.selection.$cursor;

if ($cursor.parent.type === newState.schema.nodes.inlineSeparator) {
    const newSelection = TextSelection.near(newState.doc.resolve($cursor.after() + 1));
    return newState.tr.setMeta(this.key, true).setSelection(newSelection);
}

That indeed moved the cursor at the beginning of bar before the first “B”, yet when typing new characters, they were placed inside the separator node ;(

  1. That leads me to another idea - what if instead of intercepting the cursor being placed inside the separator node, I do it when there is any input inside it - rollback the change and place the same input at the beginning of the bar node, then put the cursor position after the input. Example: image

I could skip the case when the user pastes content at that position for now, so the normal use-case scenario should be the user putting the cursor at that position, typing a char, after which the alghoritm described above should remove the char from that position, place it at the beginning of the content of the next sibling node and put the cursor position after it.

Since I do not have much experience with PM, has anyone done something like that before? Usually such hacks come with a price… And should I do all this inside a single appendTransaction or somewhere else or should I split it inside different methods - e.g. handleTextInput seems to be a good place to intercept newly entered symbol inside the node?

Thank you in advance!