Yevgen
Yevgen

Reputation: 797

Replace non-code text on webpage

I searched through a bunch of related questions that help with replacing site innerHTML using JavaScript, but most reply on targetting the ID or Class of the text. However, my can be either inside a span or td tag, possibly elsewhere. I finally was able to gather a few resources to make the following code work:

$("body").children().each(function() {
        $(this).html($(this).html().replace(/\$/g,"%"));
    });

The problem with the above code is that I randomly see some code artifacts or other issues on the loaded page. I think it has something to do with there being multiple "$" part of the website code and the above script is converting it to %, hence breaking things.using JavaScript or Jquery

Is there any way to modify the code (JavaScript/jQuery) so that it does not affect code elements and only replaces the visible text (i.e. >Here<)?

Thanks!

---Edit---

It looks like the reason I'm getting a conflict with some other code is that of this error "Uncaught TypeError: Cannot read property 'innerText' of undefined". So I'm guessing there are some elements that don't have innerText (even though they don't meet the regex criteria) and it breaks other inline script code.

Is there anything I can add or modify the code with to not try the .replace if it doesn't meet the regex expression or to not replace if it's undefined?

Upvotes: 1

Views: 188

Answers (2)

Daniel Beck
Daniel Beck

Reputation: 21475

Wholesale regex modifications to the DOM are a little dangerous; it's best to limit your work to only the DOM nodes you're certain you need to check. In this case, you want text nodes only (the visible parts of the document.)

This answer gives a convenient way to select all text nodes contained within a given element. Then you can iterate through that list and replace nodes based on your regex, without having to worry about accidentally modifying the surrounding HTML tags or attributes:

var getTextNodesIn = function(el) {
  return $(el)
    .find(":not(iframe, script)") // skip <script> and <iframe> tags
    .andSelf()
    .contents()
    .filter(function() {
      return this.nodeType == 3; // text nodes only
    }
  );
};

getTextNodesIn($('#foo')).each(function() {
  var txt = $(this).text().trim(); // trimming surrounding whitespace
  txt = txt.replace(/^\$\d$/g,"%"); // your regex
  $(this).replaceWith(txt);
})

console.log($('#foo').html()); // tags and attributes were not changed
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="foo"> Some sample data, including bits that a naive regex would trip up on:
  foo<span data-attr="$1">bar<i>$1</i>$12</span><div>baz</div>
    <p>$2</p>
    $3
  <div>bat</div>$0
  <!-- $1 -->
  <script>
    // embedded script tag:
    console.log("<b>$1</b>"); // won't be replaced
  </script>
</div>

Upvotes: 1

Yevgen
Yevgen

Reputation: 797

I did it solved it slightly differently and test each value against regex before attempting to replace it:

var regEx = new RegExp(/^\$\d$/);
var allElements = document.querySelectorAll("*"); 
        for (var i = 0; i < allElements.length; i++){
            var allElementsText = allElements[i].innerText;
            var regExTest = regEx.test(allElementsText);
            if (regExTest=== true) {
                    console.log(el[i]);
                var newText = allElementsText.replace(regEx, '%');
                allElements[i].innerText=newText; 
        }
}

Does anyone see any potential issues with this?

One issue I found is that it does not work if part of the page refreshes after the page has loaded. Is there any way to have it re-run the script when new content is generated on page?

Upvotes: 0

Related Questions