0

I'm writing a simple Firefox web extension, which will replace certain words (e.g. acronyms) with expanded versions. My code is as follows:

var replacements = [];
replacements["example1"] = "My First Example";
replacements["example2"] = "Second Example";

if(!window.location.href.startsWith('https://ignore.thissite.com/')){
    for(key in replacements){
        replaceOnDocument(new RegExp('\\b'+key+'\\b', 'gi'), '{{{REPLACE_'+key+'}}}');
        document.body.innerHTML = document.body.innerHTML.replace(new RegExp('{{{REPLACE_'+key+'}}}', 'g'), '<abbr title="'+key+'">'+replacements[key]+'</abbr>');
    }
}

function replaceOnDocument(pattern, string){
    Array.from(document.querySelectorAll("body, body *:not(script):not(noscript):not(style):not(code):not(pre)"))
        .forEach(someNode => Array.from(someNode.childNodes)
        .filter(childNode => childNode.nodeType == 3)
        .forEach(textNode => textNode.textContent = textNode.textContent.replace(pattern, string)));
}

This seems to replace all the instances as expected, but I've noticed that Javascript doesn't seem to run correctly on pages that the script has run on. I've been staring at the code for half an hour now and can't work out why that would be the case. To make things worse, the problem seems to be intermittent (although happens more often than not).

Any ideas as to why my code would prevent Javascript running as expected?

2
  • Since you are replacing the the whole body.innerHTML which may contain script tags as well, you may end up replacing necessary function names or variables too. Even if this is not the problem, replacing the whole body content seem dangerous to me. Commented Dec 18, 2017 at 16:11
  • Possible duplicate of script tag create with innerHTML of a div doesn't work Commented Dec 18, 2017 at 18:28

1 Answer 1

1

I already speculated that replacing the content of body.innerHTML may cause issues, so how about using the following approach for replacing text? codepen example

const walker = document.createTreeWalker(
  document.body,
  NodeFilter.SHOW_TEXT,
  {
    // filter / exclude tags
    acceptNode: function (node) {
      return node.parentElement.nodeName === "SCRIPT" ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_ACCEPT;
    }
  }
);

while (walker.nextNode()) {
  // replace every H with @
  walker.currentNode.nodeValue = walker.currentNode.nodeValue.replace("H", "@");
}

This iterates over every text node excluding script text nodes and replaces their content.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.