Overlapping Decorators

I am successfully marking up my document with decorators but have an issue with nested selected states. I use handleClick in my plugin to get the decorator key & use that to apply a selected class to the decorator that matches the key.

However, when dealing with nested decorators like this:

<p>
    Shakespeare goes on to show that having too much
    <mark key="_c5875" class="annotate-clarity">
        <mark key="_5981" class="annotate-inclusivity">ambition</mark>
    </mark>
    <mark key="_c5875" class="annotate-clarity"> and</mark> total control of power is just as bad.
</p>

I can easily end up with orphaned selected decorators, e.g. I’ve selected a decorator elsewhere in the document but the word ‘ambition’ remains selected even when my code only has 1 decorator with the selected state.

The markup ends up like this:

<p>
    Shakespeare goes on to show that having too much
    <mark>
        <mark key="_5981" class="annotate-inclusivity selected">ambition</mark>
    </mark>
    <mark key="_c5875" class="annotate-clarity"> and</mark> total control of power is just as bad.
</p>

Any suggestions on how to tackle?

Thanks

Decorations stop appearing in the document when you stop providing them from your plugin, so the solution would probably involve the way you are generating/maintaining your decoration set.

(This sounds a bit like you’re mutating the DOM or the decoration objects—that doesn’t work, in case that wasn’t clear.)

mutating the DOM or the decoration objects

I’m adjusting the class supplied to the decorator, e.g.

    Decoration.inline(
      annotation.from,
      annotation.to,
      {
        nodeName: "mark",
        class: `${className}${isSelected ? " selected" : ""}`,
        key: annoObj.id
      },
      { id: annoObj.id }
    )

I know this is old, but I am nearly positive I am still seeing this issue.

To clarify @jameswragg’s problem, I am toggling classes on inline decorations by removing the old decoration and then adding it back with the updated class. I am still seeing incorrect behavior, after doing these types of add / replaces. (Initial state is fine)

I am seeing two different DOM structures being rendered from the above after interaction, based on click order, and neither is what I’d consider ideal.

Here is before any interaction, and the “perfect” DOM structure:

And here are the bad states (imo)

In this one I clicked the inner decoration and then the outer. See the empty tag

Then clicking back into the inner, also bad result: The outer decoration now has a gap where the inner decoration is

Perhaps interesting, I’ve also noted that when I don’t specify nodeName in the Decoration.inline attributes, the initial render without interaction doesn’t work at all. That is, the outer decoration completely wipes out the rendered DOM (but the plugin DecorationSet state still has the two decorations)

Also, the 2015 post has key attribute for Decoration.inline. I don’t see that in the up to date reference (but still see it for Decoration widget and node types. Was that removed?

I don’t believe I am doing anything other than simple DecorationSet.remove([old]).add(doc, [updated]) calls. Perhaps these are not intended to be called successively and/or there is something in the code that is choking or failing to completely invalidate what’s necessary to get back to the first state (first picture?) What I didn’t try was removing all touched decorations, perhaps this may be a workaround, but found this thread first and figured I post.

I’d appreciate any feedback whatsoever. Thanks.

If you can reduce this to a minimal code example I’ll take a look.

Hey, returning with a minimal example that I tried to add helpful console logging to as you are changing cursor position:

In short, there appears to be indeterminate html rendered based on how decorations are added / removed? Only on initialization is the inner comment bolded (see legend in the example for explanation.)

I might be doing something wrong in the example in setActiveComments or replaceComment which would probably be fairly easy for you to recognize … or there is something up with the library decoration render code.

The problem is further exacerbated when you removed nodeName from the inline decoration and let it be the default <span> In this case, the inner comment doesnt render at all, leading me to think I am either using decorations wrong and need to split them at borders (not allow overlaps) or there is a problem with the library code as it attempts to rebuild the DOM.

Ah, that was definitely a bug, which I guess no one ran into yet because it only manifested when you had multiple levels of added nodes from decorations. This patch should help.

1 Like

Works great with all my test cases. Thanks for the quick patch and your work as a whole :+1: