0

Using Javascript of jQuery I want to swap a string of text for an html tag, over and over, without losing the previous html.

FIDDLE

<p>This is <i id="text">text</i> and more text</p>

This is text and more text

function rep() {
    var t = $('p').text().replace('text', '<b>html</b>'); 
    $('p').html(t);
}

Ideally it would look like:

<p>This is <i id="text"><b>html</b></i> and more <b>html</b></p>

This is html and more html

I DONT want to change the pre-existing html. <i id="text"> should remain in the html, no matter how many times I run the function. .html().replace(.. wouldn't work because it will grab the id="text". Thanks.

Squirrl
  • 4,909
  • 9
  • 47
  • 85
  • 2
    Use `.html()` instead of `.text()` and you'll get all the HTML. – Barmar Dec 19 '13 at 21:45
  • @Barmar I'm sry if I wasn't clear, but I don't want to change the pre-existing html. So if I use .html() than I'll change the `id='text'` tag, which I don't want to do. – Squirrl Dec 19 '13 at 21:47
  • 1
    Oh, that makes things more complicated. – Barmar Dec 19 '13 at 21:51
  • 1
    This question may be helpful: http://stackoverflow.com/questions/298750/how-do-i-select-text-nodes-with-jquery – Barmar Dec 26 '13 at 04:30

2 Answers2

2

You need to get the old value using .html(), not .text(), since the latter leaves out all the HTML markup. You can do it in a single call, using a function to calculate the replacement from the old value:

function rep() {
    $('p').html(function(i, oldhtml) {
        return oldhtml.replace(/(<[^>]*)?text/g, function($0, $1) {
            return $1 ? $0 : '<b>html</b>';
        });
    });
}

Notice that you have to use a regular expression with the g modifier to perform multiple replacements in a string. Negative lookbehind would be the normal way to exclude id="text", but this is not available. I used the workaround from Javascript: negative lookbehind equivalent?

Community
  • 1
  • 1
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • This replaces all the text in one swoop including the `` which I want to retain. I don't want to change the pre-existing html. – Squirrl Dec 19 '13 at 21:51
  • 2
    @wared Yeah, just realized that. I'll merge in the workaround from http://stackoverflow.com/questions/641407/javascript-negative-lookbehind-equivalent – Barmar Dec 19 '13 at 21:53
  • Can I suggest this regex : `/(<[^>]*?)?text/g`? `"text texttext" -> "azerty azertyazerty"` –  Dec 19 '13 at 22:02
  • Since `` isn't a valid HTML tag, that seems like overkill. – Barmar Dec 19 '13 at 22:03
  • Looking good. THank u, but I want to run it repetitively. @Barmer Ur function is replacing all the text in one call. I tried removing the `g` but that didn't do it. – Squirrl Dec 19 '13 at 22:04
  • @Barmar I know `` isn't a valid tag :D It's just an example. The idea is to deal with various situations like ` –  Dec 19 '13 at 22:09
  • @Squirrl I can't think of a way to do just one. The problem is that the lookbehind workaround matches `id="text"`, and just avoids replacing it. So if you do it without `g`, it won't make any change past that part of the HTML, because it keeps matching it each time. – Barmar Dec 19 '13 at 22:10
  • @Barmar Well, if it's more clear for you, try with this string : `"text"`. I think it's a valid one ;) –  Dec 19 '13 at 22:12
  • To do this right, you need to process the text nodes by themselves. You can get ideas from this question: http://stackoverflow.com/questions/9452340/iterating-through-each-text-element-in-a-page. I'm not going to try to write it now. – Barmar Dec 19 '13 at 22:13
1

Tell me if this code fits with your needs (I reuse input multiple times for convenience) :

function rep(input) {
    input = RegExp.escape(input); // http://stackoverflow.com/q/3561493/1636522
    input = new RegExp(input + '(?![^<]*?>)');
    input = $('p').html().replace(input, '<b>html</b>');
    $('p').html(input);
}

A little help about (?![^<]*?>) (roughly : "some text not followed by >") :

(?!...)   not followed by
[^<]*     any char except "<", zero or more times
?>        until next ">"

More on regular expressions : http://www.javascriptkit.com/javatutors/redev.shtml.

  • 1
    Sorry @Squirrl, I've copied your code without thinking. Fixed : `.text() -> .html()`. –  Dec 19 '13 at 23:03
  • Yes u genius it did http://jsfiddle.net/9j26P/16/ ! Any idea how I can replace `text` with a variable? – Squirrl Dec 19 '13 at 23:03
  • 1
    Awesome! Thank u. It's still getting caught up on parenthesis. Any way u can explain `(?![^<]*?>)'` so that I may be able to tweek it. – Squirrl Dec 19 '13 at 23:09