Query now throws no warnings under strict mode in Firefox (ticket #922). In fixing...
[jquery.git] / src / event / event.js
index 4347ae5..9adf477 100644 (file)
@@ -12,38 +12,58 @@ jQuery.event = {
                // around, causing it to be cloned in the process
                if ( jQuery.browser.msie && element.setInterval != undefined )
                        element = window;
+               
+               // if data is passed, bind to handler 
+               if( data != undefined ) { 
+               // Create temporary function pointer to original handler 
+                       var fn = handler; 
+
+                       // Create unique handler function, wrapped around original handler 
+                       handler = function() { 
+                               // Pass arguments and context to original handler 
+                               return fn.apply(this, arguments); 
+                       };
 
-               // if data is passed, bind to handler
-               if( data ) 
+                       // Store data in unique handler 
                        handler.data = data;
 
+                       // Set the guid of unique handler to the same of original handler, so it can be removed 
+                       handler.guid = fn.guid;
+               }
+
                // 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)
                        element.$events = {};
+               
+               if (!element.$handle)
+                       element.$handle = function() {
+                               jQuery.event.handle.apply(element, arguments);
+                       };
 
                // Get the current list of functions bound to this event
                var handlers = element.$events[type];
 
-               // If it hasn't been initialized yet
+               // Init the event handler queue
                if (!handlers) {
-                       // Init the event handler queue
-                       handlers = element.$events[type] = {};
-
-                       // Remember an existing handler, if it's already there
-                       if (element["on" + type])
-                               handlers[0] = element["on" + type];
+                       handlers = element.$events[type] = {};  
+                       
+                       // And bind the global event handler to the element
+                       if (element.addEventListener)
+                               element.addEventListener(type, element.$handle, false);
+                       else if (element.attachEvent)
+                               element.attachEvent("on" + type, element.$handle);
                }
 
                // Add the function to the element's handler list
                handlers[handler.guid] = handler;
 
-               // And bind the global event handler to the element
-               element["on" + type] = this.handle;
-
                // Remember the function in a global list (for triggering)
                if (!this.global[type])
                        this.global[type] = [];
@@ -55,35 +75,45 @@ jQuery.event = {
 
        // Detach an event or set of events from an element
        remove: function(element, type, handler) {
-               if (element.$events) {
-                       var i,j,k;
-                       if ( type && type.type ) { // type is actually an event object here
+               var events = element.$events, ret;
+
+               if ( events ) {
+                       // type is actually an event object here
+                       if ( type && type.type ) {
                                handler = type.handler;
-                               type    = type.type;
+                               type = type.type;
                        }
                        
-                       if (type && element.$events[type])
+                       if ( !type ) {
+                               for ( type in events )
+                                       this.remove( element, type );
+
+                       } else if ( events[type] ) {
                                // remove the given handler for the given type
                                if ( handler )
-                                       delete element.$events[type][handler.guid];
-                                       
+                                       delete events[type][handler.guid];
+                               
                                // remove all handlers for the given type
                                else
-                                       for ( i in element.$events[type] )
-                                               delete element.$events[type][i];
-                                               
-                       // remove all handlers          
-                       else
-                               for ( j in element.$events )
-                                       this.remove( element, j );
-                       
-                       // remove event handler if no more handlers exist
-                       for ( k in element.$events[type] )
-                               if (k) {
-                                       k = true;
-                                       break;
+                                       for ( handler in element.$events[type] )
+                                               delete events[type][handler];
+
+                               // remove generic event handler if no more handlers exist
+                               for ( ret in events[type] ) break;
+                               if ( !ret ) {
+                                       if (element.removeEventListener)
+                                               element.removeEventListener(type, element.$handle, false);
+                                       else if (element.detachEvent)
+                                               element.detachEvent("on" + type, element.$handle);
+                                       ret = null;
+                                       delete events[type];
                                }
-                       if (!k) element["on" + type] = null;
+                       }
+
+                       // Remove the expando if it's no longer used
+                       for ( ret in events ) break;
+                       if ( !ret )
+                               element.$handle = element.$events = null;
                }
        },
 
@@ -99,19 +129,16 @@ jQuery.event = {
 
                // Handle triggering a single element
                else {
-                       var handler = element["on" + type ], val,
-                               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 }) );
 
-                       if ( handler ) {
-                               // Pass along a fake event
-                               data.unshift( this.fix({ type: type, target: element }) );
-       
-                               // Trigger the event
-                               if ( (val = handler.apply( element, data )) !== false )
-                                       this.triggered = true;
-                       }
+                       // Trigger the event
+                       if ( (val = this.handle.apply( element, data )) !== false )
+                               this.triggered = true;
 
-                       if ( fn && val !== false )
+                       if ( fn && val !== false && !jQuery.nodeName(element, 'a') )
                                element[ type ]();
 
                        this.triggered = false;
@@ -119,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[event.type], args = [].slice.call( arguments, 1 );
                args.unshift( event );
 
                for ( var j in c ) {
@@ -143,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) {
@@ -250,7 +278,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 );
                });
        },
        
@@ -285,7 +313,7 @@ jQuery.fn.extend({
                        jQuery.event.add( this, type, function(event) {
                                jQuery(this).unbind(event);
                                return (fn || data).apply( this, arguments);
-                       }, data);
+                       }, fn && data);
                });
        },
 
@@ -388,7 +416,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();
@@ -524,6 +552,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(); });
                }
        }
 });
@@ -901,7 +932,6 @@ new function(){
                if ( script ) 
                        script.onreadystatechange = function() {
                                if ( this.readyState != "complete" ) return;
-                               this.parentNode.removeChild( this );
                                jQuery.ready();
                        };