empties surrounding marked range

Hey, it seems that when I add a markrange around just one single node, if I replace that node using tr.replaceWith, the new node is not placed inside of the range, but rather outside of it (which makes the marked range be empty). While it’s reasonably easy to handle in a single user situation (simply create a new marked range around the inserted node, it is more complex in a collaborative setup (where the replacement may be something being done on another user’s machine and one has to analyze the incoming steps very carefully to understand what is going on).

Is there any good trick to make a node that replaces another node go inside of the same marked ranges?

Have you looked at the inclusiveLeft/inclusiveRight options to ranges? Setting those to true might get you the behavior you’re looking for here.

@marijn: Adding inclusiveRight/inclusiveLeft means that anything typed before or after the range will be included in the range. That’s not exactly what I’m looking for.

I keep the marked ranges around the footnote markers to keep track of where they are and if they get deleted. The footnote marker keeps the contents of the footnote in an attribute, so every time the footnote contents are being updated, I need to use tr.replaceWith to exchange the footnote node (no way to exchange just the data of an attribute, right?) and that then triggers the marked range to be lost.

On the client where the footnote was updated, I can simply add a new marked range around the new footnote marker.

But on other collaborating clients, it is more difficult to deal with one of these marked ranges disappearing. Basically, I need to scan through the area between the footnote marker prior to this one and to the next one and see if there is any extra footnote marker in there, and if this is the case, assume that it is the footnote marker I just lost.

I tried two other strategies (unsuccesfully):

Instead of putting a marked range around the footnote marker

Main text<mR><span class="footnote" data-contents="The footnote">¹</span></mR>

which lead to the marked range becoming empty when using tr.replaceWith to exchange the footnote (in order to exchange the contents attribute of it):

Main text<span class="footnote" data-contents="The changed footnote">¹</span><mR></mR>

I set removeWhenEmpty: false and put an empty marked range in front of it, like this:

Main text<mR></mR><span class="footnote" data-contents="The footnote">¹</span>

The good thing was that now the marked range was no longer being emptied when the footnote was updated. Unfortunately, tr.replaceWith now caused the marked range to be moved after the footnote when it was exchanged:

Main text<span class="footnote" data-contents="The changed footnote">¹</span><mR></mR>

So then I tried putting the empty marked range behind the footnote marker:

Main text<span class="footnote" data-contents="The footnote">¹</span><mR></mR>

The good thing was that now the marked range would not be touched when updating the footnote:

Main text<span class="footnote" data-contents="The changed footnote">¹</span><mR></mR>

But unfortunately it was now no longer possible to remove the marked range by any conventional means. For example, selecting this part (seleciton = [])

Main t[ext<span class="footnote" data-contents="The changed footnote">¹</span><mR></mR> main text contin]uation

And hitting backspace resulted in:

Main t<mR></mR>uation

If you’re using replaceWith just to update an attribute, maybe setNodeType is a better approach? That’ll not actually remove the node, and thus make it much easier to keep the markers in place.

1 Like

Ah, I see. That is not where I would have looked as I am not changing the node type in any way. But it works! Thanks for that!

Thanks for the tip! I’ve had a very similar issue and have been using replaceWith to update attributes up until now, too. I think it would be nice to have an updateAttributes method to make it more obvious of how to achieve this. When I read setNodeType at first I did not expect to be able to update attributes using this method.

1 Like