3 var rnamespaces = /\.(.*)$/,
4 rformElems = /^(?:textarea|input|select)$/i,
7 rescape = /[^\w\s.|`]/g,
8 fcleanup = function( nm ) {
9 return nm.replace(rescape, "\\$&");
11 focusCounts = { focusin: 0, focusout: 0 };
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 // Use a key less likely to result in collisions for plain JS objects.
63 var eventKey = elem.nodeType ? "events" : "__events__",
64 events = elemData[ eventKey ],
65 eventHandle = elemData.handle;
67 if ( typeof events === "function" ) {
68 // On plain objects events is a fn that holds the the data
69 // which prevents this data from being JSON serialized
70 // the function does not need to be called, it just contains the data
71 eventHandle = events.handle;
72 events = events.events;
74 } else if ( !events ) {
75 if ( !elem.nodeType ) {
76 // On plain objects, create a fn that acts as the holder
77 // of the values to avoid JSON serialization of event data
78 elemData[ eventKey ] = elemData = function(){};
81 elemData.events = events = {};
85 elemData.handle = eventHandle = function() {
86 // Handle the second event of a trigger and when
87 // an event is called after a page has unloaded
88 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
89 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
94 // Add elem as a property of the handle function
95 // This is to prevent a memory leak with non-native events in IE.
96 eventHandle.elem = elem;
98 // Handle multiple events separated by a space
99 // jQuery(...).bind("mouseover mouseout", fn);
100 types = types.split(" ");
102 var type, i = 0, namespaces;
104 while ( (type = types[ i++ ]) ) {
105 handleObj = handleObjIn ?
106 jQuery.extend({}, handleObjIn) :
107 { handler: handler, data: data };
109 // Namespaced event handlers
110 if ( type.indexOf(".") > -1 ) {
111 namespaces = type.split(".");
112 type = namespaces.shift();
113 handleObj.namespace = namespaces.slice(0).sort().join(".");
117 handleObj.namespace = "";
120 handleObj.type = type;
121 if ( !handleObj.guid ) {
122 handleObj.guid = handler.guid;
125 // Get the current list of functions bound to this event
126 var handlers = events[ type ],
127 special = jQuery.event.special[ type ] || {};
129 // Init the event handler queue
131 handlers = events[ type ] = [];
133 // Check for a special event handler
134 // Only use addEventListener/attachEvent if the special
135 // events handler returns false
136 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
137 // Bind the global event handler to the element
138 if ( elem.addEventListener ) {
139 elem.addEventListener( type, eventHandle, false );
141 } else if ( elem.attachEvent ) {
142 elem.attachEvent( "on" + type, eventHandle );
148 special.add.call( elem, handleObj );
150 if ( !handleObj.handler.guid ) {
151 handleObj.handler.guid = handler.guid;
155 // Add the function to the element's handler list
156 handlers.push( handleObj );
158 // Keep track of which events have been used, for global triggering
159 jQuery.event.global[ type ] = true;
162 // Nullify elem to prevent memory leaks in IE
168 // Detach an event or set of events from an element
169 remove: function( elem, types, handler, pos ) {
170 // don't do events on text and comment nodes
171 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
175 if ( handler === false ) {
176 handler = returnFalse;
179 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
180 eventKey = elem.nodeType ? "events" : "__events__",
181 elemData = jQuery.data( elem ),
182 events = elemData && elemData[ eventKey ];
184 if ( !elemData || !events ) {
188 if ( typeof events === "function" ) {
190 events = events.events;
193 // types is actually an event object here
194 if ( types && types.type ) {
195 handler = types.handler;
199 // Unbind all events for the element
200 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
203 for ( type in events ) {
204 jQuery.event.remove( elem, type + types );
210 // Handle multiple events separated by a space
211 // jQuery(...).unbind("mouseover mouseout", fn);
212 types = types.split(" ");
214 while ( (type = types[ i++ ]) ) {
217 all = type.indexOf(".") < 0;
221 // Namespaced event handlers
222 namespaces = type.split(".");
223 type = namespaces.shift();
225 namespace = new RegExp("(^|\\.)" +
226 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
229 eventType = events[ type ];
236 for ( j = 0; j < eventType.length; j++ ) {
237 handleObj = eventType[ j ];
239 if ( all || namespace.test( handleObj.namespace ) ) {
240 jQuery.event.remove( elem, origType, handleObj.handler, j );
241 eventType.splice( j--, 1 );
248 special = jQuery.event.special[ type ] || {};
250 for ( j = pos || 0; j < eventType.length; j++ ) {
251 handleObj = eventType[ j ];
253 if ( handler.guid === handleObj.guid ) {
254 // remove the given handler for the given type
255 if ( all || namespace.test( handleObj.namespace ) ) {
257 eventType.splice( j--, 1 );
260 if ( special.remove ) {
261 special.remove.call( elem, handleObj );
271 // remove generic event handler if no more handlers exist
272 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
273 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
274 jQuery.removeEvent( elem, type, elemData.handle );
278 delete events[ type ];
282 // Remove the expando if it's no longer used
283 if ( jQuery.isEmptyObject( events ) ) {
284 var handle = elemData.handle;
289 delete elemData.events;
290 delete elemData.handle;
292 if ( typeof elemData === "function" ) {
293 jQuery.removeData( elem, eventKey );
295 } else if ( jQuery.isEmptyObject( elemData ) ) {
296 jQuery.removeData( elem );
301 // bubbling is internal
302 trigger: function( event, data, elem /*, bubbling */ ) {
303 // Event object or event type
304 var type = event.type || event,
305 bubbling = arguments[3];
308 event = typeof event === "object" ?
309 // jQuery.Event object
310 event[ jQuery.expando ] ? event :
312 jQuery.extend( jQuery.Event(type), event ) :
313 // Just the event type (string)
316 if ( type.indexOf("!") >= 0 ) {
317 event.type = type = type.slice(0, -1);
318 event.exclusive = true;
321 // Handle a global trigger
323 // Don't bubble custom events when global (to avoid too much overhead)
324 event.stopPropagation();
326 // Only trigger if we've ever bound an event for it
327 if ( jQuery.event.global[ type ] ) {
328 jQuery.each( jQuery.cache, function() {
329 if ( this.events && this.events[type] ) {
330 jQuery.event.trigger( event, data, this.handle.elem );
336 // Handle triggering a single element
338 // don't do events on text and comment nodes
339 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
343 // Clean up in case it is reused
344 event.result = undefined;
347 // Clone the incoming data, if any
348 data = jQuery.makeArray( data );
349 data.unshift( event );
352 event.currentTarget = elem;
354 // Trigger the event, it is assumed that "handle" is a function
355 var handle = elem.nodeType ?
356 jQuery.data( elem, "handle" ) :
357 (jQuery.data( elem, "__events__" ) || {}).handle;
360 handle.apply( elem, data );
363 var parent = elem.parentNode || elem.ownerDocument;
365 // Trigger an inline bound script
367 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
368 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
369 event.result = false;
370 event.preventDefault();
374 // prevent IE from throwing an error for some elements with some event types, see #3533
375 } catch (inlineError) {}
377 if ( !event.isPropagationStopped() && parent ) {
378 jQuery.event.trigger( event, data, parent, true );
380 } else if ( !event.isDefaultPrevented() ) {
382 target = event.target,
383 targetType = type.replace( rnamespaces, "" ),
384 isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
385 special = jQuery.event.special[ targetType ] || {};
387 if ( (!special._default || special._default.call( elem, event ) === false) &&
388 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
391 if ( target[ targetType ] ) {
392 // Make sure that we don't accidentally re-trigger the onFOO events
393 old = target[ "on" + targetType ];
396 target[ "on" + targetType ] = null;
399 jQuery.event.triggered = true;
400 target[ targetType ]();
403 // prevent IE from throwing an error for some elements with some event types, see #3533
404 } catch (triggerError) {}
407 target[ "on" + targetType ] = old;
410 jQuery.event.triggered = false;
415 handle: function( event ) {
416 var all, handlers, namespaces, namespace_re, events,
418 args = jQuery.makeArray( arguments );
420 event = args[0] = jQuery.event.fix( event || window.event );
421 event.currentTarget = this;
423 // Namespaced event handlers
424 all = event.type.indexOf(".") < 0 && !event.exclusive;
427 namespaces = event.type.split(".");
428 event.type = namespaces.shift();
429 namespace_sort = namespaces.slice(0).sort();
430 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
433 event.namespace = event.namespace || namespace_sort.join(".");
435 events = jQuery.data(this, this.nodeType ? "events" : "__events__");
437 if ( typeof events === "function" ) {
438 events = events.events;
441 handlers = (events || {})[ event.type ];
443 if ( events && handlers ) {
444 // Clone the handlers to prevent manipulation
445 handlers = handlers.slice(0);
447 for ( var j = 0, l = handlers.length; j < l; j++ ) {
448 var handleObj = handlers[ j ];
450 // Filter the functions by class
451 if ( all || namespace_re.test( handleObj.namespace ) ) {
452 // Pass in a reference to the handler function itself
453 // So that we can later remove it
454 event.handler = handleObj.handler;
455 event.data = handleObj.data;
456 event.handleObj = handleObj;
458 var ret = handleObj.handler.apply( this, args );
460 if ( ret !== undefined ) {
462 if ( ret === false ) {
463 event.preventDefault();
464 event.stopPropagation();
468 if ( event.isImmediatePropagationStopped() ) {
478 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(" "),
480 fix: function( event ) {
481 if ( event[ jQuery.expando ] ) {
485 // store a copy of the original event object
486 // and "clone" to set read-only properties
487 var originalEvent = event;
488 event = jQuery.Event( originalEvent );
490 for ( var i = this.props.length, prop; i; ) {
491 prop = this.props[ --i ];
492 event[ prop ] = originalEvent[ prop ];
495 // Fix target property, if necessary
496 if ( !event.target ) {
497 // Fixes #1925 where srcElement might not be defined either
498 event.target = event.srcElement || document;
501 // check if target is a textnode (safari)
502 if ( event.target.nodeType === 3 ) {
503 event.target = event.target.parentNode;
506 // Add relatedTarget, if necessary
507 if ( !event.relatedTarget && event.fromElement ) {
508 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
511 // Calculate pageX/Y if missing and clientX/Y available
512 if ( event.pageX == null && event.clientX != null ) {
513 var doc = document.documentElement,
514 body = document.body;
516 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
517 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
520 // Add which for key events
521 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
522 event.which = event.charCode != null ? event.charCode : event.keyCode;
525 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
526 if ( !event.metaKey && event.ctrlKey ) {
527 event.metaKey = event.ctrlKey;
530 // Add which for click: 1 === left; 2 === middle; 3 === right
531 // Note: button is not normalized, so don't use it
532 if ( !event.which && event.button !== undefined ) {
533 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
539 // Deprecated, use jQuery.guid instead
542 // Deprecated, use jQuery.proxy instead
547 // Make sure the ready event is setup
548 setup: jQuery.bindReady,
549 teardown: jQuery.noop
553 add: function( handleObj ) {
554 jQuery.event.add( this,
555 liveConvert( handleObj.origType, handleObj.selector ),
556 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
559 remove: function( handleObj ) {
560 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
565 setup: function( data, namespaces, eventHandle ) {
566 // We only want to do this special case on windows
567 if ( jQuery.isWindow( this ) ) {
568 this.onbeforeunload = eventHandle;
572 teardown: function( namespaces, eventHandle ) {
573 if ( this.onbeforeunload === eventHandle ) {
574 this.onbeforeunload = null;
581 jQuery.removeEvent = document.removeEventListener ?
582 function( elem, type, handle ) {
583 if ( elem.removeEventListener ) {
584 elem.removeEventListener( type, handle, false );
587 function( elem, type, handle ) {
588 if ( elem.detachEvent ) {
589 elem.detachEvent( "on" + type, handle );
593 jQuery.Event = function( src ) {
594 // Allow instantiation without the 'new' keyword
595 if ( !this.preventDefault ) {
596 return new jQuery.Event( src );
600 if ( src && src.type ) {
601 this.originalEvent = src;
602 this.type = src.type;
603 // Events bubbling up the document may have been marked as prevented
604 // by a handler lower down the tree; reflect the correct value.
605 this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
606 src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
612 // timeStamp is buggy for some events on Firefox(#3843)
613 // So we won't rely on the native value
614 this.timeStamp = jQuery.now();
617 this[ jQuery.expando ] = true;
620 function returnFalse() {
623 function returnTrue() {
627 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
628 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
629 jQuery.Event.prototype = {
630 preventDefault: function() {
631 this.isDefaultPrevented = returnTrue;
633 var e = this.originalEvent;
638 // if preventDefault exists run it on the original event
639 if ( e.preventDefault ) {
642 // otherwise set the returnValue property of the original event to false (IE)
644 e.returnValue = false;
647 stopPropagation: function() {
648 this.isPropagationStopped = returnTrue;
650 var e = this.originalEvent;
654 // if stopPropagation exists run it on the original event
655 if ( e.stopPropagation ) {
658 // otherwise set the cancelBubble property of the original event to true (IE)
659 e.cancelBubble = true;
661 stopImmediatePropagation: function() {
662 this.isImmediatePropagationStopped = returnTrue;
663 this.stopPropagation();
665 isDefaultPrevented: returnFalse,
666 isPropagationStopped: returnFalse,
667 isImmediatePropagationStopped: returnFalse
670 // Checks if an event happened on an element within another element
671 // Used in jQuery.event.special.mouseenter and mouseleave handlers
672 var withinElement = function( event ) {
673 // Check if mouse(over|out) are still within the same parent element
674 var parent = event.relatedTarget;
676 // Firefox sometimes assigns relatedTarget a XUL element
677 // which we cannot access the parentNode property of
679 // Traverse up the tree
680 while ( parent && parent !== this ) {
681 parent = parent.parentNode;
684 if ( parent !== this ) {
685 // set the correct event type
686 event.type = event.data;
688 // handle event if we actually just moused on to a non sub-element
689 jQuery.event.handle.apply( this, arguments );
692 // assuming we've left the element since we most likely mousedover a xul element
696 // In case of event delegation, we only need to rename the event.type,
697 // liveHandler will take care of the rest.
698 delegate = function( event ) {
699 event.type = event.data;
700 jQuery.event.handle.apply( this, arguments );
703 // Create mouseenter and mouseleave events
705 mouseenter: "mouseover",
706 mouseleave: "mouseout"
707 }, function( orig, fix ) {
708 jQuery.event.special[ orig ] = {
709 setup: function( data ) {
710 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
712 teardown: function( data ) {
713 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
719 if ( !jQuery.support.submitBubbles ) {
721 jQuery.event.special.submit = {
722 setup: function( data, namespaces ) {
723 if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
724 jQuery.event.add(this, "click.specialSubmit", function( e ) {
728 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
729 e.liveFired = undefined;
730 return trigger( "submit", this, arguments );
734 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
738 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
739 e.liveFired = undefined;
740 return trigger( "submit", this, arguments );
749 teardown: function( namespaces ) {
750 jQuery.event.remove( this, ".specialSubmit" );
756 // change delegation, happens here so we have bind.
757 if ( !jQuery.support.changeBubbles ) {
761 getVal = function( elem ) {
762 var type = elem.type, val = elem.value;
764 if ( type === "radio" || type === "checkbox" ) {
767 } else if ( type === "select-multiple" ) {
768 val = elem.selectedIndex > -1 ?
769 jQuery.map( elem.options, function( elem ) {
770 return elem.selected;
774 } else if ( elem.nodeName.toLowerCase() === "select" ) {
775 val = elem.selectedIndex;
781 testChange = function testChange( e ) {
782 var elem = e.target, data, val;
784 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
788 data = jQuery.data( elem, "_change_data" );
791 // the current data will be also retrieved by beforeactivate
792 if ( e.type !== "focusout" || elem.type !== "radio" ) {
793 jQuery.data( elem, "_change_data", val );
796 if ( data === undefined || val === data ) {
800 if ( data != null || val ) {
802 e.liveFired = undefined;
803 return jQuery.event.trigger( e, arguments[1], elem );
807 jQuery.event.special.change = {
809 focusout: testChange,
811 beforedeactivate: testChange,
813 click: function( e ) {
814 var elem = e.target, type = elem.type;
816 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
817 return testChange.call( this, e );
821 // Change has to be called before submit
822 // Keydown will be called before keypress, which is used in submit-event delegation
823 keydown: function( e ) {
824 var elem = e.target, type = elem.type;
826 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
827 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
828 type === "select-multiple" ) {
829 return testChange.call( this, e );
833 // Beforeactivate happens also before the previous element is blurred
834 // with this event you can't trigger a change event, but you can store
836 beforeactivate: function( e ) {
838 jQuery.data( elem, "_change_data", getVal(elem) );
842 setup: function( data, namespaces ) {
843 if ( this.type === "file" ) {
847 for ( var type in changeFilters ) {
848 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
851 return rformElems.test( this.nodeName );
854 teardown: function( namespaces ) {
855 jQuery.event.remove( this, ".specialChange" );
857 return rformElems.test( this.nodeName );
861 changeFilters = jQuery.event.special.change.filters;
863 // Handle when the input is .focus()'d
864 changeFilters.focus = changeFilters.beforeactivate;
867 function trigger( type, elem, args ) {
869 return jQuery.event.handle.apply( elem, args );
872 // Create "bubbling" focus and blur events
873 if ( document.addEventListener ) {
874 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
875 jQuery.event.special[ fix ] = {
877 if ( focusCounts[fix]++ === 0 ) {
878 document.addEventListener( orig, handler, true );
881 teardown: function() {
882 if ( --focusCounts[fix] === 0 ) {
883 document.removeEventListener( orig, handler, true );
888 function handler( e ) {
889 e = jQuery.event.fix( e );
891 return jQuery.event.trigger( e, null, e.target );
896 jQuery.each(["bind", "one"], function( i, name ) {
897 jQuery.fn[ name ] = function( type, data, fn ) {
898 // Handle object literals
899 if ( typeof type === "object" ) {
900 for ( var key in type ) {
901 this[ name ](key, data, type[key], fn);
906 if ( jQuery.isFunction( data ) || data === false ) {
911 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
912 jQuery( this ).unbind( event, handler );
913 return fn.apply( this, arguments );
916 if ( type === "unload" && name !== "one" ) {
917 this.one( type, data, fn );
920 for ( var i = 0, l = this.length; i < l; i++ ) {
921 jQuery.event.add( this[i], type, handler, data );
930 unbind: function( type, fn ) {
931 // Handle object literals
932 if ( typeof type === "object" && !type.preventDefault ) {
933 for ( var key in type ) {
934 this.unbind(key, type[key]);
938 for ( var i = 0, l = this.length; i < l; i++ ) {
939 jQuery.event.remove( this[i], type, fn );
946 delegate: function( selector, types, data, fn ) {
947 return this.live( types, data, fn, selector );
950 undelegate: function( selector, types, fn ) {
951 if ( arguments.length === 0 ) {
952 return this.unbind( "live" );
955 return this.die( types, null, fn, selector );
959 trigger: function( type, data ) {
960 return this.each(function() {
961 jQuery.event.trigger( type, data, this );
965 triggerHandler: function( type, data ) {
967 var event = jQuery.Event( type );
968 event.preventDefault();
969 event.stopPropagation();
970 jQuery.event.trigger( event, data, this[0] );
975 toggle: function( fn ) {
976 // Save reference to arguments for access in closure
977 var args = arguments,
980 // link all the functions, so any of them can unbind this click handler
981 while ( i < args.length ) {
982 jQuery.proxy( fn, args[ i++ ] );
985 return this.click( jQuery.proxy( fn, function( event ) {
986 // Figure out which function to execute
987 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
988 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
990 // Make sure that clicks stop
991 event.preventDefault();
993 // and execute the function
994 return args[ lastToggle ].apply( this, arguments ) || false;
998 hover: function( fnOver, fnOut ) {
999 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
1006 mouseenter: "mouseover",
1007 mouseleave: "mouseout"
1010 jQuery.each(["live", "die"], function( i, name ) {
1011 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
1012 var type, i = 0, match, namespaces, preType,
1013 selector = origSelector || this.selector,
1014 context = origSelector ? this : jQuery( this.context );
1016 if ( typeof types === "object" && !types.preventDefault ) {
1017 for ( var key in types ) {
1018 context[ name ]( key, data, types[key], selector );
1024 if ( jQuery.isFunction( data ) ) {
1029 types = (types || "").split(" ");
1031 while ( (type = types[ i++ ]) != null ) {
1032 match = rnamespaces.exec( type );
1036 namespaces = match[0];
1037 type = type.replace( rnamespaces, "" );
1040 if ( type === "hover" ) {
1041 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1047 if ( type === "focus" || type === "blur" ) {
1048 types.push( liveMap[ type ] + namespaces );
1049 type = type + namespaces;
1052 type = (liveMap[ type ] || type) + namespaces;
1055 if ( name === "live" ) {
1056 // bind live handler
1057 for ( var j = 0, l = context.length; j < l; j++ ) {
1058 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1059 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1063 // unbind live handler
1064 context.unbind( "live." + liveConvert( type, selector ), fn );
1072 function liveHandler( event ) {
1073 var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1076 events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
1078 if ( typeof events === "function" ) {
1079 events = events.events;
1082 // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1083 if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1087 if ( event.namespace ) {
1088 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1091 event.liveFired = this;
1093 var live = events.live.slice(0);
1095 for ( j = 0; j < live.length; j++ ) {
1096 handleObj = live[j];
1098 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1099 selectors.push( handleObj.selector );
1102 live.splice( j--, 1 );
1106 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1108 for ( i = 0, l = match.length; i < l; i++ ) {
1111 for ( j = 0; j < live.length; j++ ) {
1112 handleObj = live[j];
1114 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1118 // Those two events require additional checking
1119 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1120 event.type = handleObj.preType;
1121 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1124 if ( !related || related !== elem ) {
1125 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1131 for ( i = 0, l = elems.length; i < l; i++ ) {
1134 if ( maxLevel && match.level > maxLevel ) {
1138 event.currentTarget = match.elem;
1139 event.data = match.handleObj.data;
1140 event.handleObj = match.handleObj;
1142 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1144 if ( ret === false || event.isPropagationStopped() ) {
1145 maxLevel = match.level;
1147 if ( ret === false ) {
1150 if ( event.isImmediatePropagationStopped() ) {
1159 function liveConvert( type, selector ) {
1160 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1163 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1164 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1165 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1167 // Handle event binding
1168 jQuery.fn[ name ] = function( data, fn ) {
1174 return arguments.length > 0 ?
1175 this.bind( name, data, fn ) :
1176 this.trigger( name );
1179 if ( jQuery.attrFn ) {
1180 jQuery.attrFn[ name ] = true;
1184 // Prevent memory leaks in IE
1185 // Window isn't included so as not to unbind existing unload events
1187 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1188 if ( window.attachEvent && !window.addEventListener ) {
1189 jQuery(window).bind("unload", function() {
1190 for ( var id in jQuery.cache ) {
1191 if ( jQuery.cache[ id ].handle ) {
1192 // Try/Catch is to handle iframes being unloaded, see #4280
1194 jQuery.event.remove( jQuery.cache[ id ].handle.elem );