Users interested in this functionality should check out MochiKit.Signal, available in MochiKit 1.3 and later:

http://mochikit.com/doc/html/MochiKit/Signal.html

/* simple event wrapper function  to work around difference of browsers 
   setup like this :

      evt = new Event(event)

   in the event handling function where 'event' is the parameter passed to
   that function(may not contain anything, say IE )

   when using inline form, the event object must be specified in the case of
   non-IE browser, like this :

   <p onclick="my_click(event)"> click me </p>

   other even registration model would pass it implicitly, for Mozilla at least.

   element.onclick = my_click;

   this wrapper only support two button mouse detection, this.button == 1 is left
   this.button == 2 is right
*/

MochiKitEvent = function(evt) {
    this.evt = evt ? evt : window.event ;

    if (!this.evt) return null;

        this.type = this.evt.type;
        this.clientX = this.evt.clientX;
        this.clientY = this.evt.clientY;
        this.target = this.evt.target ? this.evt.target : this.evt.srcElement;
        this.srcElement = this.target;
        this.keyCode = this.evt.keyCode;
        this.which = this.evt.which ? this.evt.which : this.evt.keyCode;
        this.shiftKey = this.evt.shiftKey;
        this.button = this.evt.button == 0 ? 1 : this.evt.button;
        this.pageX = this.clientX;
        this.pageY = this.clientY;

        // Emulate the preventDefault functionality
        // The value of e.MochiKitExecuteDefault will have to be returned by 
        // the function which executes methods on the callstack (rval of DOM._newCallStack)
        this.MochiKitExecuteDefault = true;
        this.preventDefault = function(){this.MochiKitExecuteDefault = false;}                                          
        
        // Emulate the stopPropagation functionality
        // The value of e.MochiKitStopPropagation will have to be checked before
        // any functions are executed on the callstack
        this.MochiKitStopPropagation = false;
        this.stopPropagation = function(){this.MochiKitStopPropagation = true;}


        if (this.evt.pageX || this.evt.pageY) 
        { 
            this.pageX = this.evt.pageX; this.pageY = this.evt.pageY;
        }
        else if (this.evt.clientX || this.evt.clientY) 
        {
            if (document.documentElement
                 && (document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) 
            {
                //IE 6 (in standards compliant mode)
                this.pageX = this.clientX + document.documentElement.scrollLeft;
                this.pageY = this.clientY + document.documentElement.scrollTop;
            } 
            else if (document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) 
            {
                //IE 4, 5 & 6 (in non-standards compliant mode)
                this.pageX = this.clientX + document.body.scrollLeft;
                this.pageY = this.clientY + document.body.scrollTop;
            }   
        }
}

MochiKitEvent.prototype.toString=function() {
    var printString='';

        for (var i in this) {
                if(!(i in MochiKitEvent.prototype)) printString += '\n' + i + '=' + this[i];
        }
        return printString;
}

Note that when you click on text, konqueror and safari will report the text node as the event's target, while other browsers will report the parent node element. This is a commonly used workaround (written from memory, excuse errors):

while(evt.target.nodeType==3) { //3 means text node
   evt.target=evt.target.parentNode;
}