3 var rnamespaces = /\.(.*)$/,
4 rformElems = /^(?:textarea|input|select)$/i,
7 rescape = /[^\w\s.|`]/g,
8 fcleanup = function( nm ) {
9 return nm.replace(rescape, "\\$&");
13 * A number of helper functions used for managing events.
14 * Many of the ideas behind this code originated from
15 * Dean Edwards' addEvent library.
19 // Bind an event to an element
20 // Original by Dean Edwards
21 add: function( elem, types, handler, data ) {
22 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
26 // For whatever reason, IE has trouble passing the window object
27 // around, causing it to be cloned in the process
28 if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
32 if ( handler === false ) {
33 handler = returnFalse;
36 var handleObjIn, handleObj;
38 if ( handler.handler ) {
39 handleObjIn = handler;
40 handler = handleObjIn.handler;
43 // Make sure that the function being executed has a unique ID
44 if ( !handler.guid ) {
45 handler.guid = jQuery.guid++;
48 // Init the element's event structure
49 var elemData = jQuery.data( elem );
51 // If no elemData is found then we must be trying to bind to one of the
52 // banned noData elements
57 var events = elemData.events,
58 eventHandle = elemData.handle;
60 if ( typeof events === "function" ) {
61 // On plain objects events is a fn that holds the the data
62 // which prevents this data from being JSON serialized
63 // the function does not need to be called, it just contains the data
64 eventHandle = events.handle;
65 events = events.events;
67 } else if ( !events ) {
68 if ( !elem.nodeType ) {
69 // On plain objects, create a fn that acts as the holder
70 // of the values to avoid JSON serialization of event data
71 elemData.events = elemData = function(){};
74 elemData.events = events = {};
78 elemData.handle = eventHandle = function() {
79 // Handle the second event of a trigger and when
80 // an event is called after a page has unloaded
81 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
82 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
87 // Add elem as a property of the handle function
88 // This is to prevent a memory leak with non-native events in IE.
89 eventHandle.elem = elem;
91 // Handle multiple events separated by a space
92 // jQuery(...).bind("mouseover mouseout", fn);
93 types = types.split(" ");
95 var type, i = 0, namespaces;
97 while ( (type = types[ i++ ]) ) {
98 handleObj = handleObjIn ?
99 jQuery.extend({}, handleObjIn) :
100 { handler: handler, data: data };
102 // Namespaced event handlers
103 if ( type.indexOf(".") > -1 ) {
104 namespaces = type.split(".");
105 type = namespaces.shift();
106 handleObj.namespace = namespaces.slice(0).sort().join(".");
110 handleObj.namespace = "";
113 handleObj.type = type;
114 if ( !handleObj.guid ) {
115 handleObj.guid = handler.guid;
118 // Get the current list of functions bound to this event
119 var handlers = events[ type ],
120 special = jQuery.event.special[ type ] || {};
122 // Init the event handler queue
124 handlers = events[ type ] = [];
126 // Check for a special event handler
127 // Only use addEventListener/attachEvent if the special
128 // events handler returns false
129 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
130 // Bind the global event handler to the element
131 if ( elem.addEventListener ) {
132 elem.addEventListener( type, eventHandle, false );
134 } else if ( elem.attachEvent ) {
135 elem.attachEvent( "on" + type, eventHandle );
141 special.add.call( elem, handleObj );
143 if ( !handleObj.handler.guid ) {
144 handleObj.handler.guid = handler.guid;
148 // Add the function to the element's handler list
149 handlers.push( handleObj );
151 // Keep track of which events have been used, for global triggering
152 jQuery.event.global[ type ] = true;
155 // Nullify elem to prevent memory leaks in IE
161 // Detach an event or set of events from an element
162 remove: function( elem, types, handler, pos ) {
163 // don't do events on text and comment nodes
164 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
168 if ( handler === false ) {
169 handler = returnFalse;
172 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
173 elemData = jQuery.data( elem ),
174 events = elemData && elemData.events;
176 if ( !elemData || !events ) {
180 if ( typeof events === "function" ) {
182 events = events.events;
185 // types is actually an event object here
186 if ( types && types.type ) {
187 handler = types.handler;
191 // Unbind all events for the element
192 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
195 for ( type in events ) {
196 jQuery.event.remove( elem, type + types );
202 // Handle multiple events separated by a space
203 // jQuery(...).unbind("mouseover mouseout", fn);
204 types = types.split(" ");
206 while ( (type = types[ i++ ]) ) {
209 all = type.indexOf(".") < 0;
213 // Namespaced event handlers
214 namespaces = type.split(".");
215 type = namespaces.shift();
217 namespace = new RegExp("(^|\\.)" +
218 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
221 eventType = events[ type ];
228 for ( j = 0; j < eventType.length; j++ ) {
229 handleObj = eventType[ j ];
231 if ( all || namespace.test( handleObj.namespace ) ) {
232 jQuery.event.remove( elem, origType, handleObj.handler, j );
233 eventType.splice( j--, 1 );
240 special = jQuery.event.special[ type ] || {};
242 for ( j = pos || 0; j < eventType.length; j++ ) {
243 handleObj = eventType[ j ];
245 if ( handler.guid === handleObj.guid ) {
246 // remove the given handler for the given type
247 if ( all || namespace.test( handleObj.namespace ) ) {
249 eventType.splice( j--, 1 );
252 if ( special.remove ) {
253 special.remove.call( elem, handleObj );
263 // remove generic event handler if no more handlers exist
264 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
265 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
266 jQuery.removeEvent( elem, type, elemData.handle );
270 delete events[ type ];
274 // Remove the expando if it's no longer used
275 if ( jQuery.isEmptyObject( events ) ) {
276 var handle = elemData.handle;
281 delete elemData.events;
282 delete elemData.handle;
284 if ( typeof elemData === "function" ) {
287 } else if ( jQuery.isEmptyObject( elemData ) ) {
288 jQuery.removeData( elem );
293 // bubbling is internal
294 trigger: function( event, data, elem /*, bubbling */ ) {
295 // Event object or event type
296 var type = event.type || event,
297 bubbling = arguments[3];
300 event = typeof event === "object" ?
301 // jQuery.Event object
302 event[ jQuery.expando ] ? event :
304 jQuery.extend( jQuery.Event(type), event ) :
305 // Just the event type (string)
308 if ( type.indexOf("!") >= 0 ) {
309 event.type = type = type.slice(0, -1);
310 event.exclusive = true;
313 // Handle a global trigger
315 // Don't bubble custom events when global (to avoid too much overhead)
316 event.stopPropagation();
318 // Only trigger if we've ever bound an event for it
319 if ( jQuery.event.global[ type ] ) {
320 jQuery.each( jQuery.cache, function() {
321 if ( this.events && this.events[type] ) {
322 jQuery.event.trigger( event, data, this.handle.elem );
328 // Handle triggering a single element
330 // don't do events on text and comment nodes
331 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
335 // Clean up in case it is reused
336 event.result = undefined;
339 // Clone the incoming data, if any
340 data = jQuery.makeArray( data );
341 data.unshift( event );
344 event.currentTarget = elem;
346 // Trigger the event, it is assumed that "handle" is a function
347 var handle = elem.nodeType ?
348 jQuery.data( elem, "handle" ) :
349 elem.events && elem.events.handle;
352 handle.apply( elem, data );
355 var parent = elem.parentNode || elem.ownerDocument;
357 // Trigger an inline bound script
359 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
360 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
361 event.result = false;
362 event.preventDefault();
366 // prevent IE from throwing an error for some elements with some event types, see #3533
367 } catch (inlineError) {}
369 if ( !event.isPropagationStopped() && parent ) {
370 jQuery.event.trigger( event, data, parent, true );
372 } else if ( !event.isDefaultPrevented() ) {
373 var target = event.target, old, targetType = type.replace(rnamespaces, ""),
374 isClick = jQuery.nodeName(target, "a") && targetType === "click",
375 special = jQuery.event.special[ targetType ] || {};
377 if ( (!special._default || special._default.call( elem, event ) === false) &&
378 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
381 if ( target[ targetType ] ) {
382 // Make sure that we don't accidentally re-trigger the onFOO events
383 old = target[ "on" + targetType ];
386 target[ "on" + targetType ] = null;
389 jQuery.event.triggered = true;
390 target[ targetType ]();
393 // prevent IE from throwing an error for some elements with some event types, see #3533
394 } catch (triggerError) {}
397 target[ "on" + targetType ] = old;
400 jQuery.event.triggered = false;
405 handle: function( event ) {
406 var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
408 event = args[0] = jQuery.event.fix( event || window.event );
409 event.currentTarget = this;
411 // Namespaced event handlers
412 all = event.type.indexOf(".") < 0 && !event.exclusive;
415 namespaces = event.type.split(".");
416 event.type = namespaces.shift();
417 namespace_sort = namespaces.slice(0).sort();
418 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
421 event.namespace = event.namespace || namespace_sort.join(".");
423 events = jQuery.data(this, "events");
425 if ( typeof events === "function" ) {
426 events = events.events;
429 handlers = (events || {})[ event.type ];
431 if ( events && handlers ) {
432 // Clone the handlers to prevent manipulation
433 handlers = handlers.slice(0);
435 for ( var j = 0, l = handlers.length; j < l; j++ ) {
436 var handleObj = handlers[ j ];
438 // Filter the functions by class
439 if ( all || namespace_re.test( handleObj.namespace ) ) {
440 // Pass in a reference to the handler function itself
441 // So that we can later remove it
442 event.handler = handleObj.handler;
443 event.data = handleObj.data;
444 event.handleObj = handleObj;
446 var ret = handleObj.handler.apply( this, args );
448 if ( ret !== undefined ) {
450 if ( ret === false ) {
451 event.preventDefault();
452 event.stopPropagation();
456 if ( event.isImmediatePropagationStopped() ) {
466 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(" "),
468 fix: function( event ) {
469 if ( event[ jQuery.expando ] ) {
473 // store a copy of the original event object
474 // and "clone" to set read-only properties
475 var originalEvent = event;
476 event = jQuery.Event( originalEvent );
478 for ( var i = this.props.length, prop; i; ) {
479 prop = this.props[ --i ];
480 event[ prop ] = originalEvent[ prop ];
483 // Fix target property, if necessary
484 if ( !event.target ) {
485 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
488 // check if target is a textnode (safari)
489 if ( event.target.nodeType === 3 ) {
490 event.target = event.target.parentNode;
493 // Add relatedTarget, if necessary
494 if ( !event.relatedTarget && event.fromElement ) {
495 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
498 // Calculate pageX/Y if missing and clientX/Y available
499 if ( event.pageX == null && event.clientX != null ) {
500 var doc = document.documentElement, body = document.body;
501 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
502 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
505 // Add which for key events
506 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
507 event.which = event.charCode != null ? event.charCode : event.keyCode;
510 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
511 if ( !event.metaKey && event.ctrlKey ) {
512 event.metaKey = event.ctrlKey;
515 // Add which for click: 1 === left; 2 === middle; 3 === right
516 // Note: button is not normalized, so don't use it
517 if ( !event.which && event.button !== undefined ) {
518 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
524 // Deprecated, use jQuery.guid instead
527 // Deprecated, use jQuery.proxy instead
532 // Make sure the ready event is setup
533 setup: jQuery.bindReady,
534 teardown: jQuery.noop
538 add: function( handleObj ) {
539 jQuery.event.add( this,
540 liveConvert( handleObj.origType, handleObj.selector ),
541 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
544 remove: function( handleObj ) {
545 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
550 setup: function( data, namespaces, eventHandle ) {
551 // We only want to do this special case on windows
552 if ( jQuery.isWindow( this ) ) {
553 this.onbeforeunload = eventHandle;
557 teardown: function( namespaces, eventHandle ) {
558 if ( this.onbeforeunload === eventHandle ) {
559 this.onbeforeunload = null;
566 jQuery.removeEvent = document.removeEventListener ?
567 function( elem, type, handle ) {
568 if ( elem.removeEventListener ) {
569 elem.removeEventListener( type, handle, false );
572 function( elem, type, handle ) {
573 if ( elem.detachEvent ) {
574 elem.detachEvent( "on" + type, handle );
578 jQuery.Event = function( src ) {
579 // Allow instantiation without the 'new' keyword
580 if ( !this.preventDefault ) {
581 return new jQuery.Event( src );
585 if ( src && src.type ) {
586 this.originalEvent = src;
587 this.type = src.type;
593 // timeStamp is buggy for some events on Firefox(#3843)
594 // So we won't rely on the native value
595 this.timeStamp = jQuery.now();
598 this[ jQuery.expando ] = true;
601 function returnFalse() {
604 function returnTrue() {
608 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
609 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
610 jQuery.Event.prototype = {
611 preventDefault: function() {
612 this.isDefaultPrevented = returnTrue;
614 var e = this.originalEvent;
619 // if preventDefault exists run it on the original event
620 if ( e.preventDefault ) {
623 // otherwise set the returnValue property of the original event to false (IE)
625 e.returnValue = false;
628 stopPropagation: function() {
629 this.isPropagationStopped = returnTrue;
631 var e = this.originalEvent;
635 // if stopPropagation exists run it on the original event
636 if ( e.stopPropagation ) {
639 // otherwise set the cancelBubble property of the original event to true (IE)
640 e.cancelBubble = true;
642 stopImmediatePropagation: function() {
643 this.isImmediatePropagationStopped = returnTrue;
644 this.stopPropagation();
646 isDefaultPrevented: returnFalse,
647 isPropagationStopped: returnFalse,
648 isImmediatePropagationStopped: returnFalse
651 // Checks if an event happened on an element within another element
652 // Used in jQuery.event.special.mouseenter and mouseleave handlers
653 var withinElement = function( event ) {
654 // Check if mouse(over|out) are still within the same parent element
655 var parent = event.relatedTarget;
657 // Firefox sometimes assigns relatedTarget a XUL element
658 // which we cannot access the parentNode property of
660 // Traverse up the tree
661 while ( parent && parent !== this ) {
662 parent = parent.parentNode;
665 if ( parent !== this ) {
666 // set the correct event type
667 event.type = event.data;
669 // handle event if we actually just moused on to a non sub-element
670 jQuery.event.handle.apply( this, arguments );
673 // assuming we've left the element since we most likely mousedover a xul element
677 // In case of event delegation, we only need to rename the event.type,
678 // liveHandler will take care of the rest.
679 delegate = function( event ) {
680 event.type = event.data;
681 jQuery.event.handle.apply( this, arguments );
684 // Create mouseenter and mouseleave events
686 mouseenter: "mouseover",
687 mouseleave: "mouseout"
688 }, function( orig, fix ) {
689 jQuery.event.special[ orig ] = {
690 setup: function( data ) {
691 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
693 teardown: function( data ) {
694 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
700 if ( !jQuery.support.submitBubbles ) {
702 jQuery.event.special.submit = {
703 setup: function( data, namespaces ) {
704 if ( this.nodeName.toLowerCase() !== "form" ) {
705 jQuery.event.add(this, "click.specialSubmit", function( e ) {
706 var elem = e.target, type = elem.type;
708 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
709 e.liveFired = undefined;
710 return trigger( "submit", this, arguments );
714 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
715 var elem = e.target, type = elem.type;
717 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
718 e.liveFired = undefined;
719 return trigger( "submit", this, arguments );
728 teardown: function( namespaces ) {
729 jQuery.event.remove( this, ".specialSubmit" );
735 // change delegation, happens here so we have bind.
736 if ( !jQuery.support.changeBubbles ) {
740 getVal = function( elem ) {
741 var type = elem.type, val = elem.value;
743 if ( type === "radio" || type === "checkbox" ) {
746 } else if ( type === "select-multiple" ) {
747 val = elem.selectedIndex > -1 ?
748 jQuery.map( elem.options, function( elem ) {
749 return elem.selected;
753 } else if ( elem.nodeName.toLowerCase() === "select" ) {
754 val = elem.selectedIndex;
760 testChange = function testChange( e ) {
761 var elem = e.target, data, val;
763 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
767 data = jQuery.data( elem, "_change_data" );
770 // the current data will be also retrieved by beforeactivate
771 if ( e.type !== "focusout" || elem.type !== "radio" ) {
772 jQuery.data( elem, "_change_data", val );
775 if ( data === undefined || val === data ) {
779 if ( data != null || val ) {
781 return jQuery.event.trigger( e, arguments[1], elem );
785 jQuery.event.special.change = {
787 focusout: testChange,
789 click: function( e ) {
790 var elem = e.target, type = elem.type;
792 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
793 return testChange.call( this, e );
797 // Change has to be called before submit
798 // Keydown will be called before keypress, which is used in submit-event delegation
799 keydown: function( e ) {
800 var elem = e.target, type = elem.type;
802 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
803 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
804 type === "select-multiple" ) {
805 return testChange.call( this, e );
809 // Beforeactivate happens also before the previous element is blurred
810 // with this event you can't trigger a change event, but you can store
811 // information/focus[in] is not needed anymore
812 beforeactivate: function( e ) {
814 jQuery.data( elem, "_change_data", getVal(elem) );
818 setup: function( data, namespaces ) {
819 if ( this.type === "file" ) {
823 for ( var type in changeFilters ) {
824 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
827 return rformElems.test( this.nodeName );
830 teardown: function( namespaces ) {
831 jQuery.event.remove( this, ".specialChange" );
833 return rformElems.test( this.nodeName );
837 changeFilters = jQuery.event.special.change.filters;
840 function trigger( type, elem, args ) {
842 return jQuery.event.handle.apply( elem, args );
845 // Create "bubbling" focus and blur events
846 if ( document.addEventListener ) {
847 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
848 jQuery.event.special[ fix ] = {
850 this.addEventListener( orig, handler, true );
852 teardown: function() {
853 this.removeEventListener( orig, handler, true );
857 function handler( e ) {
858 e = jQuery.event.fix( e );
860 return jQuery.event.handle.call( this, e );
865 jQuery.each(["bind", "one"], function( i, name ) {
866 jQuery.fn[ name ] = function( type, data, fn ) {
867 // Handle object literals
868 if ( typeof type === "object" ) {
869 for ( var key in type ) {
870 this[ name ](key, data, type[key], fn);
875 if ( jQuery.isFunction( data ) || data === false ) {
880 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
881 jQuery( this ).unbind( event, handler );
882 return fn.apply( this, arguments );
885 if ( type === "unload" && name !== "one" ) {
886 this.one( type, data, fn );
889 for ( var i = 0, l = this.length; i < l; i++ ) {
890 jQuery.event.add( this[i], type, handler, data );
899 unbind: function( type, fn ) {
900 // Handle object literals
901 if ( typeof type === "object" && !type.preventDefault ) {
902 for ( var key in type ) {
903 this.unbind(key, type[key]);
907 for ( var i = 0, l = this.length; i < l; i++ ) {
908 jQuery.event.remove( this[i], type, fn );
915 delegate: function( selector, types, data, fn ) {
916 return this.live( types, data, fn, selector );
919 undelegate: function( selector, types, fn ) {
920 if ( arguments.length === 0 ) {
921 return this.unbind( "live" );
924 return this.die( types, null, fn, selector );
928 trigger: function( type, data ) {
929 return this.each(function() {
930 jQuery.event.trigger( type, data, this );
934 triggerHandler: function( type, data ) {
936 var event = jQuery.Event( type );
937 event.preventDefault();
938 event.stopPropagation();
939 jQuery.event.trigger( event, data, this[0] );
944 toggle: function( fn ) {
945 // Save reference to arguments for access in closure
946 var args = arguments, i = 1;
948 // link all the functions, so any of them can unbind this click handler
949 while ( i < args.length ) {
950 jQuery.proxy( fn, args[ i++ ] );
953 return this.click( jQuery.proxy( fn, function( event ) {
954 // Figure out which function to execute
955 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
956 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
958 // Make sure that clicks stop
959 event.preventDefault();
961 // and execute the function
962 return args[ lastToggle ].apply( this, arguments ) || false;
966 hover: function( fnOver, fnOut ) {
967 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
974 mouseenter: "mouseover",
975 mouseleave: "mouseout"
978 jQuery.each(["live", "die"], function( i, name ) {
979 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
980 var type, i = 0, match, namespaces, preType,
981 selector = origSelector || this.selector,
982 context = origSelector ? this : jQuery( this.context );
984 if ( typeof types === "object" && !types.preventDefault ) {
985 for ( var key in types ) {
986 context[ name ]( key, data, types[key], selector );
992 if ( jQuery.isFunction( data ) ) {
997 types = (types || "").split(" ");
999 while ( (type = types[ i++ ]) != null ) {
1000 match = rnamespaces.exec( type );
1004 namespaces = match[0];
1005 type = type.replace( rnamespaces, "" );
1008 if ( type === "hover" ) {
1009 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1015 if ( type === "focus" || type === "blur" ) {
1016 types.push( liveMap[ type ] + namespaces );
1017 type = type + namespaces;
1020 type = (liveMap[ type ] || type) + namespaces;
1023 if ( name === "live" ) {
1024 // bind live handler
1025 for ( var j = 0, l = context.length; j < l; j++ ) {
1026 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1027 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1031 // unbind live handler
1032 context.unbind( "live." + liveConvert( type, selector ), fn );
1040 function liveHandler( event ) {
1041 var stop, maxLevel, elems = [], selectors = [],
1042 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1043 events = jQuery.data( this, "events" );
1045 if ( typeof events === "function" ) {
1046 events = events.events;
1049 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1050 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1054 if ( event.namespace ) {
1055 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1058 event.liveFired = this;
1060 var live = events.live.slice(0);
1062 for ( j = 0; j < live.length; j++ ) {
1063 handleObj = live[j];
1065 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1066 selectors.push( handleObj.selector );
1069 live.splice( j--, 1 );
1073 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1075 for ( i = 0, l = match.length; i < l; i++ ) {
1078 for ( j = 0; j < live.length; j++ ) {
1079 handleObj = live[j];
1081 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1085 // Those two events require additional checking
1086 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1087 event.type = handleObj.preType;
1088 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1091 if ( !related || related !== elem ) {
1092 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1098 for ( i = 0, l = elems.length; i < l; i++ ) {
1101 if ( maxLevel && match.level > maxLevel ) {
1105 event.currentTarget = match.elem;
1106 event.data = match.handleObj.data;
1107 event.handleObj = match.handleObj;
1109 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1111 if ( ret === false || event.isPropagationStopped() ) {
1112 maxLevel = match.level;
1114 if ( ret === false ) {
1123 function liveConvert( type, selector ) {
1124 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1127 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1128 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1129 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1131 // Handle event binding
1132 jQuery.fn[ name ] = function( data, fn ) {
1138 return arguments.length > 0 ?
1139 this.bind( name, data, fn ) :
1140 this.trigger( name );
1143 if ( jQuery.attrFn ) {
1144 jQuery.attrFn[ name ] = true;
1148 // Prevent memory leaks in IE
1149 // Window isn't included so as not to unbind existing unload events
1151 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1152 if ( window.attachEvent && !window.addEventListener ) {
1153 window.attachEvent("onunload", function() {
1154 for ( var id in jQuery.cache ) {
1155 if ( jQuery.cache[ id ].handle ) {
1156 // Try/Catch is to handle iframes being unloaded, see #4280
1158 jQuery.event.remove( jQuery.cache[ id ].handle.elem );