The movement of the stream is distinct from the river bed, although it must adopt its winding courseHenri Bergson
Relates to Accessibility and DOM Scripting
Thanks to Simon Willison's interesting post on closures in Javascript I recently rediscovered
W3Future's article on applying closures to event handling methods. This article provides a very illuminating resolution
to the common problem in separating the behaviour of a web page from the structure - the method assigned as the event handler to an object does not contain a reference to the object itself (at least not in IE).
Traditionally this could be solved with a cross browser concoction of event.target, window.event.srcElement and bubble management.
The closure paradigm is a very adaptable and dynamic solution, that not only allows clean cross browser access to the source element, but is readily extensible in an object oriented environment:
function EventHandler(elem) {
this.elem = elem;
this.evt = "";
this.register = function(handler, fn) {
addEvent(this.elem, handler, fn);
}
this.invoke = function(evt) {}
this.cancel = function() {}
}
function FieldHandler(elem) {
var me = this;
this.base = EventHandler;
this.base(elem);
this.mouseon = function(evt) {
me.invoke(evt);
}
this.mouseoff = function(evt) {
me.invoke(evt);
}
}
FieldHandler.prototype = new EventHandler;
handle = new FieldHandler(DOMElement);
handle.register('mouseover', handle.mouseon);
handle.register('mouseout', handle.mouseoff);
The me variable provides access each instance of the FieldHandler object, which would otherwise be unavailable. (Note EventHandler::register it uses Scott Andrew's
Cross Browser Event Handling routine
to assign the event listeners.) Another use might be to assign the callback function for the event at runtime based on the event type:
function EventHandler(elem, me) {
var me = this || null;
// …
this.invoke = function(evt) {
me.evt = (evt) ? evt :
((window.event) ? window.event : null);
me.assign();
}
this.assign() = function() {}
// …
}
function FieldHandler(elem) {
this.base(elem, me);
// …
this.assign() = function() {
switch(this.evt.type) {
case 'mouseover':
this.mouseon();
break;
case 'mouseout':
this.mouseout();
break;
}
}
// …
}
// …
handle.register('mouseover', handle.invoke);
handle.register('mouseout', handle.invoke);
The one stumbling block I fell over briefly was the cancelling of an event. A typical example being a stylesheet switcher where a link is supplied to switch the CSS on
the server where Javascript is not available. In a Javascript environment the HTTP request should be cancelled. Sadly, using event attachment to assign handlers, return false will not cancel the operation.
Information on this hurdle appears to be lacking on the web, but fortunately the solution was nestled in the DOM2 Events Specification:
this.cancel = function() {
if (this.evt) {
if (this.evt.preventDefault) {
this.evt.preventDefault();
}
this.evt.returnValue = false;
}
}
In the W3C event model preventDefault called anywhere within an event processing tree will cancel the default event. For the Exploders falsify the returnValue property for the event.
These are very basic examples, but just in an afternoon I discovered immense power in this method without the need to hack cross browser
scripts (I have tested the method successfully across all the major PC browsers - IE5.x, IE6, Moz, Opera). I have started work on integrating the EventHandler class
into my form validation scripts and will hopefully present this as a more detailed and explanatory article when I find more time. The biggest benefit of the method is it allows for
the behavioural scripts to be totally detached from the mark-up for a web document, thus only serving javascript content where it can be handled while achieving a more lightweight document.
Posted on Sunday, Jun 20, 2004 at 03:39:51.
Comments on Accessible Javascript Event Handling (6)
α comment
(I found this via delicious… anyway:)
Be wary of the Internet Explorer Memory Leak Problem. I'm not sure if it occurs when you use the DOM methods to add events, but you might want to test it to be sure.
Posted by Mark Wubben
Thursday, Jan 13, 2005 at 13:17:29
β comment
Hi Mark, Yes I am very much aware of the memory leaks in IE. The assigment of DOMElement to member variable in the accessible event handler above can create a circular reference leading to IE memory leak.
This can be avoided by only storing the ID of the element, and creating a reference to it on each method call. However, I have found in more complex DOM libraries referencing elements a necessity, so instead use a clean up method when the page is unloaded:
Not ideal - benchmarking on my 5 year old machine took 0.5s to clean six handlers from 500 nodes! A small price to pay for IE use I guess.
Cheers for the observation - I do not believe I had got round to blogging directly on leaks before now. Beyond the reference to IE pitfalls, Richard Conrnford's article is an excellent resource for understanding the inner workings of ECMAScript with relation to performance.
Posted by Tom
Thursday, Jan 13, 2005 at 15:10:55
γ comment
when I press alt+f, my browser don't open the file-menu, but sets focus in the "forget me" radiobutton
rather stupid overruling of a standard
Posted by Hans Kejser Hansen
Saturday, Mar 05, 2005 at 11:50:30
δ comment
Perfectly valid observation hans!
Actually, I removed those accesskeys a while ago on preusal of WATS great collection of accesskey resources, but this page was still using cached version. Your posting has cleared the cache and kissed farewell to those unruly accesskeys - E and F :)))
Posted by Tom
Saturday, Mar 05, 2005 at 12:23:43
ε comment
Tom, a better way of registering events is this: http://talideon.com/weblog/2005/03/js-memory-leaks.cfm.
This script works across all event types, all browsers, and is faster and more reliable because it only deals with nodes that have had event handlers registered with them, and it allows all handlers registered with a node to be cleared, which simply assigning null to them doesn't necessarily do.
Posted by Keith Gaughan
Friday, Mar 18, 2005 at 00:06:44
ζ comment
Cheers for pointing out your solution Keith. A nice implementation of the W3C and IE DOMs and a quick test drive showed no leakage in exploder :)
Posted by Tom
Sunday, Mar 20, 2005 at 19:46:12