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 return trigger( "submit", this, arguments );
713 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
714 var elem = e.target, type = elem.type;
716 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
717 return trigger( "submit", this, arguments );
726 teardown: function( namespaces ) {
727 jQuery.event.remove( this, ".specialSubmit" );
733 // change delegation, happens here so we have bind.
734 if ( !jQuery.support.changeBubbles ) {
738 getVal = function( elem ) {
739 var type = elem.type, val = elem.value;
741 if ( type === "radio" || type === "checkbox" ) {
744 } else if ( type === "select-multiple" ) {
745 val = elem.selectedIndex > -1 ?
746 jQuery.map( elem.options, function( elem ) {
747 return elem.selected;
751 } else if ( elem.nodeName.toLowerCase() === "select" ) {
752 val = elem.selectedIndex;
758 testChange = function testChange( e ) {
759 var elem = e.target, data, val;
761 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
765 data = jQuery.data( elem, "_change_data" );
768 // the current data will be also retrieved by beforeactivate
769 if ( e.type !== "focusout" || elem.type !== "radio" ) {
770 jQuery.data( elem, "_change_data", val );
773 if ( data === undefined || val === data ) {
777 if ( data != null || val ) {
779 return jQuery.event.trigger( e, arguments[1], elem );
783 jQuery.event.special.change = {
785 focusout: testChange,
787 click: function( e ) {
788 var elem = e.target, type = elem.type;
790 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
791 return testChange.call( this, e );
795 // Change has to be called before submit
796 // Keydown will be called before keypress, which is used in submit-event delegation
797 keydown: function( e ) {
798 var elem = e.target, type = elem.type;
800 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
801 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
802 type === "select-multiple" ) {
803 return testChange.call( this, e );
807 // Beforeactivate happens also before the previous element is blurred
808 // with this event you can't trigger a change event, but you can store
809 // information/focus[in] is not needed anymore
810 beforeactivate: function( e ) {
812 jQuery.data( elem, "_change_data", getVal(elem) );
816 setup: function( data, namespaces ) {
817 if ( this.type === "file" ) {
821 for ( var type in changeFilters ) {
822 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
825 return rformElems.test( this.nodeName );
828 teardown: function( namespaces ) {
829 jQuery.event.remove( this, ".specialChange" );
831 return rformElems.test( this.nodeName );
835 changeFilters = jQuery.event.special.change.filters;
838 function trigger( type, elem, args ) {
840 return jQuery.event.handle.apply( elem, args );
843 // Create "bubbling" focus and blur events
844 if ( document.addEventListener ) {
845 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
846 jQuery.event.special[ fix ] = {
848 this.addEventListener( orig, handler, true );
850 teardown: function() {
851 this.removeEventListener( orig, handler, true );
855 function handler( e ) {
856 e = jQuery.event.fix( e );
858 return jQuery.event.handle.call( this, e );
863 jQuery.each(["bind", "one"], function( i, name ) {
864 jQuery.fn[ name ] = function( type, data, fn ) {
865 // Handle object literals
866 if ( typeof type === "object" ) {
867 for ( var key in type ) {
868 this[ name ](key, data, type[key], fn);
873 if ( jQuery.isFunction( data ) || data === false ) {
878 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
879 jQuery( this ).unbind( event, handler );
880 return fn.apply( this, arguments );
883 if ( type === "unload" && name !== "one" ) {
884 this.one( type, data, fn );
887 for ( var i = 0, l = this.length; i < l; i++ ) {
888 jQuery.event.add( this[i], type, handler, data );
897 unbind: function( type, fn ) {
898 // Handle object literals
899 if ( typeof type === "object" && !type.preventDefault ) {
900 for ( var key in type ) {
901 this.unbind(key, type[key]);
905 for ( var i = 0, l = this.length; i < l; i++ ) {
906 jQuery.event.remove( this[i], type, fn );
913 delegate: function( selector, types, data, fn ) {
914 return this.live( types, data, fn, selector );
917 undelegate: function( selector, types, fn ) {
918 if ( arguments.length === 0 ) {
919 return this.unbind( "live" );
922 return this.die( types, null, fn, selector );
926 trigger: function( type, data ) {
927 return this.each(function() {
928 jQuery.event.trigger( type, data, this );
932 triggerHandler: function( type, data ) {
934 var event = jQuery.Event( type );
935 event.preventDefault();
936 event.stopPropagation();
937 jQuery.event.trigger( event, data, this[0] );
942 toggle: function( fn ) {
943 // Save reference to arguments for access in closure
944 var args = arguments, i = 1;
946 // link all the functions, so any of them can unbind this click handler
947 while ( i < args.length ) {
948 jQuery.proxy( fn, args[ i++ ] );
951 return this.click( jQuery.proxy( fn, function( event ) {
952 // Figure out which function to execute
953 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
954 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
956 // Make sure that clicks stop
957 event.preventDefault();
959 // and execute the function
960 return args[ lastToggle ].apply( this, arguments ) || false;
964 hover: function( fnOver, fnOut ) {
965 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
972 mouseenter: "mouseover",
973 mouseleave: "mouseout"
976 jQuery.each(["live", "die"], function( i, name ) {
977 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
978 var type, i = 0, match, namespaces, preType,
979 selector = origSelector || this.selector,
980 context = origSelector ? this : jQuery( this.context );
982 if ( typeof types === "object" && !types.preventDefault ) {
983 for ( var key in types ) {
984 context[ name ]( key, data, types[key], selector );
990 if ( jQuery.isFunction( data ) ) {
995 types = (types || "").split(" ");
997 while ( (type = types[ i++ ]) != null ) {
998 match = rnamespaces.exec( type );
1002 namespaces = match[0];
1003 type = type.replace( rnamespaces, "" );
1006 if ( type === "hover" ) {
1007 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1013 if ( type === "focus" || type === "blur" ) {
1014 types.push( liveMap[ type ] + namespaces );
1015 type = type + namespaces;
1018 type = (liveMap[ type ] || type) + namespaces;
1021 if ( name === "live" ) {
1022 // bind live handler
1023 for ( var j = 0, l = context.length; j < l; j++ ) {
1024 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1025 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1029 // unbind live handler
1030 context.unbind( "live." + liveConvert( type, selector ), fn );
1038 function liveHandler( event ) {
1039 var stop, maxLevel, elems = [], selectors = [],
1040 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1041 events = jQuery.data( this, "events" );
1043 if ( typeof events === "function" ) {
1044 events = events.events;
1047 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1048 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1052 if ( event.namespace ) {
1053 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1056 event.liveFired = this;
1058 var live = events.live.slice(0);
1060 for ( j = 0; j < live.length; j++ ) {
1061 handleObj = live[j];
1063 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1064 selectors.push( handleObj.selector );
1067 live.splice( j--, 1 );
1071 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1073 for ( i = 0, l = match.length; i < l; i++ ) {
1076 for ( j = 0; j < live.length; j++ ) {
1077 handleObj = live[j];
1079 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1083 // Those two events require additional checking
1084 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1085 event.type = handleObj.preType;
1086 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1089 if ( !related || related !== elem ) {
1090 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1096 for ( i = 0, l = elems.length; i < l; i++ ) {
1099 if ( maxLevel && match.level > maxLevel ) {
1103 event.currentTarget = match.elem;
1104 event.data = match.handleObj.data;
1105 event.handleObj = match.handleObj;
1107 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1109 if ( ret === false || event.isPropagationStopped() ) {
1110 maxLevel = match.level;
1112 if ( ret === false ) {
1121 function liveConvert( type, selector ) {
1122 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1125 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1126 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1127 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1129 // Handle event binding
1130 jQuery.fn[ name ] = function( data, fn ) {
1136 return arguments.length > 0 ?
1137 this.bind( name, data, fn ) :
1138 this.trigger( name );
1141 if ( jQuery.attrFn ) {
1142 jQuery.attrFn[ name ] = true;
1146 // Prevent memory leaks in IE
1147 // Window isn't included so as not to unbind existing unload events
1149 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1150 if ( window.attachEvent && !window.addEventListener ) {
1151 window.attachEvent("onunload", function() {
1152 for ( var id in jQuery.cache ) {
1153 if ( jQuery.cache[ id ].handle ) {
1154 // Try/Catch is to handle iframes being unloaded, see #4280
1156 jQuery.event.remove( jQuery.cache[ id ].handle.elem );