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() ) {
381 var target = event.target, old, targetType = type.replace(rnamespaces, ""),
382 isClick = jQuery.nodeName(target, "a") && targetType === "click",
383 special = jQuery.event.special[ targetType ] || {};
385 if ( (!special._default || special._default.call( elem, event ) === false) &&
386 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
389 if ( target[ targetType ] ) {
390 // Make sure that we don't accidentally re-trigger the onFOO events
391 old = target[ "on" + targetType ];
394 target[ "on" + targetType ] = null;
397 jQuery.event.triggered = true;
398 target[ targetType ]();
401 // prevent IE from throwing an error for some elements with some event types, see #3533
402 } catch (triggerError) {}
405 target[ "on" + targetType ] = old;
408 jQuery.event.triggered = false;
413 handle: function( event ) {
414 var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
416 event = args[0] = jQuery.event.fix( event || window.event );
417 event.currentTarget = this;
419 // Namespaced event handlers
420 all = event.type.indexOf(".") < 0 && !event.exclusive;
423 namespaces = event.type.split(".");
424 event.type = namespaces.shift();
425 namespace_sort = namespaces.slice(0).sort();
426 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
429 event.namespace = event.namespace || namespace_sort.join(".");
431 events = jQuery.data(this, this.nodeType ? "events" : "__events__");
433 if ( typeof events === "function" ) {
434 events = events.events;
437 handlers = (events || {})[ event.type ];
439 if ( events && handlers ) {
440 // Clone the handlers to prevent manipulation
441 handlers = handlers.slice(0);
443 for ( var j = 0, l = handlers.length; j < l; j++ ) {
444 var handleObj = handlers[ j ];
446 // Filter the functions by class
447 if ( all || namespace_re.test( handleObj.namespace ) ) {
448 // Pass in a reference to the handler function itself
449 // So that we can later remove it
450 event.handler = handleObj.handler;
451 event.data = handleObj.data;
452 event.handleObj = handleObj;
454 var ret = handleObj.handler.apply( this, args );
456 if ( ret !== undefined ) {
458 if ( ret === false ) {
459 event.preventDefault();
460 event.stopPropagation();
464 if ( event.isImmediatePropagationStopped() ) {
474 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(" "),
476 fix: function( event ) {
477 if ( event[ jQuery.expando ] ) {
481 // store a copy of the original event object
482 // and "clone" to set read-only properties
483 var originalEvent = event;
484 event = jQuery.Event( originalEvent );
486 for ( var i = this.props.length, prop; i; ) {
487 prop = this.props[ --i ];
488 event[ prop ] = originalEvent[ prop ];
491 // Fix target property, if necessary
492 if ( !event.target ) {
493 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
496 // check if target is a textnode (safari)
497 if ( event.target.nodeType === 3 ) {
498 event.target = event.target.parentNode;
501 // Add relatedTarget, if necessary
502 if ( !event.relatedTarget && event.fromElement ) {
503 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
506 // Calculate pageX/Y if missing and clientX/Y available
507 if ( event.pageX == null && event.clientX != null ) {
508 var doc = document.documentElement, body = document.body;
509 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
510 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
513 // Add which for key events
514 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
515 event.which = event.charCode != null ? event.charCode : event.keyCode;
518 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
519 if ( !event.metaKey && event.ctrlKey ) {
520 event.metaKey = event.ctrlKey;
523 // Add which for click: 1 === left; 2 === middle; 3 === right
524 // Note: button is not normalized, so don't use it
525 if ( !event.which && event.button !== undefined ) {
526 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
532 // Deprecated, use jQuery.guid instead
535 // Deprecated, use jQuery.proxy instead
540 // Make sure the ready event is setup
541 setup: jQuery.bindReady,
542 teardown: jQuery.noop
546 add: function( handleObj ) {
547 jQuery.event.add( this,
548 liveConvert( handleObj.origType, handleObj.selector ),
549 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
552 remove: function( handleObj ) {
553 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
558 setup: function( data, namespaces, eventHandle ) {
559 // We only want to do this special case on windows
560 if ( jQuery.isWindow( this ) ) {
561 this.onbeforeunload = eventHandle;
565 teardown: function( namespaces, eventHandle ) {
566 if ( this.onbeforeunload === eventHandle ) {
567 this.onbeforeunload = null;
574 jQuery.removeEvent = document.removeEventListener ?
575 function( elem, type, handle ) {
576 if ( elem.removeEventListener ) {
577 elem.removeEventListener( type, handle, false );
580 function( elem, type, handle ) {
581 if ( elem.detachEvent ) {
582 elem.detachEvent( "on" + type, handle );
586 jQuery.Event = function( src ) {
587 // Allow instantiation without the 'new' keyword
588 if ( !this.preventDefault ) {
589 return new jQuery.Event( src );
593 if ( src && src.type ) {
594 this.originalEvent = src;
595 this.type = src.type;
601 // timeStamp is buggy for some events on Firefox(#3843)
602 // So we won't rely on the native value
603 this.timeStamp = jQuery.now();
606 this[ jQuery.expando ] = true;
609 function returnFalse() {
612 function returnTrue() {
616 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
617 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
618 jQuery.Event.prototype = {
619 preventDefault: function() {
620 this.isDefaultPrevented = returnTrue;
622 var e = this.originalEvent;
627 // if preventDefault exists run it on the original event
628 if ( e.preventDefault ) {
631 // otherwise set the returnValue property of the original event to false (IE)
633 e.returnValue = false;
636 stopPropagation: function() {
637 this.isPropagationStopped = returnTrue;
639 var e = this.originalEvent;
643 // if stopPropagation exists run it on the original event
644 if ( e.stopPropagation ) {
647 // otherwise set the cancelBubble property of the original event to true (IE)
648 e.cancelBubble = true;
650 stopImmediatePropagation: function() {
651 this.isImmediatePropagationStopped = returnTrue;
652 this.stopPropagation();
654 isDefaultPrevented: returnFalse,
655 isPropagationStopped: returnFalse,
656 isImmediatePropagationStopped: returnFalse
659 // Checks if an event happened on an element within another element
660 // Used in jQuery.event.special.mouseenter and mouseleave handlers
661 var withinElement = function( event ) {
662 // Check if mouse(over|out) are still within the same parent element
663 var parent = event.relatedTarget;
665 // Firefox sometimes assigns relatedTarget a XUL element
666 // which we cannot access the parentNode property of
668 // Traverse up the tree
669 while ( parent && parent !== this ) {
670 parent = parent.parentNode;
673 if ( parent !== this ) {
674 // set the correct event type
675 event.type = event.data;
677 // handle event if we actually just moused on to a non sub-element
678 jQuery.event.handle.apply( this, arguments );
681 // assuming we've left the element since we most likely mousedover a xul element
685 // In case of event delegation, we only need to rename the event.type,
686 // liveHandler will take care of the rest.
687 delegate = function( event ) {
688 event.type = event.data;
689 jQuery.event.handle.apply( this, arguments );
692 // Create mouseenter and mouseleave events
694 mouseenter: "mouseover",
695 mouseleave: "mouseout"
696 }, function( orig, fix ) {
697 jQuery.event.special[ orig ] = {
698 setup: function( data ) {
699 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
701 teardown: function( data ) {
702 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
708 if ( !jQuery.support.submitBubbles ) {
710 jQuery.event.special.submit = {
711 setup: function( data, namespaces ) {
712 if ( this.nodeName.toLowerCase() !== "form" ) {
713 jQuery.event.add(this, "click.specialSubmit", function( e ) {
714 var elem = e.target, type = elem.type;
716 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
717 e.liveFired = undefined;
718 return trigger( "submit", this, arguments );
722 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
723 var elem = e.target, type = elem.type;
725 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
726 e.liveFired = undefined;
727 return trigger( "submit", this, arguments );
736 teardown: function( namespaces ) {
737 jQuery.event.remove( this, ".specialSubmit" );
743 // change delegation, happens here so we have bind.
744 if ( !jQuery.support.changeBubbles ) {
748 getVal = function( elem ) {
749 var type = elem.type, val = elem.value;
751 if ( type === "radio" || type === "checkbox" ) {
754 } else if ( type === "select-multiple" ) {
755 val = elem.selectedIndex > -1 ?
756 jQuery.map( elem.options, function( elem ) {
757 return elem.selected;
761 } else if ( elem.nodeName.toLowerCase() === "select" ) {
762 val = elem.selectedIndex;
768 testChange = function testChange( e ) {
769 var elem = e.target, data, val;
771 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
775 data = jQuery.data( elem, "_change_data" );
778 // the current data will be also retrieved by beforeactivate
779 if ( e.type !== "focusout" || elem.type !== "radio" ) {
780 jQuery.data( elem, "_change_data", val );
783 if ( data === undefined || val === data ) {
787 if ( data != null || val ) {
789 e.liveFired = undefined;
790 return jQuery.event.trigger( e, arguments[1], elem );
794 jQuery.event.special.change = {
796 focusout: testChange,
798 beforedeactivate: testChange,
800 click: function( e ) {
801 var elem = e.target, type = elem.type;
803 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
804 return testChange.call( this, e );
808 // Change has to be called before submit
809 // Keydown will be called before keypress, which is used in submit-event delegation
810 keydown: function( e ) {
811 var elem = e.target, type = elem.type;
813 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
814 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
815 type === "select-multiple" ) {
816 return testChange.call( this, e );
820 // Beforeactivate happens also before the previous element is blurred
821 // with this event you can't trigger a change event, but you can store
823 beforeactivate: function( e ) {
825 jQuery.data( elem, "_change_data", getVal(elem) );
829 setup: function( data, namespaces ) {
830 if ( this.type === "file" ) {
834 for ( var type in changeFilters ) {
835 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
838 return rformElems.test( this.nodeName );
841 teardown: function( namespaces ) {
842 jQuery.event.remove( this, ".specialChange" );
844 return rformElems.test( this.nodeName );
848 changeFilters = jQuery.event.special.change.filters;
850 // Handle when the input is .focus()'d
851 changeFilters.focus = changeFilters.beforeactivate;
854 function trigger( type, elem, args ) {
856 return jQuery.event.handle.apply( elem, args );
859 // Create "bubbling" focus and blur events
860 if ( document.addEventListener ) {
861 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
862 jQuery.event.special[ fix ] = {
864 if ( focusCounts[fix]++ === 0 ) {
865 document.addEventListener( orig, handler, true );
868 teardown: function() {
869 if ( --focusCounts[fix] === 0 ) {
870 document.removeEventListener( orig, handler, true );
875 function handler( e ) {
876 e = jQuery.event.fix( e );
878 return jQuery.event.trigger( e, null, e.target );
883 jQuery.each(["bind", "one"], function( i, name ) {
884 jQuery.fn[ name ] = function( type, data, fn ) {
885 // Handle object literals
886 if ( typeof type === "object" ) {
887 for ( var key in type ) {
888 this[ name ](key, data, type[key], fn);
893 if ( jQuery.isFunction( data ) || data === false ) {
898 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
899 jQuery( this ).unbind( event, handler );
900 return fn.apply( this, arguments );
903 if ( type === "unload" && name !== "one" ) {
904 this.one( type, data, fn );
907 for ( var i = 0, l = this.length; i < l; i++ ) {
908 jQuery.event.add( this[i], type, handler, data );
917 unbind: function( type, fn ) {
918 // Handle object literals
919 if ( typeof type === "object" && !type.preventDefault ) {
920 for ( var key in type ) {
921 this.unbind(key, type[key]);
925 for ( var i = 0, l = this.length; i < l; i++ ) {
926 jQuery.event.remove( this[i], type, fn );
933 delegate: function( selector, types, data, fn ) {
934 return this.live( types, data, fn, selector );
937 undelegate: function( selector, types, fn ) {
938 if ( arguments.length === 0 ) {
939 return this.unbind( "live" );
942 return this.die( types, null, fn, selector );
946 trigger: function( type, data ) {
947 return this.each(function() {
948 jQuery.event.trigger( type, data, this );
952 triggerHandler: function( type, data ) {
954 var event = jQuery.Event( type );
955 event.preventDefault();
956 event.stopPropagation();
957 jQuery.event.trigger( event, data, this[0] );
962 toggle: function( fn ) {
963 // Save reference to arguments for access in closure
964 var args = arguments, i = 1;
966 // link all the functions, so any of them can unbind this click handler
967 while ( i < args.length ) {
968 jQuery.proxy( fn, args[ i++ ] );
971 return this.click( jQuery.proxy( fn, function( event ) {
972 // Figure out which function to execute
973 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
974 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
976 // Make sure that clicks stop
977 event.preventDefault();
979 // and execute the function
980 return args[ lastToggle ].apply( this, arguments ) || false;
984 hover: function( fnOver, fnOut ) {
985 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
992 mouseenter: "mouseover",
993 mouseleave: "mouseout"
996 jQuery.each(["live", "die"], function( i, name ) {
997 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
998 var type, i = 0, match, namespaces, preType,
999 selector = origSelector || this.selector,
1000 context = origSelector ? this : jQuery( this.context );
1002 if ( typeof types === "object" && !types.preventDefault ) {
1003 for ( var key in types ) {
1004 context[ name ]( key, data, types[key], selector );
1010 if ( jQuery.isFunction( data ) ) {
1015 types = (types || "").split(" ");
1017 while ( (type = types[ i++ ]) != null ) {
1018 match = rnamespaces.exec( type );
1022 namespaces = match[0];
1023 type = type.replace( rnamespaces, "" );
1026 if ( type === "hover" ) {
1027 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1033 if ( type === "focus" || type === "blur" ) {
1034 types.push( liveMap[ type ] + namespaces );
1035 type = type + namespaces;
1038 type = (liveMap[ type ] || type) + namespaces;
1041 if ( name === "live" ) {
1042 // bind live handler
1043 for ( var j = 0, l = context.length; j < l; j++ ) {
1044 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1045 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1049 // unbind live handler
1050 context.unbind( "live." + liveConvert( type, selector ), fn );
1058 function liveHandler( event ) {
1059 var stop, maxLevel, elems = [], selectors = [],
1060 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1061 events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
1063 if ( typeof events === "function" ) {
1064 events = events.events;
1067 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1068 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1072 // IE will still dispatch events on disabled elements, so halt it (#6911)
1073 if( event.target.disabled ) {
1077 if ( event.namespace ) {
1078 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1081 event.liveFired = this;
1083 var live = events.live.slice(0);
1085 for ( j = 0; j < live.length; j++ ) {
1086 handleObj = live[j];
1088 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1089 selectors.push( handleObj.selector );
1092 live.splice( j--, 1 );
1096 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1098 for ( i = 0, l = match.length; i < l; i++ ) {
1101 for ( j = 0; j < live.length; j++ ) {
1102 handleObj = live[j];
1104 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1108 // Those two events require additional checking
1109 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1110 event.type = handleObj.preType;
1111 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1114 if ( !related || related !== elem ) {
1115 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1121 for ( i = 0, l = elems.length; i < l; i++ ) {
1124 if ( maxLevel && match.level > maxLevel ) {
1128 event.currentTarget = match.elem;
1129 event.data = match.handleObj.data;
1130 event.handleObj = match.handleObj;
1132 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1134 if ( ret === false || event.isPropagationStopped() ) {
1135 maxLevel = match.level;
1137 if ( ret === false ) {
1140 if ( event.isImmediatePropagationStopped() ) {
1149 function liveConvert( type, selector ) {
1150 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1153 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1154 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1155 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1157 // Handle event binding
1158 jQuery.fn[ name ] = function( data, fn ) {
1164 return arguments.length > 0 ?
1165 this.bind( name, data, fn ) :
1166 this.trigger( name );
1169 if ( jQuery.attrFn ) {
1170 jQuery.attrFn[ name ] = true;
1174 // Prevent memory leaks in IE
1175 // Window isn't included so as not to unbind existing unload events
1177 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1178 if ( window.attachEvent && !window.addEventListener ) {
1179 jQuery(window).bind("unload", function() {
1180 for ( var id in jQuery.cache ) {
1181 if ( jQuery.cache[ id ].handle ) {
1182 // Try/Catch is to handle iframes being unloaded, see #4280
1184 jQuery.event.remove( jQuery.cache[ id ].handle.elem );