3 var hasOwn = Object.prototype.hasOwnProperty,
4 rnamespaces = /\.(.*)$/,
5 rformElems = /^(?:textarea|input|select)$/i,
8 rescape = /[^\w\s.|`]/g,
9 fcleanup = function( nm ) {
10 return nm.replace(rescape, "\\$&");
14 * A number of helper functions used for managing events.
15 * Many of the ideas behind this code originated from
16 * Dean Edwards' addEvent library.
20 // Bind an event to an element
21 // Original by Dean Edwards
22 add: function( elem, types, handler, data ) {
23 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
27 // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6)
28 // Minor release fix for bug #8018
30 // For whatever reason, IE has trouble passing the window object
31 // around, causing it to be cloned in the process
32 if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
38 if ( handler === false ) {
39 handler = returnFalse;
40 } else if ( !handler ) {
41 // Fixes bug #7229. Fix recommended by jdalton
45 var handleObjIn, handleObj;
47 if ( handler.handler ) {
48 handleObjIn = handler;
49 handler = handleObjIn.handler;
52 // Make sure that the function being executed has a unique ID
53 if ( !handler.guid ) {
54 handler.guid = jQuery.guid++;
57 // Init the element's event structure
58 var elemData = jQuery._data( elem );
60 // If no elemData is found then we must be trying to bind to one of the
61 // banned noData elements
66 var events = elemData.events,
67 eventHandle = elemData.handle;
70 elemData.events = events = {};
74 elemData.handle = eventHandle = function( e ) {
75 // Discard the second event of a jQuery.event.trigger() and
76 // when an event is called after a page has unloaded
77 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
78 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
83 // Add elem as a property of the handle function
84 // This is to prevent a memory leak with non-native events in IE.
85 eventHandle.elem = elem;
87 // Handle multiple events separated by a space
88 // jQuery(...).bind("mouseover mouseout", fn);
89 types = types.split(" ");
91 var type, i = 0, namespaces;
93 while ( (type = types[ i++ ]) ) {
94 handleObj = handleObjIn ?
95 jQuery.extend({}, handleObjIn) :
96 { handler: handler, data: data };
98 // Namespaced event handlers
99 if ( type.indexOf(".") > -1 ) {
100 namespaces = type.split(".");
101 type = namespaces.shift();
102 handleObj.namespace = namespaces.slice(0).sort().join(".");
106 handleObj.namespace = "";
109 handleObj.type = type;
110 if ( !handleObj.guid ) {
111 handleObj.guid = handler.guid;
114 // Get the current list of functions bound to this event
115 var handlers = events[ type ],
116 special = jQuery.event.special[ type ] || {};
118 // Init the event handler queue
120 handlers = events[ type ] = [];
122 // Check for a special event handler
123 // Only use addEventListener/attachEvent if the special
124 // events handler returns false
125 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
126 // Bind the global event handler to the element
127 if ( elem.addEventListener ) {
128 elem.addEventListener( type, eventHandle, false );
130 } else if ( elem.attachEvent ) {
131 elem.attachEvent( "on" + type, eventHandle );
137 special.add.call( elem, handleObj );
139 if ( !handleObj.handler.guid ) {
140 handleObj.handler.guid = handler.guid;
144 // Add the function to the element's handler list
145 handlers.push( handleObj );
147 // Keep track of which events have been used, for event optimization
148 jQuery.event.global[ type ] = true;
151 // Nullify elem to prevent memory leaks in IE
157 // Detach an event or set of events from an element
158 remove: function( elem, types, handler, pos ) {
159 // don't do events on text and comment nodes
160 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
164 if ( handler === false ) {
165 handler = returnFalse;
168 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
169 elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
170 events = elemData && elemData.events;
172 if ( !elemData || !events ) {
176 // types is actually an event object here
177 if ( types && types.type ) {
178 handler = types.handler;
182 // Unbind all events for the element
183 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
186 for ( type in events ) {
187 jQuery.event.remove( elem, type + types );
193 // Handle multiple events separated by a space
194 // jQuery(...).unbind("mouseover mouseout", fn);
195 types = types.split(" ");
197 while ( (type = types[ i++ ]) ) {
200 all = type.indexOf(".") < 0;
204 // Namespaced event handlers
205 namespaces = type.split(".");
206 type = namespaces.shift();
208 namespace = new RegExp("(^|\\.)" +
209 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
212 eventType = events[ type ];
219 for ( j = 0; j < eventType.length; j++ ) {
220 handleObj = eventType[ j ];
222 if ( all || namespace.test( handleObj.namespace ) ) {
223 jQuery.event.remove( elem, origType, handleObj.handler, j );
224 eventType.splice( j--, 1 );
231 special = jQuery.event.special[ type ] || {};
233 for ( j = pos || 0; j < eventType.length; j++ ) {
234 handleObj = eventType[ j ];
236 if ( handler.guid === handleObj.guid ) {
237 // remove the given handler for the given type
238 if ( all || namespace.test( handleObj.namespace ) ) {
240 eventType.splice( j--, 1 );
243 if ( special.remove ) {
244 special.remove.call( elem, handleObj );
254 // remove generic event handler if no more handlers exist
255 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
256 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
257 jQuery.removeEvent( elem, type, elemData.handle );
261 delete events[ type ];
265 // Remove the expando if it's no longer used
266 if ( jQuery.isEmptyObject( events ) ) {
267 var handle = elemData.handle;
272 delete elemData.events;
273 delete elemData.handle;
275 if ( jQuery.isEmptyObject( elemData ) ) {
276 jQuery.removeData( elem, undefined, true );
281 trigger: function( event, data, elem ) {
282 // Event object or event type
283 var type = event.type || event,
286 event = typeof event === "object" ?
287 // jQuery.Event object
288 event[ jQuery.expando ] ? event :
290 jQuery.extend( jQuery.Event(type), event ) :
291 // Just the event type (string)
294 if ( type.indexOf("!") >= 0 ) {
295 // Exclusive events trigger only for the bare event type (no namespaces)
296 event.type = type = type.slice(0, -1);
297 event.exclusive = true;
299 if ( type.indexOf(".") >= 0 ) {
300 // Namespaced trigger; create a regexp to match event type in handle()
301 namespaces = type.split(".");
302 event.type = type = namespaces.shift();
305 event.namespace = namespaces.join(".");
306 event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
308 // Handle a global trigger
310 // Don't bubble custom events when global (to avoid too much overhead)
311 event.stopPropagation();
313 // Save some time, only trigger if we've ever bound an event for this type
314 if ( jQuery.event.global[ type ] ) {
315 // XXX This code smells terrible. event.js should not be directly
316 // inspecting the data cache
317 jQuery.each( jQuery.cache, function() {
318 // internalKey variable is just used to make it easier to find
319 // and potentially change this stuff later; currently it just
320 // points to jQuery.expando
321 var internalKey = jQuery.expando,
322 internalCache = this[ internalKey ];
323 if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
324 jQuery.event.trigger( event, data, internalCache.handle.elem );
331 // Don't do events on text and comment nodes
332 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
336 // Clean up the event in case it is being reused
337 event.result = undefined;
340 // Clone any incoming data and prepend the event, creating the handler arg list
341 data = jQuery.makeArray( data );
342 data.unshift( event );
345 // IE doesn't like method names with a colon (#3533, #8272)
346 ontype = type.indexOf(":") < 0? "on" + type : "";
348 // Fire event on the current element, then bubble up the DOM tree
350 var handle = jQuery._data( cur, "handle" );
352 event.currentTarget = cur;
354 handle.apply( cur, data );
357 // Trigger an inline bound script
358 if ( ontype &&jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
359 event.result = false;
360 event.preventDefault();
363 // Bubble up to document, then to window
364 cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
365 } while ( cur && !event.isPropagationStopped() );
367 // If nobody prevented the default action, do it now
368 if ( !event.isDefaultPrevented() ) {
370 special = jQuery.event.special[ type ] || {};
372 if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
373 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
375 // Call a native DOM method on the target with the same name name as the event.
376 // Can't use an .isFunction)() check here because IE6/7 fails that test.
377 // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
379 if ( ontype && elem[ type ] ) {
380 // Don't re-trigger an onFOO event when we call its FOO() method
381 old = elem[ ontype ];
384 elem[ ontype ] = null;
387 jQuery.event.triggered = type;
390 } catch ( ieError ) {}
393 elem[ ontype ] = old;
396 jQuery.event.triggered = undefined;
401 handle: function( event ) {
402 event = jQuery.event.fix( event || window.event );
403 // Snapshot the handlers list since a called handler may add/remove events.
404 var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
405 run_all = !event.exclusive && !event.namespace,
406 args = jQuery.makeArray( arguments );
408 // Use the fix-ed Event rather than the (read-only) native event
410 event.currentTarget = this;
412 for ( var j = 0, l = handlers.length; j < l; j++ ) {
413 var handleObj = handlers[ j ];
415 // Triggered event must 1) be non-exclusive and have no namespace, or
416 // 2) have namespace(s) a subset or equal to those in the bound event.
417 if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
418 // Pass in a reference to the handler function itself
419 // So that we can later remove it
420 event.handler = handleObj.handler;
421 event.data = handleObj.data;
422 event.handleObj = handleObj;
424 var ret = handleObj.handler.apply( this, args );
426 if ( ret !== undefined ) {
428 if ( ret === false ) {
429 event.preventDefault();
430 event.stopPropagation();
434 if ( event.isImmediatePropagationStopped() ) {
442 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(" "),
444 fix: function( event ) {
445 if ( event[ jQuery.expando ] ) {
449 // store a copy of the original event object
450 // and "clone" to set read-only properties
451 var originalEvent = event;
452 event = jQuery.Event( originalEvent );
454 for ( var i = this.props.length, prop; i; ) {
455 prop = this.props[ --i ];
456 event[ prop ] = originalEvent[ prop ];
459 // Fix target property, if necessary
460 if ( !event.target ) {
461 // Fixes #1925 where srcElement might not be defined either
462 event.target = event.srcElement || document;
465 // check if target is a textnode (safari)
466 if ( event.target.nodeType === 3 ) {
467 event.target = event.target.parentNode;
470 // Add relatedTarget, if necessary
471 if ( !event.relatedTarget && event.fromElement ) {
472 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
475 // Calculate pageX/Y if missing and clientX/Y available
476 if ( event.pageX == null && event.clientX != null ) {
477 var eventDocument = event.target.ownerDocument || document,
478 doc = eventDocument.documentElement,
479 body = eventDocument.body;
481 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
482 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
485 // Add which for key events
486 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
487 event.which = event.charCode != null ? event.charCode : event.keyCode;
490 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
491 if ( !event.metaKey && event.ctrlKey ) {
492 event.metaKey = event.ctrlKey;
495 // Add which for click: 1 === left; 2 === middle; 3 === right
496 // Note: button is not normalized, so don't use it
497 if ( !event.which && event.button !== undefined ) {
498 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
504 // Deprecated, use jQuery.guid instead
507 // Deprecated, use jQuery.proxy instead
512 // Make sure the ready event is setup
513 setup: jQuery.bindReady,
514 teardown: jQuery.noop
518 add: function( handleObj ) {
519 jQuery.event.add( this,
520 liveConvert( handleObj.origType, handleObj.selector ),
521 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
524 remove: function( handleObj ) {
525 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
530 setup: function( data, namespaces, eventHandle ) {
531 // We only want to do this special case on windows
532 if ( jQuery.isWindow( this ) ) {
533 this.onbeforeunload = eventHandle;
537 teardown: function( namespaces, eventHandle ) {
538 if ( this.onbeforeunload === eventHandle ) {
539 this.onbeforeunload = null;
546 jQuery.removeEvent = document.removeEventListener ?
547 function( elem, type, handle ) {
548 if ( elem.removeEventListener ) {
549 elem.removeEventListener( type, handle, false );
552 function( elem, type, handle ) {
553 if ( elem.detachEvent ) {
554 elem.detachEvent( "on" + type, handle );
558 jQuery.Event = function( src ) {
559 // Allow instantiation without the 'new' keyword
560 if ( !this.preventDefault ) {
561 return new jQuery.Event( src );
565 if ( src && src.type ) {
566 this.originalEvent = src;
568 // Push explicitly provided properties onto the event object
569 for ( var prop in src ) {
570 // Ensure we don't clobber jQuery.Event prototype
571 // with own properties.
572 if ( hasOwn.call( src, prop ) ) {
573 this[ prop ] = src[ prop ];
577 // Events bubbling up the document may have been marked as prevented
578 // by a handler lower down the tree; reflect the correct value.
579 this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
580 src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
587 // timeStamp is buggy for some events on Firefox(#3843)
588 // So we won't rely on the native value
589 this.timeStamp = jQuery.now();
592 this[ jQuery.expando ] = true;
595 function returnFalse() {
598 function returnTrue() {
602 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
603 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
604 jQuery.Event.prototype = {
605 preventDefault: function() {
606 this.isDefaultPrevented = returnTrue;
608 var e = this.originalEvent;
613 // if preventDefault exists run it on the original event
614 if ( e.preventDefault ) {
617 // otherwise set the returnValue property of the original event to false (IE)
619 e.returnValue = false;
622 stopPropagation: function() {
623 this.isPropagationStopped = returnTrue;
625 var e = this.originalEvent;
629 // if stopPropagation exists run it on the original event
630 if ( e.stopPropagation ) {
633 // otherwise set the cancelBubble property of the original event to true (IE)
634 e.cancelBubble = true;
636 stopImmediatePropagation: function() {
637 this.isImmediatePropagationStopped = returnTrue;
638 this.stopPropagation();
640 isDefaultPrevented: returnFalse,
641 isPropagationStopped: returnFalse,
642 isImmediatePropagationStopped: returnFalse
645 // Checks if an event happened on an element within another element
646 // Used in jQuery.event.special.mouseenter and mouseleave handlers
647 var withinElement = function( event ) {
648 // Check if mouse(over|out) are still within the same parent element
649 var parent = event.relatedTarget;
651 // Firefox sometimes assigns relatedTarget a XUL element
652 // which we cannot access the parentNode property of
655 // Chrome does something similar, the parentNode property
656 // can be accessed but is null.
657 if ( parent && parent !== document && !parent.parentNode ) {
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 && this.nodeName.toLowerCase() !== "form" ) {
705 jQuery.event.add(this, "click.specialSubmit", function( e ) {
709 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
710 trigger( "submit", this, arguments );
714 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
718 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
719 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 e.liveFired = undefined;
782 jQuery.event.trigger( e, arguments[1], elem );
786 jQuery.event.special.change = {
788 focusout: testChange,
790 beforedeactivate: testChange,
792 click: function( e ) {
793 var elem = e.target, type = elem.type;
795 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
796 testChange.call( this, e );
800 // Change has to be called before submit
801 // Keydown will be called before keypress, which is used in submit-event delegation
802 keydown: function( e ) {
803 var elem = e.target, type = elem.type;
805 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
806 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
807 type === "select-multiple" ) {
808 testChange.call( this, e );
812 // Beforeactivate happens also before the previous element is blurred
813 // with this event you can't trigger a change event, but you can store
815 beforeactivate: function( e ) {
817 jQuery._data( elem, "_change_data", getVal(elem) );
821 setup: function( data, namespaces ) {
822 if ( this.type === "file" ) {
826 for ( var type in changeFilters ) {
827 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
830 return rformElems.test( this.nodeName );
833 teardown: function( namespaces ) {
834 jQuery.event.remove( this, ".specialChange" );
836 return rformElems.test( this.nodeName );
840 changeFilters = jQuery.event.special.change.filters;
842 // Handle when the input is .focus()'d
843 changeFilters.focus = changeFilters.beforeactivate;
846 function trigger( type, elem, args ) {
847 // Piggyback on a donor event to simulate a different one.
848 // Fake originalEvent to avoid donor's stopPropagation, but if the
849 // simulated event prevents default then we do the same on the donor.
850 // Don't pass args or remember liveFired; they apply to the donor event.
851 var event = jQuery.extend( {}, args[ 0 ] );
853 event.originalEvent = {};
854 event.liveFired = undefined;
855 jQuery.event.handle.call( elem, event );
856 if ( event.isDefaultPrevented() ) {
857 args[ 0 ].preventDefault();
861 // Create "bubbling" focus and blur events
862 if ( !jQuery.support.focusinBubbles ) {
863 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
865 // Attach a single capturing handler while someone wants focusin/focusout
868 jQuery.event.special[ fix ] = {
870 if ( attaches++ === 0 ) {
871 document.addEventListener( orig, handler, true );
874 teardown: function() {
875 if ( --attaches === 0 ) {
876 document.removeEventListener( orig, handler, true );
881 function handler( donor ) {
882 // Donor event is always a native one; fix it and switch its type.
883 // Let focusin/out handler cancel the donor focus/blur event.
884 var e = jQuery.event.fix( donor );
886 e.originalEvent = {};
887 jQuery.event.trigger( e, null, e.target );
888 if ( e.isDefaultPrevented() ) {
889 donor.preventDefault();
895 jQuery.each(["bind", "one"], function( i, name ) {
896 jQuery.fn[ name ] = function( type, data, fn ) {
897 // Handle object literals
898 if ( typeof type === "object" ) {
899 for ( var key in type ) {
900 this[ name ](key, data, type[key], fn);
905 if ( jQuery.isFunction( data ) || data === false ) {
910 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
911 jQuery( this ).unbind( event, handler );
912 return fn.apply( this, arguments );
915 if ( type === "unload" && name !== "one" ) {
916 this.one( type, data, fn );
919 for ( var i = 0, l = this.length; i < l; i++ ) {
920 jQuery.event.add( this[i], type, handler, data );
929 unbind: function( type, fn ) {
930 // Handle object literals
931 if ( typeof type === "object" && !type.preventDefault ) {
932 for ( var key in type ) {
933 this.unbind(key, type[key]);
937 for ( var i = 0, l = this.length; i < l; i++ ) {
938 jQuery.event.remove( this[i], type, fn );
945 delegate: function( selector, types, data, fn ) {
946 return this.live( types, data, fn, selector );
949 undelegate: function( selector, types, fn ) {
950 if ( arguments.length === 0 ) {
951 return this.unbind( "live" );
954 return this.die( types, null, fn, selector );
958 trigger: function( type, data ) {
959 return this.each(function() {
960 jQuery.event.trigger( type, data, this );
964 triggerHandler: function( type, data ) {
966 var event = jQuery.Event( type );
967 event.preventDefault();
968 event.stopPropagation();
969 jQuery.event.trigger( event, data, this[0] );
974 toggle: function( fn ) {
975 // Save reference to arguments for access in closure
976 var args = arguments,
979 // link all the functions, so any of them can unbind this click handler
980 while ( i < args.length ) {
981 jQuery.proxy( fn, args[ i++ ] );
984 return this.click( jQuery.proxy( fn, function( event ) {
985 // Figure out which function to execute
986 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
987 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
989 // Make sure that clicks stop
990 event.preventDefault();
992 // and execute the function
993 return args[ lastToggle ].apply( this, arguments ) || false;
997 hover: function( fnOver, fnOut ) {
998 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
1005 mouseenter: "mouseover",
1006 mouseleave: "mouseout"
1009 jQuery.each(["live", "die"], function( i, name ) {
1010 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
1011 var type, i = 0, match, namespaces, preType,
1012 selector = origSelector || this.selector,
1013 context = origSelector ? this : jQuery( this.context );
1015 if ( typeof types === "object" && !types.preventDefault ) {
1016 for ( var key in types ) {
1017 context[ name ]( key, data, types[key], selector );
1023 if ( data === false || jQuery.isFunction( data ) ) {
1024 fn = data || returnFalse;
1028 types = (types || "").split(" ");
1030 while ( (type = types[ i++ ]) != null ) {
1031 match = rnamespaces.exec( type );
1035 namespaces = match[0];
1036 type = type.replace( rnamespaces, "" );
1039 if ( type === "hover" ) {
1040 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1046 if ( type === "focus" || type === "blur" ) {
1047 types.push( liveMap[ type ] + namespaces );
1048 type = type + namespaces;
1051 type = (liveMap[ type ] || type) + namespaces;
1054 if ( name === "live" ) {
1055 // bind live handler
1056 for ( var j = 0, l = context.length; j < l; j++ ) {
1057 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1058 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1062 // unbind live handler
1063 context.unbind( "live." + liveConvert( type, selector ), fn );
1071 function liveHandler( event ) {
1072 var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1075 events = jQuery._data( this, "events" );
1077 // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1078 if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1082 if ( event.namespace ) {
1083 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1086 event.liveFired = this;
1088 var live = events.live.slice(0);
1090 for ( j = 0; j < live.length; j++ ) {
1091 handleObj = live[j];
1093 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1094 selectors.push( handleObj.selector );
1097 live.splice( j--, 1 );
1101 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1103 for ( i = 0, l = match.length; i < l; i++ ) {
1106 for ( j = 0; j < live.length; j++ ) {
1107 handleObj = live[j];
1109 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
1113 // Those two events require additional checking
1114 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1115 event.type = handleObj.preType;
1116 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1119 if ( !related || related !== elem ) {
1120 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1126 for ( i = 0, l = elems.length; i < l; i++ ) {
1129 if ( maxLevel && match.level > maxLevel ) {
1133 event.currentTarget = match.elem;
1134 event.data = match.handleObj.data;
1135 event.handleObj = match.handleObj;
1137 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1139 if ( ret === false || event.isPropagationStopped() ) {
1140 maxLevel = match.level;
1142 if ( ret === false ) {
1145 if ( event.isImmediatePropagationStopped() ) {
1154 function liveConvert( type, selector ) {
1155 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1158 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1159 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1160 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1162 // Handle event binding
1163 jQuery.fn[ name ] = function( data, fn ) {
1169 return arguments.length > 0 ?
1170 this.bind( name, data, fn ) :
1171 this.trigger( name );
1174 if ( jQuery.attrFn ) {
1175 jQuery.attrFn[ name ] = true;