Making InnerHTML and Internet Explorer Get Along
I had been wrestling with this a couple of days ago, and thought it might be nice to share. You see, not only does Internet Explorer (all versions through 7 at least) mangle CSS, but seems to have a special interest in making Javascript applications exceedingly difficult as well. Mainly, it takes any code provided by Javascript’s innerHTML property and capitalizes all of the tags before spitting it back out in the desired element. This sounds harmless enough, but by my standards, IE should have no business rewriting my code. Therefore, I devised this little script, using a bit of Regular Expression goodness (» represents line breaks):
newElement.innerHTML = element.innerHTML.replace(/<.([A-Za-z]*[A-Za-z0-9]w*)?(?=.*>)/gi, » function(w) {return w.toLowerCase();});
Now that I had that solved, I had a new problem: IE runs a rather vague error when trying to place HTML in to <p> tags. Specifically it is an “Unknown Runtime Error”… specifically. Now, I know that innerHTML is not specified by W3C, and IE is probably just doing what it thinks is best, not allowing HTML in to a non-block level element, but what about an anchor tag, or a <strong> tag? Well, with a little help from the DOM, I came up with this:
// oldElement being the element you want to place HTML in to...
var replacement = new Element(oldElement.tagName);
// now, copy all of the attributes of newElement to replacement...
for(i=0; i<$oldElement.attributes.length; i++) {
replacement.setAttribute(oldElement.attributes[i].nodeName,» oldElement.attributes[i].nodeValue);
}
// put some code in to replacement...
replacement.innerHTML = "<a href='#'>Place some <strong>code here</strong>.</a>";
// and then pull the old switch-a-roo!
oldElement.parentNode.replaceChild(replacement, oldElement);
Well, you would think that would be enough to tame ol’ IE, but no: the folks at Microsoft have cooked up one more obstacle. All versions of IE that I have encountered will rewrite all relative urls to absolute urls on page load. I have yet to find an answer as to why, or how to stop it. This, again, crosses my ideal that the browser has no business rewriting my code, and makes for the handling of certain tasks very difficult. At this point, I throw myself on the mercy of our readers… any ideas?
Comments (6)
[...] You see, not only does Internet Explorer (all versions through 7 at least) mangle CSS, but seems to have a special interest in making Javascript applications exceedingly difficult as well. Mainly, it takes any code provided Read more [...]
Have you taken a look at any Javascript library source code for ideas (jQuery, Prototype, LowPro, MooTools, etc.)?
[...] Go to the author’s original blog: Making InnerHTML and Internet Explorer Get Along [...]
Yeah, for the most part they are just simplifying the innerHTML process, which will still cause the same IE problems. Unfortunately.
I totally admire how determined you are, but I think this may be an overshoot here with the innerHTML issue. Yeah, there may be cases when you serialize an element using the innerHTML property and you actually do something with the generated HTML (for example saving it to a database from a form’s textarea).
But if you don’t and you only want to have lowercase element names in the browser’s internal document representation… Sorry Nathan, but that really doesn’t make any sense ;-). The replace function has a linear computational complexity — the longer the text, the longer it takes to scan and replace it. If it doesn’t actually make ANY difference besides making the coder feeling better, I’d strongly advice NOT to do it, because it only makes the JavaScript a bit slower.
I actually write mainly to thank you for a very useful info I learned from your post: that the replace method can take a function for its second argument. I’ve been writing JavaScript for, like, ages, and don’t remember knowing it. That’ll be very useful to me!
Anyway, as for the URL-s in href attributes… That can indeed be a pain when your scripts read this attribute to, for example, obtain the anchor’s destination id name. You can have href=”#dest” in your code, but you’ll get “http://example.com#dest” in your scripts.
Hmm, if IE changes the URL-s on page load only, write a few lines of JavaScript that:
1. Get all anchor elements by tag name
(you may also want to get some other elements with href attribute, or get all elements with document.all and run the 2.2+ steps only on those of them, that have href attribute set)
2. For each of these elements:
2.1 Get its href
2.2 Create a new href, running a replace function on the old one, that removes the absolute part of the URL.
2.3 Set the element’s href to the new href (you’ll probably wanna make 2.2 and 2.3 a single-line-expression).
It may be a pain to know which part of the URL was added by the IE. In worst case, you’ll have to manually create a JavaScript variable, let’s name it baseURL, and set it to the string that is added by the IE. Then you’ll just remove it from the href value (ensuring it’s at the beginning of the url).
Hey Bartek, thanks for the thoughts. I understand that my idealism here may seem a bit misguided, but I assure you that I have a very good reason to not want IE to run roughshod over the original source code.
As for the URLs, I am currently employing a replace for absolute URLs, but again, this does not allow me to leave the code as is. Either IE rewrites, or I rewrite everything, but the code unfortunately cannot stay the same. Ugh.
Your Comment