Wednesday, July 9th, 2008

Unobtrusive DOM 2 Event implementation for IE; Uniform Event Model revisited

Category: Browsers, IE

Tavs Dokkedahl sent in a great email about work that he and Allan Jacobs have done on bringing DOM event implementations to IE. Here it is in full:

About a year ago or so I put out the Uniform Event Model (UEM) script which
was an implementation of the W3C DOM 2 Event Interface for IE. As it turned
out that release was very premature – the script was simply incomplete and
definitely not ready for production use.

The design ideas however were good enough. Since then Allan Jacobs has
joined the JSLab team and together we have written a new version of UEM
which is much more stable and modular.

This first release includes support for:

  • DOM 2 Event Interface in IE
  • DOM 2 UIEvent Interface in IE
  • DOM 2 MouseEvent Interface in IE
  • DOM 2 Legacy keyboard handling in IE (fancy way of saying “handle it like
    Firefox”)

The code is unobtrusive – no special syntax or semantics are needed. A lot
of documentation is available

There still exists issues with some types of events but at large the code is
stable and is performing well enough to be released to the public. Hopefully
we can get some feedback on how to improve it and catch some early errors.

The size of the script is about 32Kb (when minified) it its basic form but
additional modules are available for inclusion. The download page can be
found at http://www.jslab.dk/jdc.download.php

We are currently working on finishing the DOM 3 KeyboardEvent and DOM 3
textInput interfaces (for IE, Firefox, Opera and Safari) besides various DOM
corrections for other browsers than IE.

Posted by Dion Almaer at 7:32 am
17 Comments

++++-
4.2 rating from 22 votes

17 Comments »

Comments feed TrackBack URI

32 k minified just for event handling?!? I think this is one we need the IE team to include natively.

Comment by Joeri — July 9, 2008

Amazing work, guys. However several questions/concerns come once I see such a challenging title of a post:
– Do nodes rendering through innerHTML property come with the EventListener interface applied?
– Does it support dispatching custom events? (So that inline (onfoo) handlers specified in HTML text (or rendered with innerHTML) would pick them up and be handled in the proper order)
– Does implementation properly deal with the Capturing Phase in the event propagation flow?
– Does it implement proper handling of events’ default actions?
– Does it solve all quirks with events sequencing?
– What is the patch-time overhead for a page of 100Kb?
– Isn’t it too much 32Kb only for DOM-Level-2 events implementation?
– etc.

Hope my considerations sound constructive ;)

Comment by caston — July 9, 2008

@Joeri/caston I downloaded the entire package, including all addons, and minified it with variable shrinking. The result was 32kb, the same size as just the core with simple minification applied. I then gzipped it resulting in the size being only 6.85kb. I think the file size is fine considering how thorough the code is.

@caston – I just did a quick check and I think it does handler extending nodes added via innerHTML, EPE.extendInnerHTML().

I can’t wait to look under the hood a bit more. Good job guys :)
+1 for the customizable download :)

– JDD

Comment by jdalton — July 9, 2008

I assume this is for IE6 and IE7. Is that right?
.
Is IE8 “fixed” or is it still a ball of turds?

Comment by Nosredna — July 9, 2008

>Amazing work, guys. However several questions/concerns come once >I see such a challenging title of a post:
Understable :)

– Do nodes rendering through innerHTML property come with the EventListener interface applied?
Yes.

– Does it support dispatching custom events? (So that inline (onfoo) handlers specified in HTML text (or rendered with innerHTML) would pick them up and be handled in the proper order)
Maybe. Can you clarify and give an example?

– Does implementation properly deal with the Capturing Phase in the event propagation flow?
Yes.

– Does it implement proper handling of events’ default actions?
I should think so – maybe a possible place for improvement.

– Does it solve all quirks with events sequencing?
Its a script – not the holy grail :) What particular quirk do you have in mind?

– What is the patch-time overhead for a page of 100Kb?
We didn’t do any hardcore speed analysis – I’m sure someone out there is much better at that than I am. For all the tests I’ve done myself – and some are extremely complicated like using JDC for entire GUI applications – there is no notiticeably delay. It all comes down to traversing the DOM and looping through arrays. Very little DOM manipulation is done.

– Isn’t it too much 32Kb only for DOM-Level-2 events implementation?
The 32Kb is for HTMLElement and sub interfaces included. If you use compression it goes down to around 8Kb. I’d say that is pretty decent for correcting one of the worst scripting cross-browser problem which exists.

– etc.
See http://www.jslab.dk/projects.php for answers to other questions.

Comment by Tavs — July 9, 2008

– I assume this is for IE6 and IE7. Is that right?
Yes.
– Is IE8 “fixed” or is it still a ball of turds?
To my knowledge event handling still use the old IE model

Comment by Tavs — July 9, 2008

@Tavs I think event sequencing, observer order, is where IE fires in last-in-first-out where all other browsers fire first-in-first out. Observer firing order is not specified in the spec so its up in the air. I know Prototype is looking into ensuring observer order via 1 real observer that then calls subsequent observers which are stored in an array. This would ensure first-in-first-out also It would allow you to do further tweaks like making sure IE window.onresize is called only once per change instead of several times.

Comment by jdalton — July 9, 2008

@ jdalton:
The order of execution is specified in DOM 3 Events sec. 1.2.2.2. http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-listeners
With UEM events in IE are fired in the order in which they are registered.

Comment by Tavs — July 9, 2008

@Tavs thanks for the reference :)

Comment by jdalton — July 9, 2008

@Tavs:
1) – Do nodes rendering through innerHTML property come with the EventListener interface applied?
> Yes.

Verified: No. I understand this is simply not possible (unless you make an additional call to an unobtrusive API function ;) )

Testcase:
var o = document.createElement(“div”);
o.innerHTML = “”;
alert(o.firstChild.addEventListener);

2) – Does it support dispatching custom events? (So that inline (onfoo) handlers specified in HTML text (or rendered with innerHTML) would pick them up and be handled in the proper order)
> Maybe. Can you clarify and give an example?

Verified: No. Custom onfoo inline handlers do not participate in the re-implemented event flow. Standard onfoo inline handlers do not participate in the re-implemented event flow but get handled by browser (thus an capture-phase event listener assigned with new API gets executed after the inline (target-phase) handler).
I think this can be solved by manual removing onfoo handlers set by the UA through markup (set corresponding property to null) and reinitializing them in the re-implemented event propagation.

3) – Does implementation properly deal with the Capturing Phase in the event propagation flow?
> Yes.

Verfied: No.
a) Bubble-phase listeners (in the path) get executed when non-bubbleable event is dispatched (bug).
b) Capture-phase listener is executed on the target (wrong)

4) – Does it implement proper handling of events’ default actions?
> I should think so – maybe a possible place for improvement.
Sounds like these haven’t been considered yet, right? For example: preventing focusing control action by preventing focus event with a call to event.preventDefault() doesn’t have any effect.

5) – Does it solve all quirks with events sequencing?
> Its a script – not the holy grail :) What particular quirk do you have in mind?

For example, dblclick event misses mousedown and click event happening in front. There are many more similar issues with missing/excessive events in IE.

Hope this helps.

Comment by caston — July 9, 2008

About the size, I wasn’t criticizing the script, I was criticizing IE for requiring this much code to do the same stuff as everyone else.

Comment by Joeri — July 9, 2008

This sounds very nice! I might be willing to pay a 6 or 30kb download to commonize on event handling across my web apps. It would be even nicer if it was built into one of the existing more popular frameworks like jQuery (presumably this would save on size a little).

But here’s hoping that IE8 Beta 2 does at least DOM2 Events though so we don’t need these types of scripts much longer!

Comment by codedread — July 9, 2008

@ Caston
1)
UEM builds upon EPE. EPE in turn extend nodes added by innerHTML. The test case doesn’t make sense to me as the node o does not have a first child. The test case also fails in Firefox 3.
2)
So far we can only handle the events specified in the feature list http://www.jslab.dk/uem.features.php
3)
a)
Nice catch. The error has been located but we need to run some tests before releasing a fixed version.
b)
Yes this is wrong per spec but Firefox, Opera and Safari also behaves this way. This is an optional feature which you can switch on/off using the download interface.
4)
Is has been considered and tested in various scenarios. I need more info on the particular test case. Please see the mail I’ve sent you.
5)
Not implemented but that should be possible to correct.

@ Joeri
Sorry for jumping out of the chair :)

Comment by Tavs — July 9, 2008

This works by walking the DOM and augmenting every element it finds. It also attaches a propertychange event handler to every element. While it is very thorough, I don’t imagine that it performs particularly well.

I took the decision in base2 to only augment elements that are retrieved by DOM queries. That way you are only augmenting elements that you are actually interested in.

Apologies to the authors if I have misunderstood something.

Comment by deanedwards — July 9, 2008

@ deanedwards
Only augmenting elements retrieved from DOM queries is a good idea but if you’re accessing elements using something else say document.firstChild.childNodes[1] then the approach falls short. It is an intersting idea though and a possible place for improvement.

Here is a brief and very unscientific perfomance analysis:

Performance of UEM is influenced by the performance of EPE so lets have a look at EPE first

EPE is startet on the onload event on the body tag. The first task is to add EPE functionality to existing elements. This means walking the

entire DOM but only once. Even with a ridiculous amount of nodes of say 3000 this happens so fast that IE can not measure a time difference.

The initialization procedure mainly involves property assignment and conditional tests like if statements. So the initilization runs in

something like O(n) where n is the number of nodes in the document.

If a singel node is created only the prototype object of that nodes constructor is iterated. This running time is insignificant.

If a document fragment is inserted (by innerHTML) that fragment will be walked – sometimes more than once. Running time is proportional to the

number of nodes inserted but will most likely never exceed the initialization.

Changes to a single node spawns the onproperty event handler invoking a single function which checks for plugins to EPE. In this case UEM can

be thought of as a plugin. If the property change is an event (onSomething) control is passed to UEM which arranges for a proper call to

addEventListener. If no function is registered for the changing property the function simply returns.

Changes to a HTMLElement or sub class prototype at runtime is the most expensive procedure. In this case all existing nodes must be interated.

This is done by document.all or document.getElementsByTagName. The procedure is similar to initilization and a time difference can not be

measured. Changes to such prototype objects is not likely to be called at runtime in that many cases.

I believe that memory is a more important factor than speed for EPE.

UEM is not initiliazed – it just defines the EventListener interface for window, document and HTMLElement. Assigning and removeing event

handlers are fairly basic. A number of simple check functions are invoked and the event handler is stored on the element itself.

When an event occurs (or is dispatched) a single wrapper catches the event in the native IE target phase. The function then takes the following

steps
A) Traverse DOM from target to window and record elements which have the same listener for the capture phase in an array.
B) Reverse the array (now we have a capturing chain)
C) Invoke all event handlers for the capture chain
D) Invoke event handlers for target
E) Traverse one more time as the previous event handlers might have made changes to the DOM
F) Invoke all event handlers for the bubbling chain

The difference from the above and a native implementation is the DOM traversing and array iteration. Again this happens very fast even for

deeply neested nodes.

But of course there is an overhead. The code is rather complicated so working out the worst case running time is difficult – at least for me. I

can tell you that I am using EPE/UEM for a window managing system and so far I can’t tell a difference between IE and Firefox. This system

involves drag’n drop, resizing windows, other complex functions and constantly manipulating the DOM.

I don’t consider myself qualified to undertake a thourough perfomance analysis so it would be great if someone out there who has the skills

would take on such a task.

Comment by Tavs — July 9, 2008

Revisiting the original post.
– Do nodes rendering through innerHTML property come with the EventListener interface applied?
Yes.
– Does it support dispatching custom events? (So that inline (onfoo) handlers specified in HTML text (or rendered with innerHTML) would pick them up and be handled in the proper order)
No.
– Does implementation properly deal with the Capturing Phase in the event propagation flow?
Yes.
– Does it implement proper handling of events’ default actions?
preventDefault is implemented (for Internet Explorer). Default actions are delegated to the browser.
– Does it solve all quirks with events sequencing?
No. The relative timing of keypress, keyup, and keydown are not fixed. I noticed a number of different behaviors when running test codes on Firefox, Internet Explorer, Opera, and Safari.
– What is the patch-time overhead for a page of 100Kb?
We need to do performance measurements.
The event processing speed concerned me a lot. A drag and drop test behaved poorly. But, the poor behavior was no better using native Internet Explorer events.
– Isn’t it too much 32Kb only for DOM-Level-2 events implementation?
This is unanswerable. What is the Euro-cost of a 1/4 second wait? What is the Euro-benefit of the functionality when it is used? Is it application dependent? The JavaScript library does more than just DOM-Level-2 events, too.

Comment by jacobsallan — July 9, 2008

What a Pro jsLib, great job!

Comment by KKFC — July 10, 2008

Leave a comment

You must be logged in to post a comment.