Added support for the event object properties relatedTarget, metaKey, which, and...
[jquery.git] / src / event / event.js
index 3834fd6..a402340 100644 (file)
@@ -32,8 +32,11 @@ jQuery.event = {
                }
 
                // Make sure that the function being executed has a unique ID
-               if ( !handler.guid )
+               if ( !handler.guid ) {
                        handler.guid = this.guid++;
+                       // Don't forget to set guid for the original handler function
+                       if (fn) fn.guid = handler.guid;
+               }
 
                // Init the element's event structure
                if (!element.$events)
@@ -55,7 +58,7 @@ jQuery.event = {
                        if (element.addEventListener)
                                element.addEventListener(type, element.$handle, false);
                        else if (element.attachEvent)
-                               element.attachEvent("on" + type, element.$handle, false);
+                               element.attachEvent("on" + type, element.$handle);
                }
 
                // Add the function to the element's handler list
@@ -101,7 +104,7 @@ jQuery.event = {
                                        if (element.removeEventListener)
                                                element.removeEventListener(type, element.$handle, false);
                                        else if (element.detachEvent)
-                                               element.detachEvent("on" + type, element.$handle, false);
+                                               element.detachEvent("on" + type, element.$handle);
                                        ret = null;
                                        delete events[type];
                                }
@@ -126,7 +129,7 @@ jQuery.event = {
 
                // Handle triggering a single element
                else {
-                       var val, ret, fn = jQuery.isFunction( element[ type ] );
+                       var val, ret, fn = jQuery.isFunction( element[ type ] || null );
                        
                        // Pass along a fake event
                        data.unshift( this.fix({ type: type, target: element }) );
@@ -143,19 +146,18 @@ jQuery.event = {
        },
 
        handle: function(event) {
+               // returned undefined or false
+               var val;
+               
                // Handle the second event of a trigger and when
                // an event is called after a page has unloaded
-               if ( typeof jQuery == "undefined" || jQuery.event.triggered ) return;
+               if ( typeof jQuery == "undefined" || jQuery.event.triggered )
+                 return val;
 
                // Empty object is for triggered events with no data
                event = jQuery.event.fix( event || window.event || {} ); 
 
-               // returned undefined or false
-               var returnValue;
-
-               var c = this.$events[event.type];
-
-               var args = [].slice.call( arguments, 1 );
+               var c = this.$events && this.$events[event.type], args = [].slice.call( arguments, 1 );
                args.unshift( event );
 
                for ( var j in c ) {
@@ -167,14 +169,16 @@ jQuery.event = {
                        if ( c[j].apply( this, args ) === false ) {
                                event.preventDefault();
                                event.stopPropagation();
-                               returnValue = false;
+                               val = false;
                        }
                }
 
                // Clean up added properties in IE to prevent memory leak
-               if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;
+               if (jQuery.browser.msie)
+                       event.target = event.preventDefault = event.stopPropagation =
+                               event.handler = event.data = null;
 
-               return returnValue;
+               return val;
        },
 
        fix: function(event) {
@@ -182,12 +186,33 @@ jQuery.event = {
                if ( !event.target && event.srcElement )
                        event.target = event.srcElement;
 
+               // Add relatedTarget, if necessary
+               if ( !event.relatedTarget && event.fromElement )
+                       event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+               // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+               if ( event.metaKey == null && event.ctrlKey != null )
+                       event.metaKey = event.ctrlKey;
+
+               // Add which for click: 1 == left; 2 == middle; 3 == right
+               // Note: button is not normalized, so don't use it
+               if ( event.which == null && event.button != null )
+                       event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
                // Calculate pageX/Y if missing and clientX/Y available
-               if ( event.pageX == undefined && event.clientX != undefined ) {
-                       var e = document.documentElement, b = document.body;
-                       event.pageX = event.clientX + (e.scrollLeft || b.scrollLeft);
-                       event.pageY = event.clientY + (e.scrollTop || b.scrollTop);
+               if ( event.pageX == null && event.clientX != null ) {
+                       var e = document.documentElement || document.body;
+                       event.pageX = event.clientX + e.scrollLeft;
+                       event.pageY = event.clientY + e.scrollTop;
                }
+
+               // Add which for keypresses: keyCode
+               if ( (event.which == null || event.type == "keypress") && event.keyCode != null )
+                       event.which = event.keyCode;    
+
+               // If it's a keypress event, add charCode to IE
+               if ( event.charCode == null && event.type == "keypress" )
+                       event.charCode = event.keyCode;
                                
                // check if target is a textnode (safari)
                if (jQuery.browser.safari && event.target.nodeType == 3) {
@@ -274,7 +299,7 @@ jQuery.fn.extend({
         */
        bind: function( type, data, fn ) {
                return this.each(function(){
-                       jQuery.event.add( this, type, fn || data, data );
+                       jQuery.event.add( this, type, fn || data, fn && data );
                });
        },
        
@@ -309,7 +334,7 @@ jQuery.fn.extend({
                        jQuery.event.add( this, type, function(event) {
                                jQuery(this).unbind(event);
                                return (fn || data).apply( this, arguments);
-                       }, data);
+                       }, fn && data);
                });
        },
 
@@ -412,7 +437,7 @@ jQuery.fn.extend({
 
                return this.click(function(e) {
                        // Figure out which function to execute
-                       this.lastToggle = this.lastToggle == 0 ? 1 : 0;
+                       this.lastToggle = 0 == this.lastToggle ? 1 : 0;
                        
                        // Make sure that clicks stop
                        e.preventDefault();
@@ -452,7 +477,7 @@ jQuery.fn.extend({
                // A private function for handling mouse 'hovering'
                function handleHover(e) {
                        // Check if mouse(over|out) are still within the same parent element
-                       var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
+                       var p = e.relatedTarget;
        
                        // Traverse up the tree
                        while ( p && p != this ) try { p = p.parentNode } catch(e) { p = this; };
@@ -548,6 +573,9 @@ jQuery.extend({
                        // Remove event lisenter to avoid memory leak
                        if ( jQuery.browser.mozilla || jQuery.browser.opera )
                                document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
+                       
+                       // Remove script element used by IE hack
+                       jQuery(window).load(function(){ jQuery("#__ie_init").remove(); });
                }
        }
 });
@@ -925,7 +953,6 @@ new function(){
                if ( script ) 
                        script.onreadystatechange = function() {
                                if ( this.readyState != "complete" ) return;
-                               this.parentNode.removeChild( this );
                                jQuery.ready();
                        };