-1

I'm trying to create a small tool(chrome extension) that will replace some unwanted words from a page. I'm using replaceAll function to do this. It seems to work well on normal sites but it causes some issues on social media sites.

document.body.innerHTML = document.body.innerHTML.replaceAll('game', 'work');

When I run it on twitter or other social media sites it disables some of the buttons which makes the page unusable. Is there some other way to do this without affecting those elements?

enter image description here

Grasper
  • 1,293
  • 12
  • 26
  • 2
    Calling this on `innerHTML` is affecting the entire HTML of the page so all class names, IDs, element names & data, script names, etc etc. – pilchard Aug 31 '23 at 15:54
  • 1
    Why replace in the whole HTML? That will replace classes, property values and who knows what else. Just replace the text in tags – VLAZ Aug 31 '23 at 15:54
  • it will not replace the classes because I'm changing hashed strings and only on the fly. `textContent` makes it even worse! – Grasper Aug 31 '23 at 16:06
  • Can you provide a [mcve]? At least you should provide more debugging details. What are the exact problems. How does your current code cause these problems? – jabaa Aug 31 '23 at 16:09
  • @jabaa just run `document.body.innerHTML = document.body.innerHTML.replaceAll('work', 'work');` in your console and see it for yourself. – Grasper Aug 31 '23 at 16:11
  • Stack Overflow is a question and answer platform with the goal to help future users with similar problems. This only works if the question contains all necessary details. If it's necessary to visit an external website, this won't work. The external website could change in the future and the question and answers become useless. Create a small example that reproduces the problem and post it in the question or at least describe the problem. _"Doesn't work"_ isn't a good problem description. – jabaa Aug 31 '23 at 16:12
  • @jabaa, this issue happens on an external website. How else can I give you example? This is a simple question and anyone can run an example just by coping the code I provided in their console while logged in to twitter. – Grasper Aug 31 '23 at 16:14
  • If you can't provide a complete question containing all necessary details, this is usually the wrong platform for your question. If it's necessary to visit an external website, this question isn't complete and answerable. – jabaa Aug 31 '23 at 16:15
  • @jabaa, I tagged this as chrome-extension. This is how these extensions work. They visit external sites. If you don't know the answer please avoid commenting. – Grasper Aug 31 '23 at 16:19
  • I'm asking for an example where your extension won't work or debugging details why your extension doesn't work. At least the debugging details shouldn't be too much to provide. – jabaa Aug 31 '23 at 16:21
  • @jabaa, I told you to load twitter and run the code in the console of your browser and you will see. – Grasper Aug 31 '23 at 16:22
  • Have you debugged it? What's the actual problem? What is broken? Why does it not work? Did you run your debugger? Do you expect others to debug minimized production code for you? – jabaa Aug 31 '23 at 16:23
  • @jabaa, lol. Please read my question. The code works but breaks some of the html functionality. The debugger can't detect this. The inspector might but it's hard to see. – Grasper Aug 31 '23 at 16:26
  • What is an HTML functionality? Functionality in HTML is usually related to JavaScript which can be analyzed using your debugger. There are event listeners, that are registered for HTML elements. I have no idea how a like or retweet could work or how states of HTML elements could be dynamically changed without JavaScript. – jabaa Aug 31 '23 at 16:27
  • Replacing innerHTML is like going to a whiteboard and erasing everything and redrawing it all to add one new item. You just removed all event handlers attached to all the elements on the page. – epascarello Aug 31 '23 at 17:32
  • And don't forget that replacing the HTML can/will affect event handler bindings. – Scott Marcus Aug 31 '23 at 17:35
  • @ScottMarcus, yeah, The duplicate question nicely explains what is happening... It kind of suck I can't replace with HTML but I can live with it. Thanks – Grasper Aug 31 '23 at 17:45

1 Answers1

1

There is no need to run a replacement over the entire HTML. At best it works by accident, there is a big chance it replaces something important. Moreover, this will re-parse the entire DOM and re-insert it which is what most likely breaks the entire page as this can potentially wipe out event listeners and reset a lot of other things.

The correct way would be to only replace the text in text nodes. Use a TreeWalker (constructed via document.createTreeWalker to that effect.

Example application that replaces the word "foo" with something else of choice:

function replace(oldWord, newWord) {
  const regex = new RegExp(`\\b${oldWord}\\b`);
  
  //create a TreeWalker that goes only over text nodes
  const treeWalker = document.createTreeWalker(
    document.body,        // start node
    NodeFilter.SHOW_TEXT, // filter out anything but text nodes
    { 
      // additional filtering - only where the text matches the replacement
      acceptNode: node => regex.test(node.textContent) 
        ? NodeFilter.FILTER_ACCEPT 
        : NodeFilter.FILTER_SKIP 
    } 
  );
  
  //go over matching nodes...
  for (
    let currentNode = treeWalker.nextNode(); 
    currentNode != null;
    currentNode = treeWalker.nextNode()
  ) {
  debugger;
    // ...and replace their content
    currentNode.nodeValue = currentNode.textContent.replaceAll(new RegExp(regex, "g"), newWord);
  }
}

document.querySelector("button")
  .addEventListener("click", () => {
    const replacement = document.querySelector("#replacement").value;
    replace("foo", replacement);
  });
div.foo {
  background: yellow;
}

span.foo, 
span[data-foo], 
[data-custom-attribute="foo"] {
  text-decoration: underline;
}
<div class="foo bar">
  <span class="foo">Lorem ipsum</span> foo <span data-foo="customvalue">dolor sit amet</span>, <span data-foo="customvalue">consectetur foo adipiscing foo elit</span>, <span>foo</span> <span data-custom-attribute="foo">sed do eiusmod tempor incididunt ut labore</span> et dolore magna aliqua.

  <hr/>
  
  <div>the rest will not be replaced as the word is inside other letters</div>
  <div>foobar</div>
  <div>barfoo</div>
  <div>barfoobar</div>
</div>
<br/>

<label for="replacement">Replace with:</label>
<input type="text" placeholder="replacement" value="banana" id="replacement" />
<br />
<button type="button">replace</button>
VLAZ
  • 26,331
  • 9
  • 49
  • 67