0

I've seen similar questions to this one, but none solve my problem.

I have a chrome extension where I highlight some content on the page by creating a fragment and replacing characters with spans, like this:

for (const node of textChildNodes(parentNode)) {
    const fragment = document.createDocumentFragment();
    const matches = node.textContent.match(regex);
    const split = node.textContent.split(regex);
    split.forEach((content, i) => {
        fragment.appendChild(document.createTextNode(content));
        if (i !== split.length-1) {
            const clone = elem.cloneNode(true);
            clone.appendChild(document.createTextNode(matches[i]));
            fragment.appendChild(clone);
        }
    });
node.parentElement.replaceChild(fragment, node);

With "textChildNodes()" being a function that returns only the nodes that are text nodes, like this:

const textChildNodes = obj => Array.from(obj.childNodes)
    .filter(node => node.nodeName === "#text");

It works pretty well, as shown in the picture below:

enter image description here

The problem is, in cases like this (as in a Facebook post with a "See more" button), the nodes that were highlighted have the same parent as the node with "See more", as shown in the picture below:

enter image description here

When I click on "See more", the Facebook post disappears and the error below shows up on the console:

enter image description here

This doesn't happen if the button "See more" doesn't have a "sibling" node highlighted.

I have tried changing the fragment with a div and put all text nodes inside spans, but it still happens.

Maybe the parent node, when having it's children changed, loses its "identity", and then when React goes to delete something from it, it crashes? How can I fix it?

Diogo Correia
  • 95
  • 4
  • 10
  • You can override `Node.prototype.removeChild` in [page context](/a/9517879) to and simply use child.remove() inside. – wOxxOm Mar 15 '21 at 05:27
  • @wOxxOm I did the function override as you said, with "Node.prototype.removeChild = child => child.remove()" on any content script but it didn't fix the problem. I even set a script with that function to run at "document start" and "document end" in the manifest. I also tried running my highlight.js (my content script) with window.onload (doing the same "run_at" thing in the manifest) but the error stayed the same. – Diogo Correia Mar 15 '21 at 14:34
  • The answer I've linked explains in detail how that code should be executed. – wOxxOm Mar 15 '21 at 14:36

2 Answers2

0

For anyone that comes here with a similar issue, I ended up not being able to solve it, so I just abandoned the "replaceChild()" way of doing it.

@wOxxOm left a possible solution in the comment section of this question, though:

You can override Node.prototype.removeChild in page context to and simply use child.remove() inside.

Instead, I emptied the data of the node that was going to be replaced, making it "invisible" (this nodes are all text nodes, so I couldn't assign a style to it, like "display: none").

Then, I added the fragment (the highlighted node) after that first node.

This way, all nodes are preserved, and it won't throw any error. Clearly, React was trying to remove a child node that wasn't there anymore (because it had been replaced by me with "replaceChild()").

So, in the end, I went from:

node.parentElement.replaceChild(fragment, node);

to:

node.data = '';
node.after(fragment);
Diogo Correia
  • 95
  • 4
  • 10
0

Put text in tag (ex: span/div).

From this:

<span class="highlighted">Foo</spa>
Bar

To this:

<span class="highlighted">Foo</spa>
<span>Bar</span>

Hope this help!