3 var rnamespaces = /\.(.*)$/,
4 rformElems = /^(?:textarea|input|select)$/i,
7 rescape = /[^\w\s.|`]/g,
8 fcleanup = function( nm ) {
9 return nm.replace(rescape, "\\$&");
14 * A number of helper functions used for managing events.
15 * Many of the ideas behind this code originated from
16 * Dean Edwards' addEvent library.
20 // Bind an event to an element
21 // Original by Dean Edwards
22 add: function( elem, types, handler, data ) {
23 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
27 // For whatever reason, IE has trouble passing the window object
28 // around, causing it to be cloned in the process
29 if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
33 if ( handler === false ) {
34 handler = returnFalse;
35 } else if ( !handler ) {
36 // Fixes bug #7229. Fix recommended by jdalton
40 var handleObjIn, handleObj;
42 if ( handler.handler ) {
43 handleObjIn = handler;
44 handler = handleObjIn.handler;
47 // Make sure that the function being executed has a unique ID
48 if ( !handler.guid ) {
49 handler.guid = jQuery.guid++;
52 // Init the element's event structure
53 var elemData = jQuery._data( elem );
55 // If no elemData is found then we must be trying to bind to one of the
56 // banned noData elements
61 var events = elemData[ eventKey ],
62 eventHandle = elemData.handle;
64 if ( typeof events === "function" ) {
65 // On plain objects events is a fn that holds the the data
66 // which prevents this data from being JSON serialized
67 // the function does not need to be called, it just contains the data
68 eventHandle = events.handle;
69 events = events.events;
71 } else if ( !events ) {
72 if ( !elem.nodeType ) {
73 // On plain objects, create a fn that acts as the holder
74 // of the values to avoid JSON serialization of event data
75 elemData[ eventKey ] = elemData = function(){};
78 elemData.events = events = {};
82 elemData.handle = eventHandle = function() {
83 // Handle the second event of a trigger and when
84 // an event is called after a page has unloaded
85 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
86 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
91 // Add elem as a property of the handle function
92 // This is to prevent a memory leak with non-native events in IE.
93 eventHandle.elem = elem;
95 // Handle multiple events separated by a space
96 // jQuery(...).bind("mouseover mouseout", fn);
97 types = types.split(" ");
99 var type, i = 0, namespaces;
101 while ( (type = types[ i++ ]) ) {
102 handleObj = handleObjIn ?
103 jQuery.extend({}, handleObjIn) :
104 { handler: handler, data: data };
106 // Namespaced event handlers
107 if ( type.indexOf(".") > -1 ) {
108 namespaces = type.split(".");
109 type = namespaces.shift();
110 handleObj.namespace = namespaces.slice(0).sort().join(".");
114 handleObj.namespace = "";
117 handleObj.type = type;
118 if ( !handleObj.guid ) {
119 handleObj.guid = handler.guid;
122 // Get the current list of functions bound to this event
123 var handlers = events[ type ],
124 special = jQuery.event.special[ type ] || {};
126 // Init the event handler queue
128 handlers = events[ type ] = [];
130 // Check for a special event handler
131 // Only use addEventListener/attachEvent if the special
132 // events handler returns false
133 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
134 // Bind the global event handler to the element
135 if ( elem.addEventListener ) {
136 elem.addEventListener( type, eventHandle, false );
138 } else if ( elem.attachEvent ) {
139 elem.attachEvent( "on" + type, eventHandle );
145 special.add.call( elem, handleObj );
147 if ( !handleObj.handler.guid ) {
148 handleObj.handler.guid = handler.guid;
152 // Add the function to the element's handler list
153 handlers.push( handleObj );
155 // Keep track of which events have been used, for global triggering
156 jQuery.event.global[ type ] = true;
159 // Nullify elem to prevent memory leaks in IE
165 // Detach an event or set of events from an element
166 remove: function( elem, types, handler, pos ) {
167 // don't do events on text and comment nodes
168 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
172 if ( handler === false ) {
173 handler = returnFalse;
176 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
177 elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
178 events = elemData && elemData[ eventKey ];
180 if ( !elemData || !events ) {
184 if ( typeof events === "function" ) {
186 events = events.events;
189 // types is actually an event object here
190 if ( types && types.type ) {
191 handler = types.handler;
195 // Unbind all events for the element
196 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
199 for ( type in events ) {
200 jQuery.event.remove( elem, type + types );
206 // Handle multiple events separated by a space
207 // jQuery(...).unbind("mouseover mouseout", fn);
208 types = types.split(" ");
210 while ( (type = types[ i++ ]) ) {
213 all = type.indexOf(".") < 0;
217 // Namespaced event handlers
218 namespaces = type.split(".");
219 type = namespaces.shift();
221 namespace = new RegExp("(^|\\.)" +
222 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
225 eventType = events[ type ];
232 for ( j = 0; j < eventType.length; j++ ) {
233 handleObj = eventType[ j ];
235 if ( all || namespace.test( handleObj.namespace ) ) {
236 jQuery.event.remove( elem, origType, handleObj.handler, j );
237 eventType.splice( j--, 1 );
244 special = jQuery.event.special[ type ] || {};
246 for ( j = pos || 0; j < eventType.length; j++ ) {
247 handleObj = eventType[ j ];
249 if ( handler.guid === handleObj.guid ) {
250 // remove the given handler for the given type
251 if ( all || namespace.test( handleObj.namespace ) ) {
253 eventType.splice( j--, 1 );
256 if ( special.remove ) {
257 special.remove.call( elem, handleObj );
267 // remove generic event handler if no more handlers exist
268 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
269 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
270 jQuery.removeEvent( elem, type, elemData.handle );
274 delete events[ type ];
278 // Remove the expando if it's no longer used
279 if ( jQuery.isEmptyObject( events ) ) {
280 var handle = elemData.handle;
285 delete elemData.events;
286 delete elemData.handle;
288 if ( typeof elemData === "function" ) {
289 jQuery.removeData( elem, eventKey, true );
291 } else if ( jQuery.isEmptyObject( elemData ) ) {
292 jQuery.removeData( elem, undefined, true );
297 // bubbling is internal
298 trigger: function( event, data, elem /*, bubbling */ ) {
299 // Event object or event type
300 var type = event.type || event,
301 bubbling = arguments[3];
304 event = typeof event === "object" ?
305 // jQuery.Event object
306 event[ jQuery.expando ] ? event :
308 jQuery.extend( jQuery.Event(type), event ) :
309 // Just the event type (string)
312 if ( type.indexOf("!") >= 0 ) {
313 event.type = type = type.slice(0, -1);
314 event.exclusive = true;
317 // Handle a global trigger
319 // Don't bubble custom events when global (to avoid too much overhead)
320 event.stopPropagation();
322 // Only trigger if we've ever bound an event for it
323 if ( jQuery.event.global[ type ] ) {
324 // XXX This code smells terrible. event.js should not be directly
325 // inspecting the data cache
326 jQuery.each( jQuery.cache, function() {
327 // internalKey variable is just used to make it easier to find
328 // and potentially change this stuff later; currently it just
329 // points to jQuery.expando
330 var internalKey = jQuery.expando,
331 internalCache = this[ internalKey ];
332 if ( internalCache && internalCache.events && internalCache.events[type] ) {
333 jQuery.event.trigger( event, data, internalCache.handle.elem );
339 // Handle triggering a single element
341 // don't do events on text and comment nodes
342 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
346 // Clean up in case it is reused
347 event.result = undefined;
350 // Clone the incoming data, if any
351 data = jQuery.makeArray( data );
352 data.unshift( event );
355 event.currentTarget = elem;
357 // Trigger the event, it is assumed that "handle" is a function
358 var handle = elem.nodeType ?
359 jQuery._data( elem, "handle" ) :
360 (jQuery._data( elem, eventKey ) || {}).handle;
363 handle.apply( elem, data );
366 var parent = elem.parentNode || elem.ownerDocument;
368 // Trigger an inline bound script
370 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
371 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
372 event.result = false;
373 event.preventDefault();
377 // prevent IE from throwing an error for some elements with some event types, see #3533
378 } catch (inlineError) {}
380 if ( !event.isPropagationStopped() && parent ) {
381 jQuery.event.trigger( event, data, parent, true );
383 } else if ( !event.isDefaultPrevented() ) {
385 target = event.target,
386 targetType = type.replace( rnamespaces, "" ),
387 isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
388 special = jQuery.event.special[ targetType ] || {};
390 if ( (!special._default || special._default.call( elem, event ) === false) &&
391 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
394 if ( target[ targetType ] ) {
395 // Make sure that we don't accidentally re-trigger the onFOO events
396 old = target[ "on" + targetType ];
399 target[ "on" + targetType ] = null;
402 jQuery.event.triggered = true;
403 target[ targetType ]();
406 // prevent IE from throwing an error for some elements with some event types, see #3533
407 } catch (triggerError) {}
410 target[ "on" + targetType ] = old;
413 jQuery.event.triggered = false;
418 handle: function( event ) {
419 var all, handlers, namespaces, namespace_re, events,
421 args = jQuery.makeArray( arguments );
423 event = args[0] = jQuery.event.fix( event || window.event );
424 event.currentTarget = this;
426 // Namespaced event handlers
427 all = event.type.indexOf(".") < 0 && !event.exclusive;
430 namespaces = event.type.split(".");
431 event.type = namespaces.shift();
432 namespace_sort = namespaces.slice(0).sort();
433 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
436 event.namespace = event.namespace || namespace_sort.join(".");
438 events = jQuery._data(this, eventKey);
440 if ( typeof events === "function" ) {
441 events = events.events;
444 handlers = (events || {})[ event.type ];
446 if ( events && handlers ) {
447 // Clone the handlers to prevent manipulation
448 handlers = handlers.slice(0);
450 for ( var j = 0, l = handlers.length; j < l; j++ ) {
451 var handleObj = handlers[ j ];
453 // Filter the functions by class
454 if ( all || namespace_re.test( handleObj.namespace ) ) {
455 // Pass in a reference to the handler function itself
456 // So that we can later remove it
457 event.handler = handleObj.handler;
458 event.data = handleObj.data;
459 event.handleObj = handleObj;
461 var ret = handleObj.handler.apply( this, args );
463 if ( ret !== undefined ) {
465 if ( ret === false ) {
466 event.preventDefault();
467 event.stopPropagation();
471 if ( event.isImmediatePropagationStopped() ) {
481 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(" "),
483 fix: function( event ) {
484 if ( event[ jQuery.expando ] ) {
488 // store a copy of the original event object
489 // and "clone" to set read-only properties
490 var originalEvent = event;
491 event = jQuery.Event( originalEvent );
493 for ( var i = this.props.length, prop; i; ) {
494 prop = this.props[ --i ];
495 event[ prop ] = originalEvent[ prop ];
498 // Fix target property, if necessary
499 if ( !event.target ) {
500 // Fixes #1925 where srcElement might not be defined either
501 event.target = event.srcElement || document;
504 // check if target is a textnode (safari)
505 if ( event.target.nodeType === 3 ) {
506 event.target = event.target.parentNode;
509 // Add relatedTarget, if necessary
510 if ( !event.relatedTarget && event.fromElement ) {
511 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
514 // Calculate pageX/Y if missing and clientX/Y available
515 if ( event.pageX == null && event.clientX != null ) {
516 var doc = document.documentElement,
517 body = document.body;
519 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
520 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
523 // Add which for key events
524 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
525 event.which = event.charCode != null ? event.charCode : event.keyCode;
528 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
529 if ( !event.metaKey && event.ctrlKey ) {
530 event.metaKey = event.ctrlKey;
533 // Add which for click: 1 === left; 2 === middle; 3 === right
534 // Note: button is not normalized, so don't use it
535 if ( !event.which && event.button !== undefined ) {
536 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
542 // Deprecated, use jQuery.guid instead
545 // Deprecated, use jQuery.proxy instead
550 // Make sure the ready event is setup
551 setup: jQuery.bindReady,
552 teardown: jQuery.noop
556 add: function( handleObj ) {
557 jQuery.event.add( this,
558 liveConvert( handleObj.origType, handleObj.selector ),
559 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
562 remove: function( handleObj ) {
563 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
568 setup: function( data, namespaces, eventHandle ) {
569 // We only want to do this special case on windows
570 if ( jQuery.isWindow( this ) ) {
571 this.onbeforeunload = eventHandle;
575 teardown: function( namespaces, eventHandle ) {
576 if ( this.onbeforeunload === eventHandle ) {
577 this.onbeforeunload = null;
584 jQuery.removeEvent = document.removeEventListener ?
585 function( elem, type, handle ) {
586 if ( elem.removeEventListener ) {
587 elem.removeEventListener( type, handle, false );
590 function( elem, type, handle ) {
591 if ( elem.detachEvent ) {
592 elem.detachEvent( "on" + type, handle );
596 jQuery.Event = function( src ) {
597 // Allow instantiation without the 'new' keyword
598 if ( !this.preventDefault ) {
599 return new jQuery.Event( src );
603 if ( src && src.type ) {
604 this.originalEvent = src;
605 this.type = src.type;
607 // Events bubbling up the document may have been marked as prevented
608 // by a handler lower down the tree; reflect the correct value.
609 this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
610 src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
617 // timeStamp is buggy for some events on Firefox(#3843)
618 // So we won't rely on the native value
619 this.timeStamp = jQuery.now();
622 this[ jQuery.expando ] = true;
625 function returnFalse() {
628 function returnTrue() {
632 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
633 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
634 jQuery.Event.prototype = {
635 preventDefault: function() {
636 this.isDefaultPrevented = returnTrue;
638 var e = this.originalEvent;
643 // if preventDefault exists run it on the original event
644 if ( e.preventDefault ) {
647 // otherwise set the returnValue property of the original event to false (IE)
649 e.returnValue = false;
652 stopPropagation: function() {
653 this.isPropagationStopped = returnTrue;
655 var e = this.originalEvent;
659 // if stopPropagation exists run it on the original event
660 if ( e.stopPropagation ) {
663 // otherwise set the cancelBubble property of the original event to true (IE)
664 e.cancelBubble = true;
666 stopImmediatePropagation: function() {
667 this.isImmediatePropagationStopped = returnTrue;
668 this.stopPropagation();
670 isDefaultPrevented: returnFalse,
671 isPropagationStopped: returnFalse,
672 isImmediatePropagationStopped: returnFalse
675 // Checks if an event happened on an element within another element
676 // Used in jQuery.event.special.mouseenter and mouseleave handlers
677 var withinElement = function( event ) {
678 // Check if mouse(over|out) are still within the same parent element
679 var parent = event.relatedTarget;
681 // Firefox sometimes assigns relatedTarget a XUL element
682 // which we cannot access the parentNode property of
684 // Traverse up the tree
685 while ( parent && parent !== this ) {
686 parent = parent.parentNode;
689 if ( parent !== this ) {
690 // set the correct event type
691 event.type = event.data;
693 // handle event if we actually just moused on to a non sub-element
694 jQuery.event.handle.apply( this, arguments );
697 // assuming we've left the element since we most likely mousedover a xul element
701 // In case of event delegation, we only need to rename the event.type,
702 // liveHandler will take care of the rest.
703 delegate = function( event ) {
704 event.type = event.data;
705 jQuery.event.handle.apply( this, arguments );
708 // Create mouseenter and mouseleave events
710 mouseenter: "mouseover",
711 mouseleave: "mouseout"
712 }, function( orig, fix ) {
713 jQuery.event.special[ orig ] = {
714 setup: function( data ) {
715 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
717 teardown: function( data ) {
718 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
724 if ( !jQuery.support.submitBubbles ) {
726 jQuery.event.special.submit = {
727 setup: function( data, namespaces ) {
728 if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
729 jQuery.event.add(this, "click.specialSubmit", function( e ) {
733 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
734 e.liveFired = undefined;
735 return trigger( "submit", this, arguments );
739 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
743 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
744 e.liveFired = undefined;
745 return trigger( "submit", this, arguments );
754 teardown: function( namespaces ) {
755 jQuery.event.remove( this, ".specialSubmit" );
761 // change delegation, happens here so we have bind.
762 if ( !jQuery.support.changeBubbles ) {
766 getVal = function( elem ) {
767 var type = elem.type, val = elem.value;
769 if ( type === "radio" || type === "checkbox" ) {
772 } else if ( type === "select-multiple" ) {
773 val = elem.selectedIndex > -1 ?
774 jQuery.map( elem.options, function( elem ) {
775 return elem.selected;
779 } else if ( elem.nodeName.toLowerCase() === "select" ) {
780 val = elem.selectedIndex;
786 testChange = function testChange( e ) {
787 var elem = e.target, data, val;
789 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
793 data = jQuery._data( elem, "_change_data" );
796 // the current data will be also retrieved by beforeactivate
797 if ( e.type !== "focusout" || elem.type !== "radio" ) {
798 jQuery._data( elem, "_change_data", val );
801 if ( data === undefined || val === data ) {
805 if ( data != null || val ) {
807 e.liveFired = undefined;
808 return jQuery.event.trigger( e, arguments[1], elem );
812 jQuery.event.special.change = {
814 focusout: testChange,
816 beforedeactivate: testChange,
818 click: function( e ) {
819 var elem = e.target, type = elem.type;
821 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
822 return testChange.call( this, e );
826 // Change has to be called before submit
827 // Keydown will be called before keypress, which is used in submit-event delegation
828 keydown: function( e ) {
829 var elem = e.target, type = elem.type;
831 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
832 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
833 type === "select-multiple" ) {
834 return testChange.call( this, e );
838 // Beforeactivate happens also before the previous element is blurred
839 // with this event you can't trigger a change event, but you can store
841 beforeactivate: function( e ) {
843 jQuery._data( elem, "_change_data", getVal(elem) );
847 setup: function( data, namespaces ) {
848 if ( this.type === "file" ) {
852 for ( var type in changeFilters ) {
853 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
856 return rformElems.test( this.nodeName );
859 teardown: function( namespaces ) {
860 jQuery.event.remove( this, ".specialChange" );
862 return rformElems.test( this.nodeName );
866 changeFilters = jQuery.event.special.change.filters;
868 // Handle when the input is .focus()'d
869 changeFilters.focus = changeFilters.beforeactivate;
872 function trigger( type, elem, args ) {
874 return jQuery.event.handle.apply( elem, args );
877 // Create "bubbling" focus and blur events
878 if ( document.addEventListener ) {
879 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
880 jQuery.event.special[ fix ] = {
882 this.addEventListener( orig, handler, true );
884 teardown: function() {
885 this.removeEventListener( orig, handler, true );
889 function handler( e ) {
890 e = jQuery.event.fix( e );
892 return jQuery.event.handle.call( this, e );
897 jQuery.each(["bind", "one"], function( i, name ) {
898 jQuery.fn[ name ] = function( type, data, fn ) {
899 // Handle object literals
900 if ( typeof type === "object" ) {
901 for ( var key in type ) {
902 this[ name ](key, data, type[key], fn);
907 if ( jQuery.isFunction( data ) || data === false ) {
912 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
913 jQuery( this ).unbind( event, handler );
914 return fn.apply( this, arguments );
917 if ( type === "unload" && name !== "one" ) {
918 this.one( type, data, fn );
921 for ( var i = 0, l = this.length; i < l; i++ ) {
922 jQuery.event.add( this[i], type, handler, data );
931 unbind: function( type, fn ) {
932 // Handle object literals
933 if ( typeof type === "object" && !type.preventDefault ) {
934 for ( var key in type ) {
935 this.unbind(key, type[key]);
939 for ( var i = 0, l = this.length; i < l; i++ ) {
940 jQuery.event.remove( this[i], type, fn );
947 delegate: function( selector, types, data, fn ) {
948 return this.live( types, data, fn, selector );
951 undelegate: function( selector, types, fn ) {
952 if ( arguments.length === 0 ) {
953 return this.unbind( "live" );
956 return this.die( types, null, fn, selector );
960 trigger: function( type, data ) {
961 return this.each(function() {
962 jQuery.event.trigger( type, data, this );
966 triggerHandler: function( type, data ) {
968 var event = jQuery.Event( type );
969 event.preventDefault();
970 event.stopPropagation();
971 jQuery.event.trigger( event, data, this[0] );
976 toggle: function( fn ) {
977 // Save reference to arguments for access in closure
978 var args = arguments,
981 // link all the functions, so any of them can unbind this click handler
982 while ( i < args.length ) {
983 jQuery.proxy( fn, args[ i++ ] );
986 return this.click( jQuery.proxy( fn, function( event ) {
987 // Figure out which function to execute
988 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
989 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
991 // Make sure that clicks stop
992 event.preventDefault();
994 // and execute the function
995 return args[ lastToggle ].apply( this, arguments ) || false;
999 hover: function( fnOver, fnOut ) {
1000 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
1007 mouseenter: "mouseover",
1008 mouseleave: "mouseout"
1011 jQuery.each(["live", "die"], function( i, name ) {
1012 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
1013 var type, i = 0, match, namespaces, preType,
1014 selector = origSelector || this.selector,
1015 context = origSelector ? this : jQuery( this.context );
1017 if ( typeof types === "object" && !types.preventDefault ) {
1018 for ( var key in types ) {
1019 context[ name ]( key, data, types[key], selector );
1025 if ( jQuery.isFunction( data ) ) {
1030 types = (types || "").split(" ");
1032 while ( (type = types[ i++ ]) != null ) {
1033 match = rnamespaces.exec( type );
1037 namespaces = match[0];
1038 type = type.replace( rnamespaces, "" );
1041 if ( type === "hover" ) {
1042 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1048 if ( type === "focus" || type === "blur" ) {
1049 types.push( liveMap[ type ] + namespaces );
1050 type = type + namespaces;
1053 type = (liveMap[ type ] || type) + namespaces;
1056 if ( name === "live" ) {
1057 // bind live handler
1058 for ( var j = 0, l = context.length; j < l; j++ ) {
1059 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1060 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1064 // unbind live handler
1065 context.unbind( "live." + liveConvert( type, selector ), fn );
1073 function liveHandler( event ) {
1074 var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1077 events = jQuery._data( this, eventKey );
1079 if ( typeof events === "function" ) {
1080 events = events.events;
1083 // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1084 if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1088 if ( event.namespace ) {
1089 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1092 event.liveFired = this;
1094 var live = events.live.slice(0);
1096 for ( j = 0; j < live.length; j++ ) {
1097 handleObj = live[j];
1099 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1100 selectors.push( handleObj.selector );
1103 live.splice( j--, 1 );
1107 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1109 for ( i = 0, l = match.length; i < l; i++ ) {
1112 for ( j = 0; j < live.length; j++ ) {
1113 handleObj = live[j];
1115 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1119 // Those two events require additional checking
1120 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1121 event.type = handleObj.preType;
1122 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1125 if ( !related || related !== elem ) {
1126 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1132 for ( i = 0, l = elems.length; i < l; i++ ) {
1135 if ( maxLevel && match.level > maxLevel ) {
1139 event.currentTarget = match.elem;
1140 event.data = match.handleObj.data;
1141 event.handleObj = match.handleObj;
1143 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1145 if ( ret === false || event.isPropagationStopped() ) {
1146 maxLevel = match.level;
1148 if ( ret === false ) {
1151 if ( event.isImmediatePropagationStopped() ) {
1160 function liveConvert( type, selector ) {
1161 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1164 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1165 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1166 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1168 // Handle event binding
1169 jQuery.fn[ name ] = function( data, fn ) {
1175 return arguments.length > 0 ?
1176 this.bind( name, data, fn ) :
1177 this.trigger( name );
1180 if ( jQuery.attrFn ) {
1181 jQuery.attrFn[ name ] = true;