4

I need to wrap each asterisks on a page with <span class="red"></span>. The few things I've tried don't work. I think what this boils down to is that I need to search the page for a specific character, and I can't figure out how to do that.

JacobTheDev
  • 17,318
  • 25
  • 95
  • 158

5 Answers5

5

For not replacing the entire HTML (really bad attitude), we can do fast manipulation with elements:

var specialTags = ["script", "style"].join("|"),
    re = new RegExp("^(?:" + specialTags + ")$", "i");

for (var els = document.getElementsByTagName("*"), i = els.length; i--;) {
    var el = els[i];

    if (re.test(el.tagName))
        continue;

    for (var j = 0, childs = el.childNodes, lj = childs.length; j < lj; j++) {
        var child = childs[j];
        if (child.nodeType === 3 && child.nodeValue.indexOf("*") > -1) {
            var segments = child.nodeValue.split("*");
            for (var k = 0, lk = segments.length; k < lk; k++) {
                el.insertBefore(document.createTextNode(segments[k]), child);
                if (k < lk - 1) {
                    var span = document.createElement("span");
                    span.className = "red";
                    span.appendChild(document.createTextNode("*"));
                    el.insertBefore(span, child);
                }
            }
            el.removeChild(child);
        }
    }
}

This is pure JavaScript which does not require jQuery, that can't really help here.

DEMO: http://jsfiddle.net/T4ZXA/5/

VisioN
  • 143,310
  • 32
  • 282
  • 281
  • 1
    +999, I was _so_ close to this, got stuck on the splitting part ;) – Dogbert Apr 26 '13 at 15:25
  • The ***REAL SPEED*** of this approach is demonstrated here: http://jsperf.com/replace-text-with-tag. – VisioN Apr 26 '13 at 15:32
  • +1 Remember to add the `*` to the contents of the tag (that's what the OP wanted) – MMM Apr 26 '13 at 15:34
  • This will replace * inside script and style tags. – Daniel Moses Apr 26 '13 at 15:53
  • This will also replace content in the `` – MMM Apr 26 '13 at 16:37
  • @MMM What do you mean? `` shouldn't contain text nodes with asterisks. – VisioN Apr 26 '13 at 16:38
  • @VisioN: How about `My ** website`? Never heard that the spec does not allow that. – MMM Apr 26 '13 at 16:40
  • @MMM Then it is `` and not ``. Just add `title` to `specialTags` array, and the script will skip it. – VisioN Apr 26 '13 at 16:41
  • @MMM Of course if you need to remove entire `` from operating queue, it is better to use `querySelectorAll("body, body *")` instead of `getElementsByTagName("*")`. However `querySelector` is available only in modern browsers. – VisioN Apr 26 '13 at 16:46
  • Yes, yes, all you're saying is true and known to me, I've merely stated that if anything in the head has an asterisk, it will get replaced too ;) No need to explain yourself! – MMM Apr 26 '13 at 16:51
2

How about this?...

http://jsfiddle.net/n3Sqn/

 $("body:contains(*)").contents().each(function() {
  if(this.nodeType == 1)
  {
      $(this).html($(this).html().replace(/\*/g, "<span class=\"red\">*</span>"))
  }
});
PSL
  • 123,204
  • 21
  • 253
  • 243
  • You would want to do this on nodeType == 3 so as not to replace * in html – Daniel Moses Apr 26 '13 at 15:20
  • I was initially trying that but then it doesnt replace the text in the html so i needed to get that particular text's parent node.. hence tried use Nodetype element. Probably i was doing something wrong... – PSL Apr 26 '13 at 15:21
2

This is a bit dirty and risky (explained below), but you could try the following:

var allHTML = $("body").html();
allHTML = allHTML.replace(/\*/g, "<span class=\"red\">*</span>");
$("body").html(allHTML);

http://jsfiddle.net/6rDK4/

Note: As Dogbert pointed out this might replace * characters that are within HTML tags, e.g. node attributes.

EDIT: Bear in mind that this might reattach all the scripts you have in your body though! Try replacing body with your main container.

EDIT2: VisioN posted a more elaborate but a lot safer solution.

MMM
  • 7,221
  • 2
  • 24
  • 42
  • This would replace "*" in node attributes too. – Dogbert Apr 26 '13 at 15:04
  • @Dogbert: That's true, however I don't think you use such characters in attributes often? I'll add this to the answer though. – MMM Apr 26 '13 at 15:05
  • ugh. Unfortunately the things that I'm trying to edit do have * in the attributes. Thanks, though, this would solve the problem otherwise. I'll just have to do this statically, which is going to take much longer. – JacobTheDev Apr 26 '13 at 15:09
  • @Rev Never never never replace entire markup in a way like this. Please see [my answer](http://stackoverflow.com/a/16239900/1249581) as the way how it *should* be done. – VisioN Apr 26 '13 at 15:34
  • @VisioN: I agree, that's why I wrote it's dirty and risky, your answer is brilliant though. – MMM Apr 26 '13 at 15:36
2

Without using jQuery so it might be a little faster, and definitely not dependent on libs:

(function(str,e){
    var regex = new RegExp(str, 'gi');
    e.innerHTML = e.innerHTML.replace(regex, '<span class="red">*</span>');
})('*',document.body);
Joshua
  • 3,615
  • 1
  • 26
  • 32
1

This will work and not replace * in tags it shouldn't.

http://jsfiddle.net/DR6Ca/2/

var text = $("body").find(":contains(*)").contents().filter(function() {
    //Don't include css or script tags, all other text nodes are fine.
  return this.nodeType == 3
      && ($(this).parent().get(0).tagName.toUpperCase() !== "SCRIPT") 
      && ($(this).parent().get(0).tagName.toUpperCase() !== "STYLE");
}).replaceWith(function() {
   return this.textContent.replace(/\*/g, "<span class=\"red\">*</span>");

You can test the others code in this jsfiddle to see if they keep the "hi" blue or not. If it doesn't stay blue they have a bug.

Daniel Moses
  • 5,872
  • 26
  • 39