3 var rnamespaces = /\.(.*)$/,
4 rformElems = /^(?:textarea|input|select)$/i,
7 rescape = /[^\w\s.|`]/g,
8 fcleanup = function( nm ) {
9 return nm.replace(rescape, "\\$&");
11 focusCounts = { focusin: 0, focusout: 0 };
14 * A number of helper functions used for managing events.
15 * Many of the ideas behind this code originated from
16 * Dean Edwards' addEvent library.
20 // Bind an event to an element
21 // Original by Dean Edwards
22 add: function( elem, types, handler, data ) {
23 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
27 // For whatever reason, IE has trouble passing the window object
28 // around, causing it to be cloned in the process
29 if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
33 if ( handler === false ) {
34 handler = returnFalse;
35 } else if ( !handler ) {
36 // Fixes bug #7229. Fix recommended by jdalton
40 var handleObjIn, handleObj;
42 if ( handler.handler ) {
43 handleObjIn = handler;
44 handler = handleObjIn.handler;
47 // Make sure that the function being executed has a unique ID
48 if ( !handler.guid ) {
49 handler.guid = jQuery.guid++;
52 // Init the element's event structure
53 var elemData = jQuery.data( elem );
55 // If no elemData is found then we must be trying to bind to one of the
56 // banned noData elements
61 // Use a key less likely to result in collisions for plain JS objects.
63 var eventKey = elem.nodeType ? "events" : "__events__",
64 events = elemData[ eventKey ],
65 eventHandle = elemData.handle;
67 if ( typeof events === "function" ) {
68 // On plain objects events is a fn that holds the the data
69 // which prevents this data from being JSON serialized
70 // the function does not need to be called, it just contains the data
71 eventHandle = events.handle;
72 events = events.events;
74 } else if ( !events ) {
75 if ( !elem.nodeType ) {
76 // On plain objects, create a fn that acts as the holder
77 // of the values to avoid JSON serialization of event data
78 elemData[ eventKey ] = elemData = function(){};
81 elemData.events = events = {};
85 elemData.handle = eventHandle = function() {
86 // Handle the second event of a trigger and when
87 // an event is called after a page has unloaded
88 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
89 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
94 // Add elem as a property of the handle function
95 // This is to prevent a memory leak with non-native events in IE.
96 eventHandle.elem = elem;
98 // Handle multiple events separated by a space
99 // jQuery(...).bind("mouseover mouseout", fn);
100 types = types.split(" ");
102 var type, i = 0, namespaces;
104 while ( (type = types[ i++ ]) ) {
105 handleObj = handleObjIn ?
106 jQuery.extend({}, handleObjIn) :
107 { handler: handler, data: data };
109 // Namespaced event handlers
110 if ( type.indexOf(".") > -1 ) {
111 namespaces = type.split(".");
112 type = namespaces.shift();
113 handleObj.namespace = namespaces.slice(0).sort().join(".");
117 handleObj.namespace = "";
120 handleObj.type = type;
121 if ( !handleObj.guid ) {
122 handleObj.guid = handler.guid;
125 // Get the current list of functions bound to this event
126 var handlers = events[ type ],
127 special = jQuery.event.special[ type ] || {};
129 // Init the event handler queue
131 handlers = events[ type ] = [];
133 // Check for a special event handler
134 // Only use addEventListener/attachEvent if the special
135 // events handler returns false
136 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
137 // Bind the global event handler to the element
138 if ( elem.addEventListener ) {
139 elem.addEventListener( type, eventHandle, false );
141 } else if ( elem.attachEvent ) {
142 elem.attachEvent( "on" + type, eventHandle );
148 special.add.call( elem, handleObj );
150 if ( !handleObj.handler.guid ) {
151 handleObj.handler.guid = handler.guid;
155 // Add the function to the element's handler list
156 handlers.push( handleObj );
158 // Keep track of which events have been used, for global triggering
159 jQuery.event.global[ type ] = true;
162 // Nullify elem to prevent memory leaks in IE
168 // Detach an event or set of events from an element
169 remove: function( elem, types, handler, pos ) {
170 // don't do events on text and comment nodes
171 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
175 if ( handler === false ) {
176 handler = returnFalse;
179 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
180 eventKey = elem.nodeType ? "events" : "__events__",
181 elemData = jQuery.data( elem ),
182 events = elemData && elemData[ eventKey ];
184 if ( !elemData || !events ) {
188 if ( typeof events === "function" ) {
190 events = events.events;
193 // types is actually an event object here
194 if ( types && types.type ) {
195 handler = types.handler;
199 // Unbind all events for the element
200 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
203 for ( type in events ) {
204 jQuery.event.remove( elem, type + types );
210 // Handle multiple events separated by a space
211 // jQuery(...).unbind("mouseover mouseout", fn);
212 types = types.split(" ");
214 while ( (type = types[ i++ ]) ) {
217 all = type.indexOf(".") < 0;
221 // Namespaced event handlers
222 namespaces = type.split(".");
223 type = namespaces.shift();
225 namespace = new RegExp("(^|\\.)" +
226 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
229 eventType = events[ type ];
236 for ( j = 0; j < eventType.length; j++ ) {
237 handleObj = eventType[ j ];
239 if ( all || namespace.test( handleObj.namespace ) ) {
240 jQuery.event.remove( elem, origType, handleObj.handler, j );
241 eventType.splice( j--, 1 );
248 special = jQuery.event.special[ type ] || {};
250 for ( j = pos || 0; j < eventType.length; j++ ) {
251 handleObj = eventType[ j ];
253 if ( handler.guid === handleObj.guid ) {
254 // remove the given handler for the given type
255 if ( all || namespace.test( handleObj.namespace ) ) {
257 eventType.splice( j--, 1 );
260 if ( special.remove ) {
261 special.remove.call( elem, handleObj );
271 // remove generic event handler if no more handlers exist
272 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
273 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
274 jQuery.removeEvent( elem, type, elemData.handle );
278 delete events[ type ];
282 // Remove the expando if it's no longer used
283 if ( jQuery.isEmptyObject( events ) ) {
284 var handle = elemData.handle;
289 delete elemData.events;
290 delete elemData.handle;
292 if ( typeof elemData === "function" ) {
293 jQuery.removeData( elem, eventKey );
295 } else if ( jQuery.isEmptyObject( elemData ) ) {
296 jQuery.removeData( elem );
301 // bubbling is internal
302 trigger: function( event, data, elem /*, bubbling */ ) {
303 // Event object or event type
304 var type = event.type || event,
305 bubbling = arguments[3];
308 event = typeof event === "object" ?
309 // jQuery.Event object
310 event[ jQuery.expando ] ? event :
312 jQuery.extend( jQuery.Event(type), event ) :
313 // Just the event type (string)
316 if ( type.indexOf("!") >= 0 ) {
317 event.type = type = type.slice(0, -1);
318 event.exclusive = true;
321 // Handle a global trigger
323 // Don't bubble custom events when global (to avoid too much overhead)
324 event.stopPropagation();
326 // Only trigger if we've ever bound an event for it
327 if ( jQuery.event.global[ type ] ) {
328 jQuery.each( jQuery.cache, function() {
329 if ( this.events && this.events[type] ) {
330 jQuery.event.trigger( event, data, this.handle.elem );
336 // Handle triggering a single element
338 // don't do events on text and comment nodes
339 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
343 // Clean up in case it is reused
344 event.result = undefined;
347 // Clone the incoming data, if any
348 data = jQuery.makeArray( data );
349 data.unshift( event );
352 event.currentTarget = elem;
354 // Trigger the event, it is assumed that "handle" is a function
355 var handle = elem.nodeType ?
356 jQuery.data( elem, "handle" ) :
357 (jQuery.data( elem, "__events__" ) || {}).handle;
360 handle.apply( elem, data );
363 var parent = elem.parentNode || elem.ownerDocument;
365 // Trigger an inline bound script
367 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
368 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
369 event.result = false;
370 event.preventDefault();
374 // prevent IE from throwing an error for some elements with some event types, see #3533
375 } catch (inlineError) {}
377 if ( !event.isPropagationStopped() && parent ) {
378 jQuery.event.trigger( event, data, parent, true );
380 } else if ( !event.isDefaultPrevented() ) {
382 target = event.target,
383 targetType = type.replace( rnamespaces, "" ),
384 isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
385 special = jQuery.event.special[ targetType ] || {};
387 if ( (!special._default || special._default.call( elem, event ) === false) &&
388 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
391 if ( target[ targetType ] ) {
392 // Make sure that we don't accidentally re-trigger the onFOO events
393 old = target[ "on" + targetType ];
396 target[ "on" + targetType ] = null;
399 jQuery.event.triggered = true;
400 target[ targetType ]();
403 // prevent IE from throwing an error for some elements with some event types, see #3533
404 } catch (triggerError) {}
407 target[ "on" + targetType ] = old;
410 jQuery.event.triggered = false;
415 handle: function( event ) {
416 var all, handlers, namespaces, namespace_re, events,
418 args = jQuery.makeArray( arguments );
420 event = args[0] = jQuery.event.fix( event || window.event );
421 event.currentTarget = this;
423 // Namespaced event handlers
424 all = event.type.indexOf(".") < 0 && !event.exclusive;
427 namespaces = event.type.split(".");
428 event.type = namespaces.shift();
429 namespace_sort = namespaces.slice(0).sort();
430 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
433 event.namespace = event.namespace || namespace_sort.join(".");
435 events = jQuery.data(this, this.nodeType ? "events" : "__events__");
437 if ( typeof events === "function" ) {
438 events = events.events;
441 handlers = (events || {})[ event.type ];
443 if ( events && handlers ) {
444 // Clone the handlers to prevent manipulation
445 handlers = handlers.slice(0);
447 for ( var j = 0, l = handlers.length; j < l; j++ ) {
448 var handleObj = handlers[ j ];
450 // Filter the functions by class
451 if ( all || namespace_re.test( handleObj.namespace ) ) {
452 // Pass in a reference to the handler function itself
453 // So that we can later remove it
454 event.handler = handleObj.handler;
455 event.data = handleObj.data;
456 event.handleObj = handleObj;
458 var ret = handleObj.handler.apply( this, args );
460 if ( ret !== undefined ) {
462 if ( ret === false ) {
463 event.preventDefault();
464 event.stopPropagation();
468 if ( event.isImmediatePropagationStopped() ) {
478 props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
480 fix: function( event ) {
481 if ( event[ jQuery.expando ] ) {
485 // store a copy of the original event object
486 // and "clone" to set read-only properties
487 var originalEvent = event;
488 event = jQuery.Event( originalEvent );
490 for ( var i = this.props.length, prop; i; ) {
491 prop = this.props[ --i ];
492 event[ prop ] = originalEvent[ prop ];
495 // Fix target property, if necessary
496 if ( !event.target ) {
497 // Fixes #1925 where srcElement might not be defined either
498 event.target = event.srcElement || document;
501 // check if target is a textnode (safari)
502 if ( event.target.nodeType === 3 ) {
503 event.target = event.target.parentNode;
506 // Add relatedTarget, if necessary
507 if ( !event.relatedTarget && event.fromElement ) {
508 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
511 // Calculate pageX/Y if missing and clientX/Y available
512 if ( event.pageX == null && event.clientX != null ) {
513 var doc = document.documentElement,
514 body = document.body;
516 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
517 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
520 // Add which for key events
521 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
522 event.which = event.charCode != null ? event.charCode : event.keyCode;
525 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
526 if ( !event.metaKey && event.ctrlKey ) {
527 event.metaKey = event.ctrlKey;
530 // Add which for click: 1 === left; 2 === middle; 3 === right
531 // Note: button is not normalized, so don't use it
532 if ( !event.which && event.button !== undefined ) {
533 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
539 // Deprecated, use jQuery.guid instead
542 // Deprecated, use jQuery.proxy instead
547 // Make sure the ready event is setup
548 setup: jQuery.bindReady,
549 teardown: jQuery.noop
553 add: function( handleObj ) {
554 jQuery.event.add( this,
555 liveConvert( handleObj.origType, handleObj.selector ),
556 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
559 remove: function( handleObj ) {
560 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
565 setup: function( data, namespaces, eventHandle ) {
566 // We only want to do this special case on windows
567 if ( jQuery.isWindow( this ) ) {
568 this.onbeforeunload = eventHandle;
572 teardown: function( namespaces, eventHandle ) {
573 if ( this.onbeforeunload === eventHandle ) {
574 this.onbeforeunload = null;
581 jQuery.removeEvent = document.removeEventListener ?
582 function( elem, type, handle ) {
583 if ( elem.removeEventListener ) {
584 elem.removeEventListener( type, handle, false );
587 function( elem, type, handle ) {
588 if ( elem.detachEvent ) {
589 elem.detachEvent( "on" + type, handle );
593 jQuery.Event = function( src ) {
594 // Allow instantiation without the 'new' keyword
595 if ( !this.preventDefault ) {
596 return new jQuery.Event( src );
600 if ( src && src.type ) {
601 this.originalEvent = src;
602 this.type = src.type;
608 // timeStamp is buggy for some events on Firefox(#3843)
609 // So we won't rely on the native value
610 this.timeStamp = jQuery.now();
613 this[ jQuery.expando ] = true;
616 function returnFalse() {
619 function returnTrue() {
623 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
624 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
625 jQuery.Event.prototype = {
626 preventDefault: function() {
627 this.isDefaultPrevented = returnTrue;
629 var e = this.originalEvent;
634 // if preventDefault exists run it on the original event
635 if ( e.preventDefault ) {
638 // otherwise set the returnValue property of the original event to false (IE)
640 e.returnValue = false;
643 stopPropagation: function() {
644 this.isPropagationStopped = returnTrue;
646 var e = this.originalEvent;
650 // if stopPropagation exists run it on the original event
651 if ( e.stopPropagation ) {
654 // otherwise set the cancelBubble property of the original event to true (IE)
655 e.cancelBubble = true;
657 stopImmediatePropagation: function() {
658 this.isImmediatePropagationStopped = returnTrue;
659 this.stopPropagation();
661 isDefaultPrevented: returnFalse,
662 isPropagationStopped: returnFalse,
663 isImmediatePropagationStopped: returnFalse
666 // Checks if an event happened on an element within another element
667 // Used in jQuery.event.special.mouseenter and mouseleave handlers
668 var withinElement = function( event ) {
669 // Check if mouse(over|out) are still within the same parent element
670 var parent = event.relatedTarget;
672 // Firefox sometimes assigns relatedTarget a XUL element
673 // which we cannot access the parentNode property of
675 // Traverse up the tree
676 while ( parent && parent !== this ) {
677 parent = parent.parentNode;
680 if ( parent !== this ) {
681 // set the correct event type
682 event.type = event.data;
684 // handle event if we actually just moused on to a non sub-element
685 jQuery.event.handle.apply( this, arguments );
688 // assuming we've left the element since we most likely mousedover a xul element
692 // In case of event delegation, we only need to rename the event.type,
693 // liveHandler will take care of the rest.
694 delegate = function( event ) {
695 event.type = event.data;
696 jQuery.event.handle.apply( this, arguments );
699 // Create mouseenter and mouseleave events
701 mouseenter: "mouseover",
702 mouseleave: "mouseout"
703 }, function( orig, fix ) {
704 jQuery.event.special[ orig ] = {
705 setup: function( data ) {
706 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
708 teardown: function( data ) {
709 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
715 if ( !jQuery.support.submitBubbles ) {
717 jQuery.event.special.submit = {
718 setup: function( data, namespaces ) {
719 if ( this.nodeName.toLowerCase() !== "form" ) {
720 jQuery.event.add(this, "click.specialSubmit", function( e ) {
724 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
725 e.liveFired = undefined;
726 return trigger( "submit", this, arguments );
730 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
734 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
735 e.liveFired = undefined;
736 return trigger( "submit", this, arguments );
745 teardown: function( namespaces ) {
746 jQuery.event.remove( this, ".specialSubmit" );
752 // change delegation, happens here so we have bind.
753 if ( !jQuery.support.changeBubbles ) {
757 getVal = function( elem ) {
758 var type = elem.type, val = elem.value;
760 if ( type === "radio" || type === "checkbox" ) {
763 } else if ( type === "select-multiple" ) {
764 val = elem.selectedIndex > -1 ?
765 jQuery.map( elem.options, function( elem ) {
766 return elem.selected;
770 } else if ( elem.nodeName.toLowerCase() === "select" ) {
771 val = elem.selectedIndex;
777 testChange = function testChange( e ) {
778 var elem = e.target, data, val;
780 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
784 data = jQuery.data( elem, "_change_data" );
787 // the current data will be also retrieved by beforeactivate
788 if ( e.type !== "focusout" || elem.type !== "radio" ) {
789 jQuery.data( elem, "_change_data", val );
792 if ( data === undefined || val === data ) {
796 if ( data != null || val ) {
798 e.liveFired = undefined;
799 return jQuery.event.trigger( e, arguments[1], elem );
803 jQuery.event.special.change = {
805 focusout: testChange,
807 beforedeactivate: testChange,
809 click: function( e ) {
810 var elem = e.target, type = elem.type;
812 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
813 return testChange.call( this, e );
817 // Change has to be called before submit
818 // Keydown will be called before keypress, which is used in submit-event delegation
819 keydown: function( e ) {
820 var elem = e.target, type = elem.type;
822 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
823 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
824 type === "select-multiple" ) {
825 return testChange.call( this, e );
829 // Beforeactivate happens also before the previous element is blurred
830 // with this event you can't trigger a change event, but you can store
832 beforeactivate: function( e ) {
834 jQuery.data( elem, "_change_data", getVal(elem) );
838 setup: function( data, namespaces ) {
839 if ( this.type === "file" ) {
843 for ( var type in changeFilters ) {
844 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
847 return rformElems.test( this.nodeName );
850 teardown: function( namespaces ) {
851 jQuery.event.remove( this, ".specialChange" );
853 return rformElems.test( this.nodeName );
857 changeFilters = jQuery.event.special.change.filters;
859 // Handle when the input is .focus()'d
860 changeFilters.focus = changeFilters.beforeactivate;
863 function trigger( type, elem, args ) {
865 return jQuery.event.handle.apply( elem, args );
868 // Create "bubbling" focus and blur events
869 if ( document.addEventListener ) {
870 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
871 jQuery.event.special[ fix ] = {
873 if ( focusCounts[fix]++ === 0 ) {
874 document.addEventListener( orig, handler, true );
877 teardown: function() {
878 if ( --focusCounts[fix] === 0 ) {
879 document.removeEventListener( orig, handler, true );
884 function handler( e ) {
885 e = jQuery.event.fix( e );
887 return jQuery.event.trigger( e, null, e.target );
892 jQuery.each(["bind", "one"], function( i, name ) {
893 jQuery.fn[ name ] = function( type, data, fn ) {
894 // Handle object literals
895 if ( typeof type === "object" ) {
896 for ( var key in type ) {
897 this[ name ](key, data, type[key], fn);
902 if ( jQuery.isFunction( data ) || data === false ) {
907 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
908 jQuery( this ).unbind( event, handler );
909 return fn.apply( this, arguments );
912 if ( type === "unload" && name !== "one" ) {
913 this.one( type, data, fn );
916 for ( var i = 0, l = this.length; i < l; i++ ) {
917 jQuery.event.add( this[i], type, handler, data );
926 unbind: function( type, fn ) {
927 // Handle object literals
928 if ( typeof type === "object" && !type.preventDefault ) {
929 for ( var key in type ) {
930 this.unbind(key, type[key]);
934 for ( var i = 0, l = this.length; i < l; i++ ) {
935 jQuery.event.remove( this[i], type, fn );
942 delegate: function( selector, types, data, fn ) {
943 return this.live( types, data, fn, selector );
946 undelegate: function( selector, types, fn ) {
947 if ( arguments.length === 0 ) {
948 return this.unbind( "live" );
951 return this.die( types, null, fn, selector );
955 trigger: function( type, data ) {
956 return this.each(function() {
957 jQuery.event.trigger( type, data, this );
961 triggerHandler: function( type, data ) {
963 var event = jQuery.Event( type );
964 event.preventDefault();
965 event.stopPropagation();
966 jQuery.event.trigger( event, data, this[0] );
971 toggle: function( fn ) {
972 // Save reference to arguments for access in closure
973 var args = arguments,
976 // link all the functions, so any of them can unbind this click handler
977 while ( i < args.length ) {
978 jQuery.proxy( fn, args[ i++ ] );
981 return this.click( jQuery.proxy( fn, function( event ) {
982 // Figure out which function to execute
983 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
984 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
986 // Make sure that clicks stop
987 event.preventDefault();
989 // and execute the function
990 return args[ lastToggle ].apply( this, arguments ) || false;
994 hover: function( fnOver, fnOut ) {
995 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
1002 mouseenter: "mouseover",
1003 mouseleave: "mouseout"
1006 jQuery.each(["live", "die"], function( i, name ) {
1007 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
1008 var type, i = 0, match, namespaces, preType,
1009 selector = origSelector || this.selector,
1010 context = origSelector ? this : jQuery( this.context );
1012 if ( typeof types === "object" && !types.preventDefault ) {
1013 for ( var key in types ) {
1014 context[ name ]( key, data, types[key], selector );
1020 if ( jQuery.isFunction( data ) ) {
1025 types = (types || "").split(" ");
1027 while ( (type = types[ i++ ]) != null ) {
1028 match = rnamespaces.exec( type );
1032 namespaces = match[0];
1033 type = type.replace( rnamespaces, "" );
1036 if ( type === "hover" ) {
1037 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1043 if ( type === "focus" || type === "blur" ) {
1044 types.push( liveMap[ type ] + namespaces );
1045 type = type + namespaces;
1048 type = (liveMap[ type ] || type) + namespaces;
1051 if ( name === "live" ) {
1052 // bind live handler
1053 for ( var j = 0, l = context.length; j < l; j++ ) {
1054 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1055 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1059 // unbind live handler
1060 context.unbind( "live." + liveConvert( type, selector ), fn );
1068 function liveHandler( event ) {
1069 var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1072 events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
1074 if ( typeof events === "function" ) {
1075 events = events.events;
1078 // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1079 if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1083 if ( event.namespace ) {
1084 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1087 event.liveFired = this;
1089 var live = events.live.slice(0);
1091 for ( j = 0; j < live.length; j++ ) {
1092 handleObj = live[j];
1094 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1095 selectors.push( handleObj.selector );
1098 live.splice( j--, 1 );
1102 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1104 for ( i = 0, l = match.length; i < l; i++ ) {
1107 for ( j = 0; j < live.length; j++ ) {
1108 handleObj = live[j];
1110 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1114 // Those two events require additional checking
1115 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1116 event.type = handleObj.preType;
1117 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1120 if ( !related || related !== elem ) {
1121 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1127 for ( i = 0, l = elems.length; i < l; i++ ) {
1130 if ( maxLevel && match.level > maxLevel ) {
1134 event.currentTarget = match.elem;
1135 event.data = match.handleObj.data;
1136 event.handleObj = match.handleObj;
1138 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1140 if ( ret === false || event.isPropagationStopped() ) {
1141 maxLevel = match.level;
1143 if ( ret === false ) {
1146 if ( event.isImmediatePropagationStopped() ) {
1155 function liveConvert( type, selector ) {
1156 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1159 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1160 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1161 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1163 // Handle event binding
1164 jQuery.fn[ name ] = function( data, fn ) {
1170 return arguments.length > 0 ?
1171 this.bind( name, data, fn ) :
1172 this.trigger( name );
1175 if ( jQuery.attrFn ) {
1176 jQuery.attrFn[ name ] = true;
1180 // Prevent memory leaks in IE
1181 // Window isn't included so as not to unbind existing unload events
1183 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1184 if ( window.attachEvent && !window.addEventListener ) {
1185 jQuery(window).bind("unload", function() {
1186 for ( var id in jQuery.cache ) {
1187 if ( jQuery.cache[ id ].handle ) {
1188 // Try/Catch is to handle iframes being unloaded, see #4280
1190 jQuery.event.remove( jQuery.cache[ id ].handle.elem );