Revert "Make sure that focusin/focusout bubbles in non-IE browsers." This was causing...
[jquery.git] / src / event.js
index 58a6953..2d53562 100644 (file)
@@ -8,7 +8,7 @@ var rnamespaces = /\.(.*)$/,
        fcleanup = function( nm ) {
                return nm.replace(rescape, "\\$&");
        },
-       focusCounts = { focusin: 0, focusout: 0 };
+       eventKey = "events";
 
 /*
  * A number of helper functions used for managing events.
@@ -50,7 +50,7 @@ jQuery.event = {
                }
 
                // Init the element's event structure
-               var elemData = jQuery.data( elem );
+               var elemData = jQuery._data( elem );
 
                // If no elemData is found then we must be trying to bind to one of the
                // banned noData elements
@@ -58,12 +58,9 @@ jQuery.event = {
                        return;
                }
 
-               // Use a key less likely to result in collisions for plain JS objects.
-               // Fixes bug #7150.
-               var eventKey = elem.nodeType ? "events" : "__events__",
-                       events = elemData[ eventKey ],
+               var events = elemData[ eventKey ],
                        eventHandle = elemData.handle;
-                       
+
                if ( typeof events === "function" ) {
                        // On plain objects events is a fn that holds the the data
                        // which prevents this data from being JSON serialized
@@ -143,9 +140,9 @@ jQuery.event = {
                                        }
                                }
                        }
-                       
-                       if ( special.add ) { 
-                               special.add.call( elem, handleObj ); 
+
+                       if ( special.add ) {
+                               special.add.call( elem, handleObj );
 
                                if ( !handleObj.handler.guid ) {
                                        handleObj.handler.guid = handler.guid;
@@ -177,14 +174,13 @@ jQuery.event = {
                }
 
                var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
-                       eventKey = elem.nodeType ? "events" : "__events__",
-                       elemData = jQuery.data( elem ),
+                       elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
                        events = elemData && elemData[ eventKey ];
 
                if ( !elemData || !events ) {
                        return;
                }
-               
+
                if ( typeof events === "function" ) {
                        elemData = events;
                        events = events.events;
@@ -222,7 +218,7 @@ jQuery.event = {
                                namespaces = type.split(".");
                                type = namespaces.shift();
 
-                               namespace = new RegExp("(^|\\.)" + 
+                               namespace = new RegExp("(^|\\.)" +
                                        jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
                        }
 
@@ -290,10 +286,10 @@ jQuery.event = {
                        delete elemData.handle;
 
                        if ( typeof elemData === "function" ) {
-                               jQuery.removeData( elem, eventKey );
+                               jQuery.removeData( elem, eventKey, true );
 
                        } else if ( jQuery.isEmptyObject( elemData ) ) {
-                               jQuery.removeData( elem );
+                               jQuery.removeData( elem, undefined, true );
                        }
                }
        },
@@ -325,9 +321,16 @@ jQuery.event = {
 
                                // Only trigger if we've ever bound an event for it
                                if ( jQuery.event.global[ type ] ) {
+                                       // XXX This code smells terrible. event.js should not be directly
+                                       // inspecting the data cache
                                        jQuery.each( jQuery.cache, function() {
-                                               if ( this.events && this.events[type] ) {
-                                                       jQuery.event.trigger( event, data, this.handle.elem );
+                                               // internalKey variable is just used to make it easier to find
+                                               // and potentially change this stuff later; currently it just
+                                               // points to jQuery.expando
+                                               var internalKey = jQuery.expando,
+                                                       internalCache = this[ internalKey ];
+                                               if ( internalCache && internalCache.events && internalCache.events[type] ) {
+                                                       jQuery.event.trigger( event, data, internalCache.handle.elem );
                                                }
                                        });
                                }
@@ -353,8 +356,8 @@ jQuery.event = {
 
                // Trigger the event, it is assumed that "handle" is a function
                var handle = elem.nodeType ?
-                       jQuery.data( elem, "handle" ) :
-                       (jQuery.data( elem, "__events__" ) || {}).handle;
+                       jQuery._data( elem, "handle" ) :
+                       (jQuery._data( elem, eventKey ) || {}).handle;
 
                if ( handle ) {
                        handle.apply( elem, data );
@@ -384,7 +387,7 @@ jQuery.event = {
                                isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
                                special = jQuery.event.special[ targetType ] || {};
 
-                       if ( (!special._default || special._default.call( elem, event ) === false) && 
+                       if ( (!special._default || special._default.call( elem, event ) === false) &&
                                !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
 
                                try {
@@ -432,7 +435,7 @@ jQuery.event = {
 
                event.namespace = event.namespace || namespace_sort.join(".");
 
-               events = jQuery.data(this, this.nodeType ? "events" : "__events__");
+               events = jQuery._data(this, eventKey);
 
                if ( typeof events === "function" ) {
                        events = events.events;
@@ -454,7 +457,7 @@ jQuery.event = {
                                        event.handler = handleObj.handler;
                                        event.data = handleObj.data;
                                        event.handleObj = handleObj;
-       
+
                                        var ret = handleObj.handler.apply( this, args );
 
                                        if ( ret !== undefined ) {
@@ -553,7 +556,7 @@ jQuery.event = {
                        add: function( handleObj ) {
                                jQuery.event.add( this,
                                        liveConvert( handleObj.origType, handleObj.selector ),
-                                       jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); 
+                                       jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
                        },
 
                        remove: function( handleObj ) {
@@ -583,7 +586,7 @@ jQuery.removeEvent = document.removeEventListener ?
                if ( elem.removeEventListener ) {
                        elem.removeEventListener( type, handle, false );
                }
-       } : 
+       } :
        function( elem, type, handle ) {
                if ( elem.detachEvent ) {
                        elem.detachEvent( "on" + type, handle );
@@ -600,6 +603,12 @@ jQuery.Event = function( src ) {
        if ( src && src.type ) {
                this.originalEvent = src;
                this.type = src.type;
+
+               // Events bubbling up the document may have been marked as prevented
+               // by a handler lower down the tree; reflect the correct value.
+               this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || 
+                       src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+
        // Event type
        } else {
                this.type = src;
@@ -630,7 +639,7 @@ jQuery.Event.prototype = {
                if ( !e ) {
                        return;
                }
-               
+
                // if preventDefault exists run it on the original event
                if ( e.preventDefault ) {
                        e.preventDefault();
@@ -716,7 +725,7 @@ if ( !jQuery.support.submitBubbles ) {
 
        jQuery.event.special.submit = {
                setup: function( data, namespaces ) {
-                       if ( this.nodeName.toLowerCase() !== "form" ) {
+                       if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
                                jQuery.event.add(this, "click.specialSubmit", function( e ) {
                                        var elem = e.target,
                                                type = elem.type;
@@ -726,7 +735,7 @@ if ( !jQuery.support.submitBubbles ) {
                                                return trigger( "submit", this, arguments );
                                        }
                                });
-        
+
                                jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
                                        var elem = e.target,
                                                type = elem.type;
@@ -781,14 +790,14 @@ if ( !jQuery.support.changeBubbles ) {
                        return;
                }
 
-               data = jQuery.data( elem, "_change_data" );
+               data = jQuery._data( elem, "_change_data" );
                val = getVal(elem);
 
                // the current data will be also retrieved by beforeactivate
                if ( e.type !== "focusout" || elem.type !== "radio" ) {
-                       jQuery.data( elem, "_change_data", val );
+                       jQuery._data( elem, "_change_data", val );
                }
-               
+
                if ( data === undefined || val === data ) {
                        return;
                }
@@ -802,7 +811,7 @@ if ( !jQuery.support.changeBubbles ) {
 
        jQuery.event.special.change = {
                filters: {
-                       focusout: testChange, 
+                       focusout: testChange,
 
                        beforedeactivate: testChange,
 
@@ -831,7 +840,7 @@ if ( !jQuery.support.changeBubbles ) {
                        // information
                        beforeactivate: function( e ) {
                                var elem = e.target;
-                               jQuery.data( elem, "_change_data", getVal(elem) );
+                               jQuery._data( elem, "_change_data", getVal(elem) );
                        }
                },
 
@@ -870,21 +879,17 @@ if ( document.addEventListener ) {
        jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
                jQuery.event.special[ fix ] = {
                        setup: function() {
-                               if ( focusCounts[fix]++ === 0 ) {
-                                       document.addEventListener( orig, handler, true );
-                               }
+                               this.addEventListener( orig, handler, true );
                        }, 
                        teardown: function() { 
-                               if ( --focusCounts[fix] === 0 ) {
-                                       document.removeEventListener( orig, handler, true );
-                               }
+                               this.removeEventListener( orig, handler, true );
                        }
                };
 
-               function handler( e ) { 
+               function handler( e ) {
                        e = jQuery.event.fix( e );
                        e.type = fix;
-                       return jQuery.event.trigger( e, null, e.target );
+                       return jQuery.event.handle.call( this, e );
                }
        });
 }
@@ -898,7 +903,7 @@ jQuery.each(["bind", "one"], function( i, name ) {
                        }
                        return this;
                }
-               
+
                if ( jQuery.isFunction( data ) || data === false ) {
                        fn = data;
                        data = undefined;
@@ -938,20 +943,20 @@ jQuery.fn.extend({
 
                return this;
        },
-       
+
        delegate: function( selector, types, data, fn ) {
                return this.live( types, data, fn, selector );
        },
-       
+
        undelegate: function( selector, types, fn ) {
                if ( arguments.length === 0 ) {
                                return this.unbind( "live" );
-               
+
                } else {
                        return this.die( types, null, fn, selector );
                }
        },
-       
+
        trigger: function( type, data ) {
                return this.each(function() {
                        jQuery.event.trigger( type, data, this );
@@ -980,8 +985,8 @@ jQuery.fn.extend({
 
                return this.click( jQuery.proxy( fn, function( event ) {
                        // Figure out which function to execute
-                       var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
-                       jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+                       var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+                       jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
 
                        // Make sure that clicks stop
                        event.preventDefault();
@@ -1008,12 +1013,12 @@ jQuery.each(["live", "die"], function( i, name ) {
                var type, i = 0, match, namespaces, preType,
                        selector = origSelector || this.selector,
                        context = origSelector ? this : jQuery( this.context );
-               
+
                if ( typeof types === "object" && !types.preventDefault ) {
                        for ( var key in types ) {
                                context[ name ]( key, data, types[key], selector );
                        }
-                       
+
                        return this;
                }
 
@@ -1060,7 +1065,7 @@ jQuery.each(["live", "die"], function( i, name ) {
                                context.unbind( "live." + liveConvert( type, selector ), fn );
                        }
                }
-               
+
                return this;
        };
 });
@@ -1069,7 +1074,7 @@ function liveHandler( event ) {
        var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
                elems = [],
                selectors = [],
-               events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
+               events = jQuery._data( this, eventKey );
 
        if ( typeof events === "function" ) {
                events = events.events;
@@ -1079,7 +1084,7 @@ function liveHandler( event ) {
        if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
                return;
        }
-       
+
        if ( event.namespace ) {
                namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
        }
@@ -1177,21 +1182,4 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
        }
 });
 
-// Prevent memory leaks in IE
-// Window isn't included so as not to unbind existing unload events
-// More info:
-//  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
-if ( window.attachEvent && !window.addEventListener ) {
-       jQuery(window).bind("unload", function() {
-               for ( var id in jQuery.cache ) {
-                       if ( jQuery.cache[ id ].handle ) {
-                               // Try/Catch is to handle iframes being unloaded, see #4280
-                               try {
-                                       jQuery.event.remove( jQuery.cache[ id ].handle.elem );
-                               } catch(e) {}
-                       }
-               }
-       });
-}
-
 })( jQuery );