0

I'm trying to search a page for all numbers, and selectively increase the font size only on numbers. So for the header "Over $3000" only '3000' should increase size. So far I have tried this, and a few other permutations on the same theme, but no dice. Any ideas?

$(function () {

   function replaceText(i,el) {
      var regex = /(\d+)/g;
      if (el.nodeType === 3) {
          if (regex.test(el.data)) {
              $(el).css('font-size', '30px');
          }
      } else {
          $(el).css('font-size', '30px');
      }
    }

    $('body').each( replaceText );

});
coolalligator15
  • 105
  • 2
  • 8

1 Answers1

2

What you could use is the .html() method. You can access the HTML of the element in a function as the second argument. However, using body as a selector is dangerously broad—narrowing down your range of selectors will also help greatly with performance.

Mistake: using .html() is extremely risky because you might end up replacing numerical attributes in HTML elements/tags. A better solution would be to fetch the text nodes in all children of the <body> element (although changing the selector to be more specific will help), using a previously published method, will work.

The code consist of two loops:

  1. The first loop iterates through all descendents of the <body> element, i.e. using $('body').find('*').each(function() {...});—this is very costly. You should narrow down your selectors to achieve better performance.
  2. The second loop occurs after retrieving the content of each child, using .contents(), and then filtering based on node type using .filter(). This gives us all text nodes in the body element. We simply replace these text nodes with the regex you have defined.

p/s: It's a good idea to separate the styling from your JS code, unless it has to be specific depending on context. Otherwise, simply declare an appropriate class and style it any way you desire:

$('body').find('*').each(function() {
  $(this).contents().filter(function () {
    return this.nodeType === 3;
  }).each(function () {
    $(this).replaceWith($(this).text().replace(/(\d+)/g, '<span class="number">$1</span>'));
  });
});
span.number {
  font-size: 30px;
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Over $2000.</p>
<div><p>Over $3000.</p></div>
Community
  • 1
  • 1
Terry
  • 63,248
  • 15
  • 96
  • 118
  • 2
    Pretty bad solution, as it will remove bound event handlers. However, if there are none, then it's okay. – dfsq Sep 13 '15 at 21:28
  • 2
    Another problem is with the RegExp - it will also add span inside attributes with numeric value - `` for example. – Ori Drori Sep 13 '15 at 21:29
  • 1
    @OriDrori You're correct. Made a mistake right there—using `.contents().filter()` to retrieve text nodes only is a lot safer. – Terry Sep 13 '15 at 21:44
  • @Terry - this looks nice. Maybe the TreeWalker in this [answer](http://stackoverflow.com/a/10730777/5157454) can help? – Ori Drori Sep 13 '15 at 21:55