Moved unload abort code so that the event is only bound if the xhr transport is used...
[jquery.git] / src / event.js
index 6e65438..675e5ff 100644 (file)
@@ -1,9 +1,14 @@
+(function( jQuery ) {
+
 var rnamespaces = /\.(.*)$/,
+       rformElems = /^(?:textarea|input|select)$/i,
+       rperiod = /\./g,
+       rspace = / /g,
+       rescape = /[^\w\s.|`]/g,
        fcleanup = function( nm ) {
-               return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
-                       return "\\" + ch;
-               });
-       };
+               return nm.replace(rescape, "\\$&");
+       },
+       focusCounts = { focusin: 0, focusout: 0 };
 
 /*
  * A number of helper functions used for managing events.
@@ -21,10 +26,17 @@ jQuery.event = {
 
                // For whatever reason, IE has trouble passing the window object
                // around, causing it to be cloned in the process
-               if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
+               if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
                        elem = window;
                }
 
+               if ( handler === false ) {
+                       handler = returnFalse;
+               } else if ( !handler ) {
+                       // Fixes bug #7229. Fix recommended by jdalton
+                 return;
+               }
+
                var handleObjIn, handleObj;
 
                if ( handler.handler ) {
@@ -46,8 +58,28 @@ jQuery.event = {
                        return;
                }
 
-               var events = elemData.events = elemData.events || {},
-                       eventHandle = elemData.handle, eventHandle;
+               // 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 ],
+                       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
+                       // the function does not need to be called, it just contains the data
+                       eventHandle = events.handle;
+                       events = events.events;
+
+               } else if ( !events ) {
+                       if ( !elem.nodeType ) {
+                               // On plain objects, create a fn that acts as the holder
+                               // of the values to avoid JSON serialization of event data
+                               elemData[ eventKey ] = elemData = function(){};
+                       }
+
+                       elemData.events = events = {};
+               }
 
                if ( !eventHandle ) {
                        elemData.handle = eventHandle = function() {
@@ -86,7 +118,9 @@ jQuery.event = {
                        }
 
                        handleObj.type = type;
-                       handleObj.guid = handler.guid;
+                       if ( !handleObj.guid ) {
+                               handleObj.guid = handler.guid;
+                       }
 
                        // Get the current list of functions bound to this event
                        var handlers = events[ type ],
@@ -109,9 +143,13 @@ 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;
+                               }
                        }
 
                        // Add the function to the element's handler list
@@ -134,14 +172,24 @@ jQuery.event = {
                        return;
                }
 
-               var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+               if ( handler === false ) {
+                       handler = returnFalse;
+               }
+
+               var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+                       eventKey = elem.nodeType ? "events" : "__events__",
                        elemData = jQuery.data( elem ),
-                       events = elemData && elemData.events;
+                       events = elemData && elemData[ eventKey ];
 
                if ( !elemData || !events ) {
                        return;
                }
 
+               if ( typeof events === "function" ) {
+                       elemData = events;
+                       events = events.events;
+               }
+
                // types is actually an event object here
                if ( types && types.type ) {
                        handler = types.handler;
@@ -174,8 +222,8 @@ jQuery.event = {
                                namespaces = type.split(".");
                                type = namespaces.shift();
 
-                               namespace = new RegExp("(^|\\.)" + 
-                                       jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
+                               namespace = new RegExp("(^|\\.)" +
+                                       jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
                        }
 
                        eventType = events[ type ];
@@ -185,7 +233,7 @@ jQuery.event = {
                        }
 
                        if ( !handler ) {
-                               for ( var j = 0; j < eventType.length; j++ ) {
+                               for ( j = 0; j < eventType.length; j++ ) {
                                        handleObj = eventType[ j ];
 
                                        if ( all || namespace.test( handleObj.namespace ) ) {
@@ -199,7 +247,7 @@ jQuery.event = {
 
                        special = jQuery.event.special[ type ] || {};
 
-                       for ( var j = pos || 0; j < eventType.length; j++ ) {
+                       for ( j = pos || 0; j < eventType.length; j++ ) {
                                handleObj = eventType[ j ];
 
                                if ( handler.guid === handleObj.guid ) {
@@ -223,7 +271,7 @@ jQuery.event = {
                        // remove generic event handler if no more handlers exist
                        if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
                                if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
-                                       removeEvent( elem, type, elemData.handle );
+                                       jQuery.removeEvent( elem, type, elemData.handle );
                                }
 
                                ret = null;
@@ -241,7 +289,10 @@ jQuery.event = {
                        delete elemData.events;
                        delete elemData.handle;
 
-                       if ( jQuery.isEmptyObject( elemData ) ) {
+                       if ( typeof elemData === "function" ) {
+                               jQuery.removeData( elem, eventKey );
+
+                       } else if ( jQuery.isEmptyObject( elemData ) ) {
                                jQuery.removeData( elem );
                        }
                }
@@ -256,7 +307,7 @@ jQuery.event = {
                if ( !bubbling ) {
                        event = typeof event === "object" ?
                                // jQuery.Event object
-                               event[expando] ? event :
+                               event[ jQuery.expando ] ? event :
                                // Object literal
                                jQuery.extend( jQuery.Event(type), event ) :
                                // Just the event type (string)
@@ -301,7 +352,10 @@ jQuery.event = {
                event.currentTarget = elem;
 
                // Trigger the event, it is assumed that "handle" is a function
-               var handle = jQuery.data( elem, "handle" );
+               var handle = elem.nodeType ?
+                       jQuery.data( elem, "handle" ) :
+                       (jQuery.data( elem, "__events__" ) || {}).handle;
+
                if ( handle ) {
                        handle.apply( elem, data );
                }
@@ -313,41 +367,44 @@ jQuery.event = {
                        if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
                                if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
                                        event.result = false;
+                                       event.preventDefault();
                                }
                        }
 
                // prevent IE from throwing an error for some elements with some event types, see #3533
-               } catch (e) {}
+               } catch (inlineError) {}
 
                if ( !event.isPropagationStopped() && parent ) {
                        jQuery.event.trigger( event, data, parent, true );
 
                } else if ( !event.isDefaultPrevented() ) {
-                       var target = event.target, old,
-                               isClick = jQuery.nodeName(target, "a") && type === "click",
-                               special = jQuery.event.special[ type ] || {};
+                       var old,
+                               target = event.target,
+                               targetType = type.replace( rnamespaces, "" ),
+                               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 {
-                                       if ( target[ type ] ) {
+                                       if ( target[ targetType ] ) {
                                                // Make sure that we don't accidentally re-trigger the onFOO events
-                                               old = target[ "on" + type ];
+                                               old = target[ "on" + targetType ];
 
                                                if ( old ) {
-                                                       target[ "on" + type ] = null;
+                                                       target[ "on" + targetType ] = null;
                                                }
 
                                                jQuery.event.triggered = true;
-                                               target[ type ]();
+                                               target[ targetType ]();
                                        }
 
                                // prevent IE from throwing an error for some elements with some event types, see #3533
-                               } catch (e) {}
+                               } catch (triggerError) {}
 
                                if ( old ) {
-                                       target[ "on" + type ] = old;
+                                       target[ "on" + targetType ] = old;
                                }
 
                                jQuery.event.triggered = false;
@@ -356,9 +413,11 @@ jQuery.event = {
        },
 
        handle: function( event ) {
-               var all, handlers, namespaces, namespace, events;
+               var all, handlers, namespaces, namespace_re, events,
+                       namespace_sort = [],
+                       args = jQuery.makeArray( arguments );
 
-               event = arguments[0] = jQuery.event.fix( event || window.event );
+               event = args[0] = jQuery.event.fix( event || window.event );
                event.currentTarget = this;
 
                // Namespaced event handlers
@@ -367,10 +426,19 @@ jQuery.event = {
                if ( !all ) {
                        namespaces = event.type.split(".");
                        event.type = namespaces.shift();
-                       namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
+                       namespace_sort = namespaces.slice(0).sort();
+                       namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
                }
 
-               var events = jQuery.data(this, "events"), handlers = events[ event.type ];
+               event.namespace = event.namespace || namespace_sort.join(".");
+
+               events = jQuery.data(this, this.nodeType ? "events" : "__events__");
+
+               if ( typeof events === "function" ) {
+                       events = events.events;
+               }
+
+               handlers = (events || {})[ event.type ];
 
                if ( events && handlers ) {
                        // Clone the handlers to prevent manipulation
@@ -380,14 +448,14 @@ jQuery.event = {
                                var handleObj = handlers[ j ];
 
                                // Filter the functions by class
-                               if ( all || namespace.test( handleObj.namespace ) ) {
+                               if ( all || namespace_re.test( handleObj.namespace ) ) {
                                        // Pass in a reference to the handler function itself
                                        // So that we can later remove it
                                        event.handler = handleObj.handler;
                                        event.data = handleObj.data;
                                        event.handleObj = handleObj;
-       
-                                       var ret = handleObj.handler.apply( this, arguments );
+
+                                       var ret = handleObj.handler.apply( this, args );
 
                                        if ( ret !== undefined ) {
                                                event.result = ret;
@@ -407,10 +475,10 @@ jQuery.event = {
                return event.result;
        },
 
-       props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+       props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
 
        fix: function( event ) {
-               if ( event[ expando ] ) {
+               if ( event[ jQuery.expando ] ) {
                        return event;
                }
 
@@ -426,7 +494,8 @@ jQuery.event = {
 
                // Fix target property, if necessary
                if ( !event.target ) {
-                       event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+                       // Fixes #1925 where srcElement might not be defined either
+                       event.target = event.srcElement || document;
                }
 
                // check if target is a textnode (safari)
@@ -441,14 +510,16 @@ jQuery.event = {
 
                // Calculate pageX/Y if missing and clientX/Y available
                if ( event.pageX == null && event.clientX != null ) {
-                       var doc = document.documentElement, body = document.body;
+                       var doc = document.documentElement,
+                               body = document.body;
+
                        event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
                        event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
                }
 
                // Add which for key events
-               if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
-                       event.which = event.charCode || event.keyCode;
+               if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+                       event.which = event.charCode != null ? event.charCode : event.keyCode;
                }
 
                // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
@@ -480,36 +551,24 @@ jQuery.event = {
 
                live: {
                        add: function( handleObj ) {
-                               jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); 
+                               jQuery.event.add( this,
+                                       liveConvert( handleObj.origType, handleObj.selector ),
+                                       jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
                        },
 
                        remove: function( handleObj ) {
-                               var remove = true,
-                                       type = handleObj.origType.replace(rnamespaces, "");
-                               
-                               jQuery.each( jQuery.data(this, "events").live || [], function() {
-                                       if ( type === this.origType.replace(rnamespaces, "") ) {
-                                               remove = false;
-                                               return false;
-                                       }
-                               });
-
-                               if ( remove ) {
-                                       jQuery.event.remove( this, handleObj.origType, liveHandler );
-                               }
+                               jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
                        }
-
                },
 
                beforeunload: {
                        setup: function( data, namespaces, eventHandle ) {
                                // We only want to do this special case on windows
-                               if ( this.setInterval ) {
+                               if ( jQuery.isWindow( this ) ) {
                                        this.onbeforeunload = eventHandle;
                                }
-
-                               return false;
                        },
+
                        teardown: function( namespaces, eventHandle ) {
                                if ( this.onbeforeunload === eventHandle ) {
                                        this.onbeforeunload = null;
@@ -519,12 +578,16 @@ jQuery.event = {
        }
 };
 
-var removeEvent = document.removeEventListener ?
+jQuery.removeEvent = document.removeEventListener ?
        function( elem, type, handle ) {
-               elem.removeEventListener( type, handle, false );
-       } : 
+               if ( elem.removeEventListener ) {
+                       elem.removeEventListener( type, handle, false );
+               }
+       } :
        function( elem, type, handle ) {
-               elem.detachEvent( "on" + type, handle );
+               if ( elem.detachEvent ) {
+                       elem.detachEvent( "on" + type, handle );
+               }
        };
 
 jQuery.Event = function( src ) {
@@ -537,6 +600,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;
@@ -544,10 +613,10 @@ jQuery.Event = function( src ) {
 
        // timeStamp is buggy for some events on Firefox(#3843)
        // So we won't rely on the native value
-       this.timeStamp = now();
+       this.timeStamp = jQuery.now();
 
        // Mark it as fixed
-       this[ expando ] = true;
+       this[ jQuery.expando ] = true;
 };
 
 function returnFalse() {
@@ -567,13 +636,15 @@ jQuery.Event.prototype = {
                if ( !e ) {
                        return;
                }
-               
+
                // if preventDefault exists run it on the original event
                if ( e.preventDefault ) {
                        e.preventDefault();
-               }
+
                // otherwise set the returnValue property of the original event to false (IE)
-               e.returnValue = false;
+               } else {
+                       e.returnValue = false;
+               }
        },
        stopPropagation: function() {
                this.isPropagationStopped = returnTrue;
@@ -651,19 +722,23 @@ 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;
+                                       var elem = e.target,
+                                               type = elem.type;
 
                                        if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+                                               e.liveFired = undefined;
                                                return trigger( "submit", this, arguments );
                                        }
                                });
-        
+
                                jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
-                                       var elem = e.target, type = elem.type;
+                                       var elem = e.target,
+                                               type = elem.type;
 
                                        if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+                                               e.liveFired = undefined;
                                                return trigger( "submit", this, arguments );
                                        }
                                });
@@ -683,9 +758,7 @@ if ( !jQuery.support.submitBubbles ) {
 // change delegation, happens here so we have bind.
 if ( !jQuery.support.changeBubbles ) {
 
-       var formElems = /textarea|input|select/i,
-
-       changeFilters,
+       var changeFilters,
 
        getVal = function( elem ) {
                var type = elem.type, val = elem.value;
@@ -710,7 +783,7 @@ if ( !jQuery.support.changeBubbles ) {
        testChange = function testChange( e ) {
                var elem = e.target, data, val;
 
-               if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
+               if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
                        return;
                }
 
@@ -721,20 +794,23 @@ if ( !jQuery.support.changeBubbles ) {
                if ( e.type !== "focusout" || elem.type !== "radio" ) {
                        jQuery.data( elem, "_change_data", val );
                }
-               
+
                if ( data === undefined || val === data ) {
                        return;
                }
 
                if ( data != null || val ) {
                        e.type = "change";
+                       e.liveFired = undefined;
                        return jQuery.event.trigger( e, arguments[1], elem );
                }
        };
 
        jQuery.event.special.change = {
                filters: {
-                       focusout: testChange, 
+                       focusout: testChange,
+
+                       beforedeactivate: testChange,
 
                        click: function( e ) {
                                var elem = e.target, type = elem.type;
@@ -758,7 +834,7 @@ if ( !jQuery.support.changeBubbles ) {
 
                        // Beforeactivate happens also before the previous element is blurred
                        // with this event you can't trigger a change event, but you can store
-                       // information/focus[in] is not needed anymore
+                       // information
                        beforeactivate: function( e ) {
                                var elem = e.target;
                                jQuery.data( elem, "_change_data", getVal(elem) );
@@ -774,17 +850,20 @@ if ( !jQuery.support.changeBubbles ) {
                                jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
                        }
 
-                       return formElems.test( this.nodeName );
+                       return rformElems.test( this.nodeName );
                },
 
                teardown: function( namespaces ) {
                        jQuery.event.remove( this, ".specialChange" );
 
-                       return formElems.test( this.nodeName );
+                       return rformElems.test( this.nodeName );
                }
        };
 
        changeFilters = jQuery.event.special.change.filters;
+
+       // Handle when the input is .focus()'d
+       changeFilters.focus = changeFilters.beforeactivate;
 }
 
 function trigger( type, elem, args ) {
@@ -797,17 +876,21 @@ if ( document.addEventListener ) {
        jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
                jQuery.event.special[ fix ] = {
                        setup: function() {
-                               this.addEventListener( orig, handler, true );
-                       }, 
-                       teardown: function() { 
-                               this.removeEventListener( orig, handler, true );
+                               if ( focusCounts[fix]++ === 0 ) {
+                                       document.addEventListener( orig, handler, true );
+                               }
+                       },
+                       teardown: function() {
+                               if ( --focusCounts[fix] === 0 ) {
+                                       document.removeEventListener( orig, handler, true );
+                               }
                        }
                };
 
-               function handler( e ) { 
+               function handler( e ) {
                        e = jQuery.event.fix( e );
                        e.type = fix;
-                       return jQuery.event.handle.call( this, e );
+                       return jQuery.event.trigger( e, null, e.target );
                }
        });
 }
@@ -821,8 +904,8 @@ jQuery.each(["bind", "one"], function( i, name ) {
                        }
                        return this;
                }
-               
-               if ( jQuery.isFunction( data ) ) {
+
+               if ( jQuery.isFunction( data ) || data === false ) {
                        fn = data;
                        data = undefined;
                }
@@ -861,20 +944,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 );
@@ -893,7 +976,8 @@ jQuery.fn.extend({
 
        toggle: function( fn ) {
                // Save reference to arguments for access in closure
-               var args = arguments, i = 1;
+               var args = arguments,
+                       i = 1;
 
                // link all the functions, so any of them can unbind this click handler
                while ( i < args.length ) {
@@ -931,6 +1015,14 @@ jQuery.each(["live", "die"], function( i, name ) {
                        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;
+               }
+
                if ( jQuery.isFunction( data ) ) {
                        fn = data;
                        data = undefined;
@@ -964,31 +1056,40 @@ jQuery.each(["live", "die"], function( i, name ) {
 
                        if ( name === "live" ) {
                                // bind live handler
-                               context.each(function(){
-                                       jQuery.event.add( this, liveConvert( type, selector ),
+                               for ( var j = 0, l = context.length; j < l; j++ ) {
+                                       jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
                                                { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
-                               });
+                               }
 
                        } else {
                                // unbind live handler
-                               context.unbind( liveConvert( type, selector ), fn );
+                               context.unbind( "live." + liveConvert( type, selector ), fn );
                        }
                }
-               
+
                return this;
-       }
+       };
 });
 
 function liveHandler( event ) {
-       var stop, elems = [], selectors = [], args = arguments,
-               related, match, handleObj, elem, j, i, l, data,
-               events = jQuery.data( this, "events" );
+       var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+               elems = [],
+               selectors = [],
+               events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
 
-       // Make sure we avoid non-left-click bubbling in Firefox (#3861)
-       if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
+       if ( typeof events === "function" ) {
+               events = events.events;
+       }
+
+       // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
+       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("\\.(?:.*\\.)?") + "(\\.|$)");
+       }
+
        event.liveFired = this;
 
        var live = events.live.slice(0);
@@ -1007,20 +1108,23 @@ function liveHandler( event ) {
        match = jQuery( event.target ).closest( selectors, event.currentTarget );
 
        for ( i = 0, l = match.length; i < l; i++ ) {
+               close = match[i];
+
                for ( j = 0; j < live.length; j++ ) {
                        handleObj = live[j];
 
-                       if ( match[i].selector === handleObj.selector ) {
-                               elem = match[i].elem;
+                       if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
+                               elem = close.elem;
                                related = null;
 
                                // Those two events require additional checking
                                if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+                                       event.type = handleObj.preType;
                                        related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
                                }
 
                                if ( !related || related !== elem ) {
-                                       elems.push({ elem: elem, handleObj: handleObj });
+                                       elems.push({ elem: elem, handleObj: handleObj, level: close.level });
                                }
                        }
                }
@@ -1028,13 +1132,26 @@ function liveHandler( event ) {
 
        for ( i = 0, l = elems.length; i < l; i++ ) {
                match = elems[i];
+
+               if ( maxLevel && match.level > maxLevel ) {
+                       break;
+               }
+
                event.currentTarget = match.elem;
                event.data = match.handleObj.data;
                event.handleObj = match.handleObj;
 
-               if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {
-                       stop = false;
-                       break;
+               ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+               if ( ret === false || event.isPropagationStopped() ) {
+                       maxLevel = match.level;
+
+                       if ( ret === false ) {
+                               stop = false;
+                       }
+                       if ( event.isImmediatePropagationStopped() ) {
+                               break;
+                       }
                }
        }
 
@@ -1042,7 +1159,7 @@ function liveHandler( event ) {
 }
 
 function liveConvert( type, selector ) {
-       return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
+       return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
 }
 
 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
@@ -1050,8 +1167,15 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
        "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
 
        // Handle event binding
-       jQuery.fn[ name ] = function( fn ) {
-               return fn ? this.bind( name, fn ) : this.trigger( name );
+       jQuery.fn[ name ] = function( data, fn ) {
+               if ( fn == null ) {
+                       fn = data;
+                       data = null;
+               }
+
+               return arguments.length > 0 ?
+                       this.bind( name, data, fn ) :
+                       this.trigger( name );
        };
 
        if ( jQuery.attrFn ) {
@@ -1059,19 +1183,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 ) {
-       window.attachEvent("onunload", 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 );