3

I want to replace all displaying text with something like "@@@@". It mean user will see all the page is full of "@@@@" instead of texts (except image, iframe or something doesn't exists in the page's HTML code).

This almost replace the html code of the page, but not effect to the tags and codes, just the text that display to user.

For example, I want to replace all the text in this page:

<!DOCTYPE html>
<html>
<body>                  
<ul class="topnav">
    <li>Item 1</li>
    <li>Item 2 
        <ul><li>Nested item 1</li><li>Nested item 2</li><li>Nested item 3</li></ul>
       </li>
    <li>Item 3</li>
</ul>
<div>DIV1</div>
<div>DIV2</div>
<span>SPAN</span>
<table>
<tr>
    <td>Username</td>
</tr>
<tr>
    <td>Password</td>
</tr>
</table>
<p>
  <input type="checkbox" name="remember" tabindex=3 />
  <label for="checkbox">Remember <strong>password</strong></label>
</p>
<p>Click here to <a href='register.php'>Register</a></p>
</body>
</html>

And the result should be:

<!DOCTYPE html>
<html>
<body>                  
<ul class="topnav">
    <li>@@@@</li>
    <li>@@@@ 
        <ul><li>@@@@</li><li>@@@@</li><li>@@@@</li></ul>
       </li>
    <li>@@@@</li>
</ul>
<div>@@@@</div>
<div>@@@@</div>
<span>@@@@</span>
<table>
<tr>
    <td>@@@@</td>
</tr>
<tr>
    <td>@@@@</td>
</tr>
</table>
<p>
  <input type="checkbox" name="remember" tabindex=3 />
  <label for="checkbox">@@@@<strong>@@@@</strong></label>
</p>
<p>@@@@<a href='register.php'>@@@@</a></p>
</body>
</html>

Some I've been tried:

Use JQuery to replace all the elements, tags (and it's child) that only contain plain text, this works fine at the beginning:

<ul class="topnav">
    <li>@@@@</li>
    <li>@@@@ 
        <ul><li>@@@@</li><li>@@@@</li><li>@@@@</li></ul>
       </li>
    <li>@@@@</li>
</ul>
<div>@@@@</div>
<div>@@@@</div>
<span>@@@@</span>

But lately I realized that in case of elements, tags have child, it would failed:

<p>
  <input type="checkbox" name="remember" tabindex=3 />
  <label for="checkbox">Remember <strong>password</strong></label>
</p>
<p>Click here to <a href='register.php'>Register</a></p>

So I tried another way, using document.body.innerText to select all the text, but the HTML format is lost.

I was so tired. Can someone help me?

Thanks a lot!

Tony Dinh
  • 6,668
  • 5
  • 39
  • 58
  • `in case of elements, tags have child, it would failed:` can you explain this case? – Furqan Hameedi Jun 23 '12 at 06:13
  • You need to replace anything between a `>` and a `<` in the `body.innerHTML` – Scott Stevens Jun 23 '12 at 06:18
  • @Furqan: If there are child tags, the function would check that is not a "plain text" and ignore them (the example HTML I showed). – Tony Dinh Jun 23 '12 at 09:20
  • @ScottS: In this case:

    hello, click here

    my link would be lost.
    – Tony Dinh Jun 23 '12 at 09:21
  • @TrungDQ No, since you would only replace between any two tags (be opening or closing). You would check for the `>` and `<` symbols, **not** the opening and closing tags that are on the same parent level. – Scott Stevens Jun 23 '12 at 09:38
  • @ScottS I see what you mean, but here is a example: `

    hello world, now kiss

    `. According to your method, the result is: `

    hello @@@@, now kiss

    `, but the result I wanted is: `

    @@@@@@@@@

    `. I was considering about using regex but it became so much complex. Can you find out something more effective? :-(
    – Tony Dinh Jun 23 '12 at 09:58
  • You misunderstand me. I am posting my explanation as an answer now. – Scott Stevens Jun 24 '12 at 03:31

4 Answers4

9

This code seems to work for me:

$('*').contents().filter(function() {
    return this.nodeType == Node.TEXT_NODE && this.nodeValue.trim() != '';
}).each(function() {
    this.nodeValue = '@@@@';
});

Basically, it replaces the contents of each text node with @@@@.

For a demo, see here: http://jsfiddle.net/K8544/3/

Blender
  • 289,723
  • 53
  • 439
  • 496
1

Try this one. It's a function that replaces inner text with "*", but only if its inner HTML is equal to its inner text. Otherwise, it calls itself recursively, navigating down the DOM until it reaches the innermost element.

    $(document).ready(function() {
        function replaceChildren(node) {
            if ($(node).html() == $(node).text()) $(node).text("@@@@");
            else {
                $(node).children().each(function() {
                    replaceChildren(this);
                });
            }
        }
        replaceChildren($("body"));
    });

It's not perfect, but should be pretty close for most purposes. I tried it on a Stack Overflow page, and most text got replaced. The only place it doesn't work is where there is stray markup and text within the same tag, for example <div>Here is some inner text <strong>and markup</strong></div>. Maybe this suffices for your purpose though ...

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
1

A JQuery-only solution:

$("body *").contents().wrap("<obscure></obscure>");
$("obscure").each(function(i,e) {if ($(e).children().length==0) $(e).replaceWith("@@@@");}​);
$("obscure > *").unwrap();

http://jsfiddle.net/cranio/CW9jY/1/

This code wraps EVERY node with a custom tag (obscure); the use of .contents() makes sure we wrap ALSO the pure text nodes. Then we substitute the obscure nodes which have no children (that were text-only nodes before) with @@@@, hence eliminating also the obscure tags. Finally, we unwrap the other elements that were wrapped with <obscure>.

Cranio
  • 9,647
  • 4
  • 35
  • 55
  • @TrungDQ let me know if this is what you want to achieve. – Cranio Jun 23 '12 at 06:32
  • Hi! Sorry for late reply. I've tried to use your code but seem like it doesn't work in almost page. Your fiddle example works fine, but when I used this code with larger HTML page, it didn't work. Blender's solution work fine for me. Anyway, thanks for your help :) – Tony Dinh Jun 23 '12 at 12:26
1

You can match anything between two tags - these don't have to be the same tag. For instance, <div>aaa<a href="bbb">ccc dd</a></div>, it would find aaa, replace it with @@@, then find ccc dd and replace it with @@@ @@ by looking between > and the next <.

<script type="text/javascript">
function obscure() {
    var newhtml = document.body.innerHTML.split("<");
    for (var i=1; i<newhtml.length; i++) {
        var list = newhtml[i].split(">");
        newhtml[i] = (list[0]) + ">" + ((list[1]).replace(/[^@\s]/gim, "@"));
    }
    newhtml[0] = (newhtml[0].replace(/[^@\s]/gim, "@"));
    document.body.innerHTML = newhtml.join("<");
}
</script>

(Note: This does not replace whitespace, since that appeared to be causing some issues).

Scott Stevens
  • 2,546
  • 1
  • 20
  • 29
  • Oh, I see. Sorry I was so silly. This would work very well, seem quite complex at first but I think it is faster than the JQuery one. Thanks for your help! – Tony Dinh Jun 24 '12 at 04:33