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;
37 var handleObjIn, handleObj;
39 if ( handler.handler ) {
40 handleObjIn = handler;
41 handler = handleObjIn.handler;
44 // Make sure that the function being executed has a unique ID
45 if ( !handler.guid ) {
46 handler.guid = jQuery.guid++;
49 // Init the element's event structure
50 var elemData = jQuery.data( elem );
52 // If no elemData is found then we must be trying to bind to one of the
53 // banned noData elements
58 // Use a key less likely to result in collisions for plain JS objects.
60 var eventKey = elem.nodeType ? "events" : "__events__",
61 events = elemData[ eventKey ],
62 eventHandle = elemData.handle;
64 if ( typeof events === "function" ) {
65 // On plain objects events is a fn that holds the the data
66 // which prevents this data from being JSON serialized
67 // the function does not need to be called, it just contains the data
68 eventHandle = events.handle;
69 events = events.events;
71 } else if ( !events ) {
72 if ( !elem.nodeType ) {
73 // On plain objects, create a fn that acts as the holder
74 // of the values to avoid JSON serialization of event data
75 elemData[ eventKey ] = elemData = function(){};
78 elemData.events = events = {};
82 elemData.handle = eventHandle = function() {
83 // Handle the second event of a trigger and when
84 // an event is called after a page has unloaded
85 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
86 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
91 // Add elem as a property of the handle function
92 // This is to prevent a memory leak with non-native events in IE.
93 eventHandle.elem = elem;
95 // Handle multiple events separated by a space
96 // jQuery(...).bind("mouseover mouseout", fn);
97 types = types.split(" ");
99 var type, i = 0, namespaces;
101 while ( (type = types[ i++ ]) ) {
102 handleObj = handleObjIn ?
103 jQuery.extend({}, handleObjIn) :
104 { handler: handler, data: data };
106 // Namespaced event handlers
107 if ( type.indexOf(".") > -1 ) {
108 namespaces = type.split(".");
109 type = namespaces.shift();
110 handleObj.namespace = namespaces.slice(0).sort().join(".");
114 handleObj.namespace = "";
117 handleObj.type = type;
118 if ( !handleObj.guid ) {
119 handleObj.guid = handler.guid;
122 // Get the current list of functions bound to this event
123 var handlers = events[ type ],
124 special = jQuery.event.special[ type ] || {};
126 // Init the event handler queue
128 handlers = events[ type ] = [];
130 // Check for a special event handler
131 // Only use addEventListener/attachEvent if the special
132 // events handler returns false
133 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
134 // Bind the global event handler to the element
135 if ( elem.addEventListener ) {
136 elem.addEventListener( type, eventHandle, false );
138 } else if ( elem.attachEvent ) {
139 elem.attachEvent( "on" + type, eventHandle );
145 special.add.call( elem, handleObj );
147 if ( !handleObj.handler.guid ) {
148 handleObj.handler.guid = handler.guid;
152 // Add the function to the element's handler list
153 handlers.push( handleObj );
155 // Keep track of which events have been used, for global triggering
156 jQuery.event.global[ type ] = true;
159 // Nullify elem to prevent memory leaks in IE
165 // Detach an event or set of events from an element
166 remove: function( elem, types, handler, pos ) {
167 // don't do events on text and comment nodes
168 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
172 if ( handler === false ) {
173 handler = returnFalse;
176 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
177 eventKey = elem.nodeType ? "events" : "__events__",
178 elemData = jQuery.data( elem ),
179 events = elemData && elemData[ eventKey ];
181 if ( !elemData || !events ) {
185 if ( typeof events === "function" ) {
187 events = events.events;
190 // types is actually an event object here
191 if ( types && types.type ) {
192 handler = types.handler;
196 // Unbind all events for the element
197 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
200 for ( type in events ) {
201 jQuery.event.remove( elem, type + types );
207 // Handle multiple events separated by a space
208 // jQuery(...).unbind("mouseover mouseout", fn);
209 types = types.split(" ");
211 while ( (type = types[ i++ ]) ) {
214 all = type.indexOf(".") < 0;
218 // Namespaced event handlers
219 namespaces = type.split(".");
220 type = namespaces.shift();
222 namespace = new RegExp("(^|\\.)" +
223 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
226 eventType = events[ type ];
233 for ( j = 0; j < eventType.length; j++ ) {
234 handleObj = eventType[ j ];
236 if ( all || namespace.test( handleObj.namespace ) ) {
237 jQuery.event.remove( elem, origType, handleObj.handler, j );
238 eventType.splice( j--, 1 );
245 special = jQuery.event.special[ type ] || {};
247 for ( j = pos || 0; j < eventType.length; j++ ) {
248 handleObj = eventType[ j ];
250 if ( handler.guid === handleObj.guid ) {
251 // remove the given handler for the given type
252 if ( all || namespace.test( handleObj.namespace ) ) {
254 eventType.splice( j--, 1 );
257 if ( special.remove ) {
258 special.remove.call( elem, handleObj );
268 // remove generic event handler if no more handlers exist
269 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
270 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
271 jQuery.removeEvent( elem, type, elemData.handle );
275 delete events[ type ];
279 // Remove the expando if it's no longer used
280 if ( jQuery.isEmptyObject( events ) ) {
281 var handle = elemData.handle;
286 delete elemData.events;
287 delete elemData.handle;
289 if ( typeof elemData === "function" ) {
290 jQuery.removeData( elem, eventKey );
292 } else if ( jQuery.isEmptyObject( elemData ) ) {
293 jQuery.removeData( elem );
298 // bubbling is internal
299 trigger: function( event, data, elem /*, bubbling */ ) {
300 // Event object or event type
301 var type = event.type || event,
302 bubbling = arguments[3];
305 event = typeof event === "object" ?
306 // jQuery.Event object
307 event[ jQuery.expando ] ? event :
309 jQuery.extend( jQuery.Event(type), event ) :
310 // Just the event type (string)
313 if ( type.indexOf("!") >= 0 ) {
314 event.type = type = type.slice(0, -1);
315 event.exclusive = true;
318 // Handle a global trigger
320 // Don't bubble custom events when global (to avoid too much overhead)
321 event.stopPropagation();
323 // Only trigger if we've ever bound an event for it
324 if ( jQuery.event.global[ type ] ) {
325 jQuery.each( jQuery.cache, function() {
326 if ( this.events && this.events[type] ) {
327 jQuery.event.trigger( event, data, this.handle.elem );
333 // Handle triggering a single element
335 // don't do events on text and comment nodes
336 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
340 // Clean up in case it is reused
341 event.result = undefined;
344 // Clone the incoming data, if any
345 data = jQuery.makeArray( data );
346 data.unshift( event );
349 event.currentTarget = elem;
351 // Trigger the event, it is assumed that "handle" is a function
352 var handle = elem.nodeType ?
353 jQuery.data( elem, "handle" ) :
354 (jQuery.data( elem, "__events__" ) || {}).handle;
357 handle.apply( elem, data );
360 var parent = elem.parentNode || elem.ownerDocument;
362 // Trigger an inline bound script
364 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
365 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
366 event.result = false;
367 event.preventDefault();
371 // prevent IE from throwing an error for some elements with some event types, see #3533
372 } catch (inlineError) {}
374 if ( !event.isPropagationStopped() && parent ) {
375 jQuery.event.trigger( event, data, parent, true );
377 } else if ( !event.isDefaultPrevented() ) {
378 var target = event.target, old, targetType = type.replace(rnamespaces, ""),
379 isClick = jQuery.nodeName(target, "a") && targetType === "click",
380 special = jQuery.event.special[ targetType ] || {};
382 if ( (!special._default || special._default.call( elem, event ) === false) &&
383 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
386 if ( target[ targetType ] ) {
387 // Make sure that we don't accidentally re-trigger the onFOO events
388 old = target[ "on" + targetType ];
391 target[ "on" + targetType ] = null;
394 jQuery.event.triggered = true;
395 target[ targetType ]();
398 // prevent IE from throwing an error for some elements with some event types, see #3533
399 } catch (triggerError) {}
402 target[ "on" + targetType ] = old;
405 jQuery.event.triggered = false;
410 handle: function( event ) {
411 var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
413 event = args[0] = jQuery.event.fix( event || window.event );
414 event.currentTarget = this;
416 // Namespaced event handlers
417 all = event.type.indexOf(".") < 0 && !event.exclusive;
420 namespaces = event.type.split(".");
421 event.type = namespaces.shift();
422 namespace_sort = namespaces.slice(0).sort();
423 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
426 event.namespace = event.namespace || namespace_sort.join(".");
428 events = jQuery.data(this, this.nodeType ? "events" : "__events__");
430 if ( typeof events === "function" ) {
431 events = events.events;
434 handlers = (events || {})[ event.type ];
436 if ( events && handlers ) {
437 // Clone the handlers to prevent manipulation
438 handlers = handlers.slice(0);
440 for ( var j = 0, l = handlers.length; j < l; j++ ) {
441 var handleObj = handlers[ j ];
443 // Filter the functions by class
444 if ( all || namespace_re.test( handleObj.namespace ) ) {
445 // Pass in a reference to the handler function itself
446 // So that we can later remove it
447 event.handler = handleObj.handler;
448 event.data = handleObj.data;
449 event.handleObj = handleObj;
451 var ret = handleObj.handler.apply( this, args );
453 if ( ret !== undefined ) {
455 if ( ret === false ) {
456 event.preventDefault();
457 event.stopPropagation();
461 if ( event.isImmediatePropagationStopped() ) {
471 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(" "),
473 fix: function( event ) {
474 if ( event[ jQuery.expando ] ) {
478 // store a copy of the original event object
479 // and "clone" to set read-only properties
480 var originalEvent = event;
481 event = jQuery.Event( originalEvent );
483 for ( var i = this.props.length, prop; i; ) {
484 prop = this.props[ --i ];
485 event[ prop ] = originalEvent[ prop ];
488 // Fix target property, if necessary
489 if ( !event.target ) {
490 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
493 // check if target is a textnode (safari)
494 if ( event.target.nodeType === 3 ) {
495 event.target = event.target.parentNode;
498 // Add relatedTarget, if necessary
499 if ( !event.relatedTarget && event.fromElement ) {
500 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
503 // Calculate pageX/Y if missing and clientX/Y available
504 if ( event.pageX == null && event.clientX != null ) {
505 var doc = document.documentElement, body = document.body;
506 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
507 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
510 // Add which for key events
511 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
512 event.which = event.charCode != null ? event.charCode : event.keyCode;
515 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
516 if ( !event.metaKey && event.ctrlKey ) {
517 event.metaKey = event.ctrlKey;
520 // Add which for click: 1 === left; 2 === middle; 3 === right
521 // Note: button is not normalized, so don't use it
522 if ( !event.which && event.button !== undefined ) {
523 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
529 // Deprecated, use jQuery.guid instead
532 // Deprecated, use jQuery.proxy instead
537 // Make sure the ready event is setup
538 setup: jQuery.bindReady,
539 teardown: jQuery.noop
543 add: function( handleObj ) {
544 jQuery.event.add( this,
545 liveConvert( handleObj.origType, handleObj.selector ),
546 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
549 remove: function( handleObj ) {
550 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
555 setup: function( data, namespaces, eventHandle ) {
556 // We only want to do this special case on windows
557 if ( jQuery.isWindow( this ) ) {
558 this.onbeforeunload = eventHandle;
562 teardown: function( namespaces, eventHandle ) {
563 if ( this.onbeforeunload === eventHandle ) {
564 this.onbeforeunload = null;
571 jQuery.removeEvent = document.removeEventListener ?
572 function( elem, type, handle ) {
573 if ( elem.removeEventListener ) {
574 elem.removeEventListener( type, handle, false );
577 function( elem, type, handle ) {
578 if ( elem.detachEvent ) {
579 elem.detachEvent( "on" + type, handle );
583 jQuery.Event = function( src ) {
584 // Allow instantiation without the 'new' keyword
585 if ( !this.preventDefault ) {
586 return new jQuery.Event( src );
590 if ( src && src.type ) {
591 this.originalEvent = src;
592 this.type = src.type;
598 // timeStamp is buggy for some events on Firefox(#3843)
599 // So we won't rely on the native value
600 this.timeStamp = jQuery.now();
603 this[ jQuery.expando ] = true;
606 function returnFalse() {
609 function returnTrue() {
613 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
614 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
615 jQuery.Event.prototype = {
616 preventDefault: function() {
617 this.isDefaultPrevented = returnTrue;
619 var e = this.originalEvent;
624 // if preventDefault exists run it on the original event
625 if ( e.preventDefault ) {
628 // otherwise set the returnValue property of the original event to false (IE)
630 e.returnValue = false;
633 stopPropagation: function() {
634 this.isPropagationStopped = returnTrue;
636 var e = this.originalEvent;
640 // if stopPropagation exists run it on the original event
641 if ( e.stopPropagation ) {
644 // otherwise set the cancelBubble property of the original event to true (IE)
645 e.cancelBubble = true;
647 stopImmediatePropagation: function() {
648 this.isImmediatePropagationStopped = returnTrue;
649 this.stopPropagation();
651 isDefaultPrevented: returnFalse,
652 isPropagationStopped: returnFalse,
653 isImmediatePropagationStopped: returnFalse
656 // Checks if an event happened on an element within another element
657 // Used in jQuery.event.special.mouseenter and mouseleave handlers
658 var withinElement = function( event ) {
659 // Check if mouse(over|out) are still within the same parent element
660 var parent = event.relatedTarget;
662 // Firefox sometimes assigns relatedTarget a XUL element
663 // which we cannot access the parentNode property of
665 // Traverse up the tree
666 while ( parent && parent !== this ) {
667 parent = parent.parentNode;
670 if ( parent !== this ) {
671 // set the correct event type
672 event.type = event.data;
674 // handle event if we actually just moused on to a non sub-element
675 jQuery.event.handle.apply( this, arguments );
678 // assuming we've left the element since we most likely mousedover a xul element
682 // In case of event delegation, we only need to rename the event.type,
683 // liveHandler will take care of the rest.
684 delegate = function( event ) {
685 event.type = event.data;
686 jQuery.event.handle.apply( this, arguments );
689 // Create mouseenter and mouseleave events
691 mouseenter: "mouseover",
692 mouseleave: "mouseout"
693 }, function( orig, fix ) {
694 jQuery.event.special[ orig ] = {
695 setup: function( data ) {
696 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
698 teardown: function( data ) {
699 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
705 if ( !jQuery.support.submitBubbles ) {
707 jQuery.event.special.submit = {
708 setup: function( data, namespaces ) {
709 if ( this.nodeName.toLowerCase() !== "form" ) {
710 jQuery.event.add(this, "click.specialSubmit", function( e ) {
711 var elem = e.target, type = elem.type;
713 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
714 e.liveFired = undefined;
715 return trigger( "submit", this, arguments );
719 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
720 var elem = e.target, type = elem.type;
722 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
723 e.liveFired = undefined;
724 return trigger( "submit", this, arguments );
733 teardown: function( namespaces ) {
734 jQuery.event.remove( this, ".specialSubmit" );
740 // change delegation, happens here so we have bind.
741 if ( !jQuery.support.changeBubbles ) {
745 getVal = function( elem ) {
746 var type = elem.type, val = elem.value;
748 if ( type === "radio" || type === "checkbox" ) {
751 } else if ( type === "select-multiple" ) {
752 val = elem.selectedIndex > -1 ?
753 jQuery.map( elem.options, function( elem ) {
754 return elem.selected;
758 } else if ( elem.nodeName.toLowerCase() === "select" ) {
759 val = elem.selectedIndex;
765 testChange = function testChange( e ) {
766 var elem = e.target, data, val;
768 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
772 data = jQuery.data( elem, "_change_data" );
775 // the current data will be also retrieved by beforeactivate
776 if ( e.type !== "focusout" || elem.type !== "radio" ) {
777 jQuery.data( elem, "_change_data", val );
780 if ( data === undefined || val === data ) {
784 if ( data != null || val ) {
786 e.liveFired = undefined;
787 return jQuery.event.trigger( e, arguments[1], elem );
791 jQuery.event.special.change = {
793 focusout: testChange,
795 click: function( e ) {
796 var elem = e.target, type = elem.type;
798 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
799 return testChange.call( this, e );
803 // Change has to be called before submit
804 // Keydown will be called before keypress, which is used in submit-event delegation
805 keydown: function( e ) {
806 var elem = e.target, type = elem.type;
808 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
809 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
810 type === "select-multiple" ) {
811 return testChange.call( this, e );
815 // Beforeactivate happens also before the previous element is blurred
816 // with this event you can't trigger a change event, but you can store
818 beforeactivate: function( e ) {
820 jQuery.data( elem, "_change_data", getVal(elem) );
824 setup: function( data, namespaces ) {
825 if ( this.type === "file" ) {
829 for ( var type in changeFilters ) {
830 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
833 return rformElems.test( this.nodeName );
836 teardown: function( namespaces ) {
837 jQuery.event.remove( this, ".specialChange" );
839 return rformElems.test( this.nodeName );
843 changeFilters = jQuery.event.special.change.filters;
845 // Handle when the input is .focus()'d
846 changeFilters.focus = changeFilters.beforeactivate;
849 function trigger( type, elem, args ) {
851 return jQuery.event.handle.apply( elem, args );
854 // Create "bubbling" focus and blur events
855 if ( document.addEventListener ) {
856 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
857 jQuery.event.special[ fix ] = {
859 if ( focusCounts[fix]++ === 0 ) {
860 document.addEventListener( orig, handler, true );
863 teardown: function() {
864 if ( --focusCounts[fix] === 0 ) {
865 document.removeEventListener( orig, handler, true );
870 function handler( e ) {
871 e = jQuery.event.fix( e );
873 return jQuery.event.trigger( e, null, e.target );
878 jQuery.each(["bind", "one"], function( i, name ) {
879 jQuery.fn[ name ] = function( type, data, fn ) {
880 // Handle object literals
881 if ( typeof type === "object" ) {
882 for ( var key in type ) {
883 this[ name ](key, data, type[key], fn);
888 if ( jQuery.isFunction( data ) || data === false ) {
893 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
894 jQuery( this ).unbind( event, handler );
895 return fn.apply( this, arguments );
898 if ( type === "unload" && name !== "one" ) {
899 this.one( type, data, fn );
902 for ( var i = 0, l = this.length; i < l; i++ ) {
903 jQuery.event.add( this[i], type, handler, data );
912 unbind: function( type, fn ) {
913 // Handle object literals
914 if ( typeof type === "object" && !type.preventDefault ) {
915 for ( var key in type ) {
916 this.unbind(key, type[key]);
920 for ( var i = 0, l = this.length; i < l; i++ ) {
921 jQuery.event.remove( this[i], type, fn );
928 delegate: function( selector, types, data, fn ) {
929 return this.live( types, data, fn, selector );
932 undelegate: function( selector, types, fn ) {
933 if ( arguments.length === 0 ) {
934 return this.unbind( "live" );
937 return this.die( types, null, fn, selector );
941 trigger: function( type, data ) {
942 return this.each(function() {
943 jQuery.event.trigger( type, data, this );
947 triggerHandler: function( type, data ) {
949 var event = jQuery.Event( type );
950 event.preventDefault();
951 event.stopPropagation();
952 jQuery.event.trigger( event, data, this[0] );
957 toggle: function( fn ) {
958 // Save reference to arguments for access in closure
959 var args = arguments, i = 1;
961 // link all the functions, so any of them can unbind this click handler
962 while ( i < args.length ) {
963 jQuery.proxy( fn, args[ i++ ] );
966 return this.click( jQuery.proxy( fn, function( event ) {
967 // Figure out which function to execute
968 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
969 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
971 // Make sure that clicks stop
972 event.preventDefault();
974 // and execute the function
975 return args[ lastToggle ].apply( this, arguments ) || false;
979 hover: function( fnOver, fnOut ) {
980 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
987 mouseenter: "mouseover",
988 mouseleave: "mouseout"
991 jQuery.each(["live", "die"], function( i, name ) {
992 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
993 var type, i = 0, match, namespaces, preType,
994 selector = origSelector || this.selector,
995 context = origSelector ? this : jQuery( this.context );
997 if ( typeof types === "object" && !types.preventDefault ) {
998 for ( var key in types ) {
999 context[ name ]( key, data, types[key], selector );
1005 if ( jQuery.isFunction( data ) ) {
1010 types = (types || "").split(" ");
1012 while ( (type = types[ i++ ]) != null ) {
1013 match = rnamespaces.exec( type );
1017 namespaces = match[0];
1018 type = type.replace( rnamespaces, "" );
1021 if ( type === "hover" ) {
1022 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1028 if ( type === "focus" || type === "blur" ) {
1029 types.push( liveMap[ type ] + namespaces );
1030 type = type + namespaces;
1033 type = (liveMap[ type ] || type) + namespaces;
1036 if ( name === "live" ) {
1037 // bind live handler
1038 for ( var j = 0, l = context.length; j < l; j++ ) {
1039 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1040 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1044 // unbind live handler
1045 context.unbind( "live." + liveConvert( type, selector ), fn );
1053 function liveHandler( event ) {
1054 var stop, maxLevel, elems = [], selectors = [],
1055 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1056 events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
1058 if ( typeof events === "function" ) {
1059 events = events.events;
1062 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1063 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1067 if ( event.namespace ) {
1068 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1071 event.liveFired = this;
1073 var live = events.live.slice(0);
1075 for ( j = 0; j < live.length; j++ ) {
1076 handleObj = live[j];
1078 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1079 selectors.push( handleObj.selector );
1082 live.splice( j--, 1 );
1086 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1088 for ( i = 0, l = match.length; i < l; i++ ) {
1091 for ( j = 0; j < live.length; j++ ) {
1092 handleObj = live[j];
1094 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1098 // Those two events require additional checking
1099 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1100 event.type = handleObj.preType;
1101 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1104 if ( !related || related !== elem ) {
1105 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1111 for ( i = 0, l = elems.length; i < l; i++ ) {
1114 if ( maxLevel && match.level > maxLevel ) {
1118 event.currentTarget = match.elem;
1119 event.data = match.handleObj.data;
1120 event.handleObj = match.handleObj;
1122 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1124 if ( ret === false || event.isPropagationStopped() ) {
1125 maxLevel = match.level;
1127 if ( ret === false ) {
1136 function liveConvert( type, selector ) {
1137 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1140 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1141 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1142 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1144 // Handle event binding
1145 jQuery.fn[ name ] = function( data, fn ) {
1151 return arguments.length > 0 ?
1152 this.bind( name, data, fn ) :
1153 this.trigger( name );
1156 if ( jQuery.attrFn ) {
1157 jQuery.attrFn[ name ] = true;
1161 // Prevent memory leaks in IE
1162 // Window isn't included so as not to unbind existing unload events
1164 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1165 if ( window.attachEvent && !window.addEventListener ) {
1166 jQuery(window).bind("unload", function() {
1167 for ( var id in jQuery.cache ) {
1168 if ( jQuery.cache[ id ].handle ) {
1169 // Try/Catch is to handle iframes being unloaded, see #4280
1171 jQuery.event.remove( jQuery.cache[ id ].handle.elem );