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 // Use a key less likely to result in collisions for plain JS objects.
59 var eventKey = elem.nodeType ? "events" : "__events__",
60 events = elemData[ eventKey ],
61 eventHandle = elemData.handle;
63 if ( typeof events === "function" ) {
64 // On plain objects events is a fn that holds the the data
65 // which prevents this data from being JSON serialized
66 // the function does not need to be called, it just contains the data
67 eventHandle = events.handle;
68 events = events.events;
70 } else if ( !events ) {
71 if ( !elem.nodeType ) {
72 // On plain objects, create a fn that acts as the holder
73 // of the values to avoid JSON serialization of event data
74 elemData[ eventKey ] = elemData = function(){};
77 elemData.events = events = {};
81 elemData.handle = eventHandle = function() {
82 // Handle the second event of a trigger and when
83 // an event is called after a page has unloaded
84 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
85 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
90 // Add elem as a property of the handle function
91 // This is to prevent a memory leak with non-native events in IE.
92 eventHandle.elem = elem;
94 // Handle multiple events separated by a space
95 // jQuery(...).bind("mouseover mouseout", fn);
96 types = types.split(" ");
98 var type, i = 0, namespaces;
100 while ( (type = types[ i++ ]) ) {
101 handleObj = handleObjIn ?
102 jQuery.extend({}, handleObjIn) :
103 { handler: handler, data: data };
105 // Namespaced event handlers
106 if ( type.indexOf(".") > -1 ) {
107 namespaces = type.split(".");
108 type = namespaces.shift();
109 handleObj.namespace = namespaces.slice(0).sort().join(".");
113 handleObj.namespace = "";
116 handleObj.type = type;
117 if ( !handleObj.guid ) {
118 handleObj.guid = handler.guid;
121 // Get the current list of functions bound to this event
122 var handlers = events[ type ],
123 special = jQuery.event.special[ type ] || {};
125 // Init the event handler queue
127 handlers = events[ type ] = [];
129 // Check for a special event handler
130 // Only use addEventListener/attachEvent if the special
131 // events handler returns false
132 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
133 // Bind the global event handler to the element
134 if ( elem.addEventListener ) {
135 elem.addEventListener( type, eventHandle, false );
137 } else if ( elem.attachEvent ) {
138 elem.attachEvent( "on" + type, eventHandle );
144 special.add.call( elem, handleObj );
146 if ( !handleObj.handler.guid ) {
147 handleObj.handler.guid = handler.guid;
151 // Add the function to the element's handler list
152 handlers.push( handleObj );
154 // Keep track of which events have been used, for global triggering
155 jQuery.event.global[ type ] = true;
158 // Nullify elem to prevent memory leaks in IE
164 // Detach an event or set of events from an element
165 remove: function( elem, types, handler, pos ) {
166 // don't do events on text and comment nodes
167 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
171 if ( handler === false ) {
172 handler = returnFalse;
175 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
176 eventKey = elem.nodeType ? "events" : "__events__",
177 elemData = 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[ eventKey ];
286 delete elemData.handle;
288 if ( typeof elemData === "function" ) {
289 jQuery.removeData( elem, "events" );
291 } else if ( jQuery.isEmptyObject( elemData ) ) {
292 jQuery.removeData( elem );
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 jQuery.each( jQuery.cache, function() {
325 if ( this.events && this.events[type] ) {
326 jQuery.event.trigger( event, data, this.handle.elem );
332 // Handle triggering a single element
334 // don't do events on text and comment nodes
335 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
339 // Clean up in case it is reused
340 event.result = undefined;
343 // Clone the incoming data, if any
344 data = jQuery.makeArray( data );
345 data.unshift( event );
348 event.currentTarget = elem;
350 // Trigger the event, it is assumed that "handle" is a function
351 var handle = elem.nodeType ?
352 jQuery.data( elem, "handle" ) :
353 (jQuery.data( elem, "__events__" ) || {}).handle;
356 handle.apply( elem, data );
359 var parent = elem.parentNode || elem.ownerDocument;
361 // Trigger an inline bound script
363 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
364 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
365 event.result = false;
366 event.preventDefault();
370 // prevent IE from throwing an error for some elements with some event types, see #3533
371 } catch (inlineError) {}
373 if ( !event.isPropagationStopped() && parent ) {
374 jQuery.event.trigger( event, data, parent, true );
376 } else if ( !event.isDefaultPrevented() ) {
377 var target = event.target, old, targetType = type.replace(rnamespaces, ""),
378 isClick = jQuery.nodeName(target, "a") && targetType === "click",
379 special = jQuery.event.special[ targetType ] || {};
381 if ( (!special._default || special._default.call( elem, event ) === false) &&
382 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
385 if ( target[ targetType ] ) {
386 // Make sure that we don't accidentally re-trigger the onFOO events
387 old = target[ "on" + targetType ];
390 target[ "on" + targetType ] = null;
393 jQuery.event.triggered = true;
394 target[ targetType ]();
397 // prevent IE from throwing an error for some elements with some event types, see #3533
398 } catch (triggerError) {}
401 target[ "on" + targetType ] = old;
404 jQuery.event.triggered = false;
409 handle: function( event ) {
410 var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
412 event = args[0] = jQuery.event.fix( event || window.event );
413 event.currentTarget = this;
415 // Namespaced event handlers
416 all = event.type.indexOf(".") < 0 && !event.exclusive;
419 namespaces = event.type.split(".");
420 event.type = namespaces.shift();
421 namespace_sort = namespaces.slice(0).sort();
422 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
425 event.namespace = event.namespace || namespace_sort.join(".");
427 events = jQuery.data(this, this.nodeType ? "events" : "__events__");
429 if ( typeof events === "function" ) {
430 events = events.events;
433 handlers = (events || {})[ event.type ];
435 if ( events && handlers ) {
436 // Clone the handlers to prevent manipulation
437 handlers = handlers.slice(0);
439 for ( var j = 0, l = handlers.length; j < l; j++ ) {
440 var handleObj = handlers[ j ];
442 // Filter the functions by class
443 if ( all || namespace_re.test( handleObj.namespace ) ) {
444 // Pass in a reference to the handler function itself
445 // So that we can later remove it
446 event.handler = handleObj.handler;
447 event.data = handleObj.data;
448 event.handleObj = handleObj;
450 var ret = handleObj.handler.apply( this, args );
452 if ( ret !== undefined ) {
454 if ( ret === false ) {
455 event.preventDefault();
456 event.stopPropagation();
460 if ( event.isImmediatePropagationStopped() ) {
470 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(" "),
472 fix: function( event ) {
473 if ( event[ jQuery.expando ] ) {
477 // store a copy of the original event object
478 // and "clone" to set read-only properties
479 var originalEvent = event;
480 event = jQuery.Event( originalEvent );
482 for ( var i = this.props.length, prop; i; ) {
483 prop = this.props[ --i ];
484 event[ prop ] = originalEvent[ prop ];
487 // Fix target property, if necessary
488 if ( !event.target ) {
489 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
492 // check if target is a textnode (safari)
493 if ( event.target.nodeType === 3 ) {
494 event.target = event.target.parentNode;
497 // Add relatedTarget, if necessary
498 if ( !event.relatedTarget && event.fromElement ) {
499 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
502 // Calculate pageX/Y if missing and clientX/Y available
503 if ( event.pageX == null && event.clientX != null ) {
504 var doc = document.documentElement, body = document.body;
505 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
506 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
509 // Add which for key events
510 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
511 event.which = event.charCode != null ? event.charCode : event.keyCode;
514 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
515 if ( !event.metaKey && event.ctrlKey ) {
516 event.metaKey = event.ctrlKey;
519 // Add which for click: 1 === left; 2 === middle; 3 === right
520 // Note: button is not normalized, so don't use it
521 if ( !event.which && event.button !== undefined ) {
522 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
528 // Deprecated, use jQuery.guid instead
531 // Deprecated, use jQuery.proxy instead
536 // Make sure the ready event is setup
537 setup: jQuery.bindReady,
538 teardown: jQuery.noop
542 add: function( handleObj ) {
543 jQuery.event.add( this,
544 liveConvert( handleObj.origType, handleObj.selector ),
545 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
548 remove: function( handleObj ) {
549 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
554 setup: function( data, namespaces, eventHandle ) {
555 // We only want to do this special case on windows
556 if ( jQuery.isWindow( this ) ) {
557 this.onbeforeunload = eventHandle;
561 teardown: function( namespaces, eventHandle ) {
562 if ( this.onbeforeunload === eventHandle ) {
563 this.onbeforeunload = null;
570 jQuery.removeEvent = document.removeEventListener ?
571 function( elem, type, handle ) {
572 if ( elem.removeEventListener ) {
573 elem.removeEventListener( type, handle, false );
576 function( elem, type, handle ) {
577 if ( elem.detachEvent ) {
578 elem.detachEvent( "on" + type, handle );
582 jQuery.Event = function( src ) {
583 // Allow instantiation without the 'new' keyword
584 if ( !this.preventDefault ) {
585 return new jQuery.Event( src );
589 if ( src && src.type ) {
590 this.originalEvent = src;
591 this.type = src.type;
597 // timeStamp is buggy for some events on Firefox(#3843)
598 // So we won't rely on the native value
599 this.timeStamp = jQuery.now();
602 this[ jQuery.expando ] = true;
605 function returnFalse() {
608 function returnTrue() {
612 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
613 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
614 jQuery.Event.prototype = {
615 preventDefault: function() {
616 this.isDefaultPrevented = returnTrue;
618 var e = this.originalEvent;
623 // if preventDefault exists run it on the original event
624 if ( e.preventDefault ) {
627 // otherwise set the returnValue property of the original event to false (IE)
629 e.returnValue = false;
632 stopPropagation: function() {
633 this.isPropagationStopped = returnTrue;
635 var e = this.originalEvent;
639 // if stopPropagation exists run it on the original event
640 if ( e.stopPropagation ) {
643 // otherwise set the cancelBubble property of the original event to true (IE)
644 e.cancelBubble = true;
646 stopImmediatePropagation: function() {
647 this.isImmediatePropagationStopped = returnTrue;
648 this.stopPropagation();
650 isDefaultPrevented: returnFalse,
651 isPropagationStopped: returnFalse,
652 isImmediatePropagationStopped: returnFalse
655 // Checks if an event happened on an element within another element
656 // Used in jQuery.event.special.mouseenter and mouseleave handlers
657 var withinElement = function( event ) {
658 // Check if mouse(over|out) are still within the same parent element
659 var parent = event.relatedTarget;
661 // Firefox sometimes assigns relatedTarget a XUL element
662 // which we cannot access the parentNode property of
664 // Traverse up the tree
665 while ( parent && parent !== this ) {
666 parent = parent.parentNode;
669 if ( parent !== this ) {
670 // set the correct event type
671 event.type = event.data;
673 // handle event if we actually just moused on to a non sub-element
674 jQuery.event.handle.apply( this, arguments );
677 // assuming we've left the element since we most likely mousedover a xul element
681 // In case of event delegation, we only need to rename the event.type,
682 // liveHandler will take care of the rest.
683 delegate = function( event ) {
684 event.type = event.data;
685 jQuery.event.handle.apply( this, arguments );
688 // Create mouseenter and mouseleave events
690 mouseenter: "mouseover",
691 mouseleave: "mouseout"
692 }, function( orig, fix ) {
693 jQuery.event.special[ orig ] = {
694 setup: function( data ) {
695 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
697 teardown: function( data ) {
698 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
704 if ( !jQuery.support.submitBubbles ) {
706 jQuery.event.special.submit = {
707 setup: function( data, namespaces ) {
708 if ( this.nodeName.toLowerCase() !== "form" ) {
709 jQuery.event.add(this, "click.specialSubmit", function( e ) {
710 var elem = e.target, type = elem.type;
712 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
713 e.liveFired = undefined;
714 return trigger( "submit", this, arguments );
718 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
719 var elem = e.target, type = elem.type;
721 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
722 e.liveFired = undefined;
723 return trigger( "submit", this, arguments );
732 teardown: function( namespaces ) {
733 jQuery.event.remove( this, ".specialSubmit" );
739 // change delegation, happens here so we have bind.
740 if ( !jQuery.support.changeBubbles ) {
744 getVal = function( elem ) {
745 var type = elem.type, val = elem.value;
747 if ( type === "radio" || type === "checkbox" ) {
750 } else if ( type === "select-multiple" ) {
751 val = elem.selectedIndex > -1 ?
752 jQuery.map( elem.options, function( elem ) {
753 return elem.selected;
757 } else if ( elem.nodeName.toLowerCase() === "select" ) {
758 val = elem.selectedIndex;
764 testChange = function testChange( e ) {
765 var elem = e.target, data, val;
767 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
771 data = jQuery.data( elem, "_change_data" );
774 // the current data will be also retrieved by beforeactivate
775 if ( e.type !== "focusout" || elem.type !== "radio" ) {
776 jQuery.data( elem, "_change_data", val );
779 if ( data === undefined || val === data ) {
783 if ( data != null || val ) {
785 e.liveFired = undefined;
786 return jQuery.event.trigger( e, arguments[1], elem );
790 jQuery.event.special.change = {
792 focusout: testChange,
794 click: function( e ) {
795 var elem = e.target, type = elem.type;
797 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
798 return testChange.call( this, e );
802 // Change has to be called before submit
803 // Keydown will be called before keypress, which is used in submit-event delegation
804 keydown: function( e ) {
805 var elem = e.target, type = elem.type;
807 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
808 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
809 type === "select-multiple" ) {
810 return testChange.call( this, e );
814 // Beforeactivate happens also before the previous element is blurred
815 // with this event you can't trigger a change event, but you can store
817 beforeactivate: function( e ) {
819 jQuery.data( elem, "_change_data", getVal(elem) );
823 setup: function( data, namespaces ) {
824 if ( this.type === "file" ) {
828 for ( var type in changeFilters ) {
829 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
832 return rformElems.test( this.nodeName );
835 teardown: function( namespaces ) {
836 jQuery.event.remove( this, ".specialChange" );
838 return rformElems.test( this.nodeName );
842 changeFilters = jQuery.event.special.change.filters;
844 // Handle when the input is .focus()'d
845 changeFilters.focus = changeFilters.beforeactivate;
848 function trigger( type, elem, args ) {
850 return jQuery.event.handle.apply( elem, args );
853 // Create "bubbling" focus and blur events
854 if ( document.addEventListener ) {
855 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
856 jQuery.event.special[ fix ] = {
858 this.addEventListener( orig, handler, true );
860 teardown: function() {
861 this.removeEventListener( orig, handler, true );
865 function handler( e ) {
866 e = jQuery.event.fix( e );
868 return jQuery.event.handle.call( this, e );
873 jQuery.each(["bind", "one"], function( i, name ) {
874 jQuery.fn[ name ] = function( type, data, fn ) {
875 // Handle object literals
876 if ( typeof type === "object" ) {
877 for ( var key in type ) {
878 this[ name ](key, data, type[key], fn);
883 if ( jQuery.isFunction( data ) || data === false ) {
888 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
889 jQuery( this ).unbind( event, handler );
890 return fn.apply( this, arguments );
893 if ( type === "unload" && name !== "one" ) {
894 this.one( type, data, fn );
897 for ( var i = 0, l = this.length; i < l; i++ ) {
898 jQuery.event.add( this[i], type, handler, data );
907 unbind: function( type, fn ) {
908 // Handle object literals
909 if ( typeof type === "object" && !type.preventDefault ) {
910 for ( var key in type ) {
911 this.unbind(key, type[key]);
915 for ( var i = 0, l = this.length; i < l; i++ ) {
916 jQuery.event.remove( this[i], type, fn );
923 delegate: function( selector, types, data, fn ) {
924 return this.live( types, data, fn, selector );
927 undelegate: function( selector, types, fn ) {
928 if ( arguments.length === 0 ) {
929 return this.unbind( "live" );
932 return this.die( types, null, fn, selector );
936 trigger: function( type, data ) {
937 return this.each(function() {
938 jQuery.event.trigger( type, data, this );
942 triggerHandler: function( type, data ) {
944 var event = jQuery.Event( type );
945 event.preventDefault();
946 event.stopPropagation();
947 jQuery.event.trigger( event, data, this[0] );
952 toggle: function( fn ) {
953 // Save reference to arguments for access in closure
954 var args = arguments, i = 1;
956 // link all the functions, so any of them can unbind this click handler
957 while ( i < args.length ) {
958 jQuery.proxy( fn, args[ i++ ] );
961 return this.click( jQuery.proxy( fn, function( event ) {
962 // Figure out which function to execute
963 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
964 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
966 // Make sure that clicks stop
967 event.preventDefault();
969 // and execute the function
970 return args[ lastToggle ].apply( this, arguments ) || false;
974 hover: function( fnOver, fnOut ) {
975 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
982 mouseenter: "mouseover",
983 mouseleave: "mouseout"
986 jQuery.each(["live", "die"], function( i, name ) {
987 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
988 var type, i = 0, match, namespaces, preType,
989 selector = origSelector || this.selector,
990 context = origSelector ? this : jQuery( this.context );
992 if ( typeof types === "object" && !types.preventDefault ) {
993 for ( var key in types ) {
994 context[ name ]( key, data, types[key], selector );
1000 if ( jQuery.isFunction( data ) ) {
1005 types = (types || "").split(" ");
1007 while ( (type = types[ i++ ]) != null ) {
1008 match = rnamespaces.exec( type );
1012 namespaces = match[0];
1013 type = type.replace( rnamespaces, "" );
1016 if ( type === "hover" ) {
1017 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1023 if ( type === "focus" || type === "blur" ) {
1024 types.push( liveMap[ type ] + namespaces );
1025 type = type + namespaces;
1028 type = (liveMap[ type ] || type) + namespaces;
1031 if ( name === "live" ) {
1032 // bind live handler
1033 for ( var j = 0, l = context.length; j < l; j++ ) {
1034 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1035 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1039 // unbind live handler
1040 context.unbind( "live." + liveConvert( type, selector ), fn );
1048 function liveHandler( event ) {
1049 var stop, maxLevel, elems = [], selectors = [],
1050 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1051 events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
1053 if ( typeof events === "function" ) {
1054 events = events.events;
1057 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1058 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1062 if ( event.namespace ) {
1063 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1066 event.liveFired = this;
1068 var live = events.live.slice(0);
1070 for ( j = 0; j < live.length; j++ ) {
1071 handleObj = live[j];
1073 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1074 selectors.push( handleObj.selector );
1077 live.splice( j--, 1 );
1081 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1083 for ( i = 0, l = match.length; i < l; i++ ) {
1086 for ( j = 0; j < live.length; j++ ) {
1087 handleObj = live[j];
1089 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1093 // Those two events require additional checking
1094 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1095 event.type = handleObj.preType;
1096 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1099 if ( !related || related !== elem ) {
1100 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1106 for ( i = 0, l = elems.length; i < l; i++ ) {
1109 if ( maxLevel && match.level > maxLevel ) {
1113 event.currentTarget = match.elem;
1114 event.data = match.handleObj.data;
1115 event.handleObj = match.handleObj;
1117 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1119 if ( ret === false || event.isPropagationStopped() ) {
1120 maxLevel = match.level;
1122 if ( ret === false ) {
1131 function liveConvert( type, selector ) {
1132 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1135 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1136 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1137 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1139 // Handle event binding
1140 jQuery.fn[ name ] = function( data, fn ) {
1146 return arguments.length > 0 ?
1147 this.bind( name, data, fn ) :
1148 this.trigger( name );
1151 if ( jQuery.attrFn ) {
1152 jQuery.attrFn[ name ] = true;
1156 // Prevent memory leaks in IE
1157 // Window isn't included so as not to unbind existing unload events
1159 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1160 if ( window.attachEvent && !window.addEventListener ) {
1161 jQuery(window).bind("unload", function() {
1162 for ( var id in jQuery.cache ) {
1163 if ( jQuery.cache[ id ].handle ) {
1164 // Try/Catch is to handle iframes being unloaded, see #4280
1166 jQuery.event.remove( jQuery.cache[ id ].handle.elem );