I have come across a weird situation which looks like a security bug in IE. This concerns DOM manipulation by creating new objects using innerHTML.
Some background on the topic: In a certain project, I am using a 3rd party WYSIWYG Html rich editor. As all of these editors, they create new DOM elements (mainly fancy toolbars with buttons). After development, the application was installed on some QA machines and servers. Much to my surprise, when browsing to the application from the actual server itself (i.e. localhost), in IE all the scripting worked well, except for the rich editor. The editor’s html was built successfully, but the toolbar buttons were inactive.
So, I created my own sample and added DOM elements using innerHTML, in a similar fashion to how the rich editor added it’s own buttons, in order to try to emulate and understand what was going on here. I enabled Active Scripting settings both in the Internet zone and in the Local Intranet zone. The following works as expected:
In order to reproduce this bug, we’ll disable Active Scripting on the Internet zone, and leave it as enabled for the Local Intranet zone. Here’s the Internet zone:
The Local Intranet remains as Enabled:
As you can see, by switching lines 12 and 13, I added the wrapping div to the DOM tree first, and only then I set the innerHTML property to an anchor with an “onclick” event. I refreshed the page and now the event worked as expected! It’s as if IE creates the elements well but the events are not triggered, if the newly created element is not yet attached to the DOM. Appending the element afterwards is simply “too late”. Note, that if I had set the innerHTML of the #container div directly (i.e. without creating a second div), this would have worked as #container div is already a part of the DOM.
The same behavior goes for jQuery Insertion – the following ‘append’ creates the elements successfully, but the ‘onclick’ does not work (jQuery 1.7.1):
I assume that jQuery first creates an element and sets it’s innerHTML, prior to attaching it to the DOM. So the same behavior applies. The workaround is very easy:
As you can see, jQuery’s ‘html’ works on an existing DOM element (‘#container’) and that is why the event works, whereas ‘append’ seems to create a new DOM element and set it’s innerHTML before the element is attached to the DOM, and that is why it fails.
“Armed with this knowledge”, the workaround on how to solve the non-working buttons of the Html editor is now very simple, and applies to both enabled and disabled Active Scripting scenarios; all that is required, is to “re-apply” the innerHTML property of the newly created elements. Because those new elements are now a part of the DOM, setting the innerHTML recreates the child elements and their events correctly this time. I used jQuery for setting the innerHTML. For example:
- Lines 11-14 simulate code which creates the html in a buggy manner.
- Line 17 applies this workaround for IE only.
- Line 18 takes the DOM’s html from the newly created div element.
- Line 19 “re-applies” the html, which basically means that the anchor tag and the ‘onclick’ are recreated.
This time IE handles the ‘onclick’ well:
I believe that the described behavior is an IE bug. If MS wanted to block element creation using innerHTML when Internet zone Active Scripting is disabled, it would have blocked it entirely disallowing the above workaround. Fortunately, this bug is easy to workaround once you realize what it is. Naturally, this workaround could prove to be expensive, so I would limit using it only to specific cases where you have no alternative, and only for IE (like I had when using the 3rd party editor).