views:

215

answers:

1

Someone tried to recreate smarty in js:

// actually from a template file, not hardcoded in the javascript
html = '<span class="{test}">yay</span>'; 


html = change(html, 'test', 'foo bar');
function change(html, key, value){
    html = html.replace('{'+key+'}',value);
    html = html.replace('%7B'+key+'%7D',value);
    return html;
}

element.innerHTML = html;

In FF this works fine (as expected):

<span class="foo bar">yay</span>

In IE 7/8 and probably 6... it gives me this:

<span class="foo" bar="">yay</span>

Why does it create the extra attribute instead of doing what I expected it to do?

+3  A: 

Someone tried to recreate smarty in js

I really wish they wouldn't do that...!

I suspect what's happened here is that the code is grabbing the original HTML from an element's innerHTML instead of a string as you write above. In that case, IE will serialise its DOM into what it thinks is a nice way to format HTML markup, which may not be much like the markup it was originally fed. One of the questionable things it may do in this case is to omit quotes:

<SPAN class={test}>yay</SPAN>

“But, that's not valid HTML!”, you complain. Pfft — like IE cares.

Now do the replace and you get:

<SPAN class=foo bar>yay</SPAN>

Where bar is obviously a new attribute and will be parsed into a separate Attr node when you write it back to the innerHTML.

Once again, the moral is don't process HTML with regex. Browsers are no more obliged to give you correct HTML when you read innerHTML than your average inexpert HTML author-clod is.

This code will fail not just for this case but also anything with regex special characters in the key, or replacement-special characters in the value, or HTML special characters anywhere, and doesn't allow the same key twice, and for some unknown reason attempts to template URL-encoded strings (?), potentially messing up if the replacement value contains curly brackets.

If you can keep it all in the DOM, assigning to span.className is simple and safe. If you must template with HTML strings (and if you do, you need to look at HTML escaping to avoid the gaping XSS holes that plague most JS templating systems), then you'll need to keep the input HTML template as the original text string, not reading it from a DOM.

bobince
I think he wishes he hadn't done that either...
SeanJA
Thanks for the great explanation!
SeanJA
I do wish that I could keep it in the dom, but this is system is about 5 years old and it 'works' so I would rather not mes... erm... fix it.
SeanJA