Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's a good alternative to HTML rewriting?

Consider this document fragment:

<div id="test">
    <h1>An article about John</h1>
    <p>The frist paragraph is about John.</p>
    <p>The second paragraph contains a <a href="#">link to John's CV</a>.</p>
    <div class="comments">
        <h2>Comments to John's article</h2>
        <ul>
            <li>Some user asks John a question.</li>
            <li>John responds.</li>
        </ul>
    </div>
</div>

I would like to replace every occurrence of the string "John" with the string "Peter". This could be done via HTML rewriting:

$('#test').html(function(i, v) {
    return v.replace(/John/g, 'Peter');    
});

Working demo: http://jsfiddle.net/v2yp5/

The above jQuery code looks simple and straight-forward, but this is deceiving because it is a lousy solution. HTML rewriting recreates all the DOM nodes inside the #test DIV. Subsequently, changes made on that DOM subtree programmatically (for instance "onevent" handlers), or by the user (entered form fields) are not preserved.

So what would be an appropriate way to perform this task?

like image 432
Šime Vidas Avatar asked May 16 '11 00:05

Šime Vidas


People also ask

What is the alternative for document write?

As a recommended alternative to document. write you could use DOM manipulation to directly query and add node elements to the DOM. This would be a better answer if it addressed the question of why document.

Why is Document write () not recommended anymore?

. write is considered a browser violation as it halts the parser from rendering the page.


1 Answers

How about a jQuery plugin version for a little code reduction?

http://jsfiddle.net/v2yp5/4/

jQuery.fn.textWalk = function( fn ) {
    this.contents().each( jwalk );
    function jwalk() {
        var nn = this.nodeName.toLowerCase();
        if( nn === '#text' ) {
            fn.call( this );
        } else if( this.nodeType === 1 && this.childNodes && this.childNodes[0] && nn !== 'script' && nn !== 'textarea' ) {
            $(this).contents().each( jwalk );
        }
    }
    return this;
};

$('#test').textWalk(function() {
    this.data = this.data.replace('John','Peter');
});

Or do a little duck typing, and have an option to pass a couple strings for the replace:

http://jsfiddle.net/v2yp5/5/

jQuery.fn.textWalk = function( fn, str ) {
    var func = jQuery.isFunction( fn );
    this.contents().each( jwalk );

    function jwalk() {
        var nn = this.nodeName.toLowerCase();
        if( nn === '#text' ) {
            if( func ) {
                fn.call( this );
            } else {
                this.data = this.data.replace( fn, str );
            }
        } else if( this.nodeType === 1 && this.childNodes && this.childNodes[0] && nn !== 'script' && nn !== 'textarea' ) {
            $(this).contents().each( jwalk );
        }
    }
    return this;
};

$('#test').textWalk(function() {
    this.data = this.data.replace('John','Peter');
});

$('#test').textWalk( 'Peter', 'Bob' );
like image 134
user113716 Avatar answered Oct 24 '22 10:10

user113716