skip to Main Content

I’m looking to match strings in a .json list called "mylist" with visible strings only on any webpage any time they appear. Matching strings would be replaced with the term "REPLACED!" below in the script.

The most important thing is that the script should work on modern browsers and not degrade page loading performance. So I’d appreciate any optimization tips!

Here’s what I have got so far:

@resource      mylist https://example.com/mylist.json

(function(){
var mylist = JSON.parse(GM_getResourceText("mylist"));
var regexp = new RegExp('\b(' + mylist.join('|') + ')\b(?!\)\))', "gi");
 
function walk(node) {
    var child, next;
 
    switch ( node.nodeType )
    {
        case 1:
        case 9:
        case 11:
            child = node.firstChild;
            while ( child )
            {
                next = child.nextSibling;
                walk(child);
                child = next;
            }
            break;
 
        case 3:
            handleText(node);
            break;
    }
}
 
function handleText(textNode) {
    textNode.nodeValue = textNode.nodeValue.replace(regexp, 'REPLACED!');
}
 
walk(document.body);
})();

I’ve made a sample here: https://jsfiddle.net/xgnocwbq/

The biggest issue I am facing is that on some pages, the script works. On others, it does not work at all. For example, on Qwant search results, my code doesn’t work at all. Yet on Google search results, it does.

2

Answers


  1. JavaScript replace visible text Regex

    First of all there are some major problems in your code:

    • Dynamic Content: Websites like Google or Facebook use special methods like AJAX to refresh and update content without reloading the whole page. Your code only looks at the page once, when it first loads. If more stuff appears on the page later, your code won’t see it. By using the MutationObserver you can handle dynamic content with ease.

    • Performance: Currently you are iterating over each node, which can be slow on pages with a large number of DOM elements. Use document.querySelectorAll to increase performance. It only grabs text nodes, which is a faster approach.

    Here is an adjusted version of your code:

    @resource mylist https: //example.com/mylist.json
    
        (function() {
            var mylist = JSON.parse(GM_getResourceText("mylist"));
            var regexp = new RegExp('\b(' + mylist.join('|') + ')\b(?!\)\))', "gi");
    
            function handleText(textNode) {
                textNode.nodeValue = textNode.nodeValue.replace(regexp, 'REPLACED!');
            }
    
            function processNode(node) {
                if (node.nodeType === 3) {
                    handleText(node);
                } else {
                    let childNodes = node.querySelectorAll('*');
                    childNodes.forEach(processNode);
                }
            }
    
            // Processes the initial page content
            processNode(document.body);
    
            // Observes the changes in the DOM to handle dynamic content
            const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach(processNode);
                });
            });
    
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        })();
    

    If the refined script still does not work on certain websites, it’s essential to inspect the site closely, using browser developer tools, to understand its specific behaviours or obstructions that might be interfering with your code.

    Login or Signup to reply.
  2. Fixing @AztecCodes work, the only issue is using the querySelector() function, where instead you should use childNodes attribute.

    (function() {
      var mylist = JSON.parse(GM_getResourceText("mylist"));
      var regexp = new RegExp('\b(' + mylist.join('|') + ')\b(?!\)\))', "gi");
    
      function handleText(textNode) {
          console.log("Replacing text")
          textNode.nodeValue = textNode.nodeValue.replace(regexp, 'REPLACED!');
      }
    
      function processNode(node) {
          if (node.nodeType === 3) {
              handleText(node);
          } else {
              node.childNodes.forEach(processNode);
          }
      }
    
      // Processes the initial page content
      processNode(document.body);
    
      // Observes the changes in the DOM to handle dynamic content
      const observer = new MutationObserver((mutations) => {
          mutations.forEach((mutation) => {
              mutation.addedNodes.forEach(processNode);
          });
      });
    
      observer.observe(document.body, {
          childList: true,
          subtree: true
      });
    })();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search