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 beforedeactivate: testChange,
797 click: function( e ) {
798 var elem = e.target, type = elem.type;
800 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
801 return testChange.call( this, e );
805 // Change has to be called before submit
806 // Keydown will be called before keypress, which is used in submit-event delegation
807 keydown: function( e ) {
808 var elem = e.target, type = elem.type;
810 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
811 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
812 type === "select-multiple" ) {
813 return testChange.call( this, e );
817 // Beforeactivate happens also before the previous element is blurred
818 // with this event you can't trigger a change event, but you can store
820 beforeactivate: function( e ) {
822 jQuery.data( elem, "_change_data", getVal(elem) );
826 setup: function( data, namespaces ) {
827 if ( this.type === "file" ) {
831 for ( var type in changeFilters ) {
832 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
835 return rformElems.test( this.nodeName );
838 teardown: function( namespaces ) {
839 jQuery.event.remove( this, ".specialChange" );
841 return rformElems.test( this.nodeName );
845 changeFilters = jQuery.event.special.change.filters;
847 // Handle when the input is .focus()'d
848 changeFilters.focus = changeFilters.beforeactivate;
851 function trigger( type, elem, args ) {
853 return jQuery.event.handle.apply( elem, args );
856 // Create "bubbling" focus and blur events
857 if ( document.addEventListener ) {
858 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
859 jQuery.event.special[ fix ] = {
861 if ( focusCounts[fix]++ === 0 ) {
862 document.addEventListener( orig, handler, true );
865 teardown: function() {
866 if ( --focusCounts[fix] === 0 ) {
867 document.removeEventListener( orig, handler, true );
872 function handler( e ) {
873 e = jQuery.event.fix( e );
875 return jQuery.event.trigger( e, null, e.target );
880 jQuery.each(["bind", "one"], function( i, name ) {
881 jQuery.fn[ name ] = function( type, data, fn ) {
882 // Handle object literals
883 if ( typeof type === "object" ) {
884 for ( var key in type ) {
885 this[ name ](key, data, type[key], fn);
890 if ( jQuery.isFunction( data ) || data === false ) {
895 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
896 jQuery( this ).unbind( event, handler );
897 return fn.apply( this, arguments );
900 if ( type === "unload" && name !== "one" ) {
901 this.one( type, data, fn );
904 for ( var i = 0, l = this.length; i < l; i++ ) {
905 jQuery.event.add( this[i], type, handler, data );
914 unbind: function( type, fn ) {
915 // Handle object literals
916 if ( typeof type === "object" && !type.preventDefault ) {
917 for ( var key in type ) {
918 this.unbind(key, type[key]);
922 for ( var i = 0, l = this.length; i < l; i++ ) {
923 jQuery.event.remove( this[i], type, fn );
930 delegate: function( selector, types, data, fn ) {
931 return this.live( types, data, fn, selector );
934 undelegate: function( selector, types, fn ) {
935 if ( arguments.length === 0 ) {
936 return this.unbind( "live" );
939 return this.die( types, null, fn, selector );
943 trigger: function( type, data ) {
944 return this.each(function() {
945 jQuery.event.trigger( type, data, this );
949 triggerHandler: function( type, data ) {
951 var event = jQuery.Event( type );
952 event.preventDefault();
953 event.stopPropagation();
954 jQuery.event.trigger( event, data, this[0] );
959 toggle: function( fn ) {
960 // Save reference to arguments for access in closure
961 var args = arguments, i = 1;
963 // link all the functions, so any of them can unbind this click handler
964 while ( i < args.length ) {
965 jQuery.proxy( fn, args[ i++ ] );
968 return this.click( jQuery.proxy( fn, function( event ) {
969 // Figure out which function to execute
970 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
971 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
973 // Make sure that clicks stop
974 event.preventDefault();
976 // and execute the function
977 return args[ lastToggle ].apply( this, arguments ) || false;
981 hover: function( fnOver, fnOut ) {
982 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
989 mouseenter: "mouseover",
990 mouseleave: "mouseout"
993 jQuery.each(["live", "die"], function( i, name ) {
994 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
995 var type, i = 0, match, namespaces, preType,
996 selector = origSelector || this.selector,
997 context = origSelector ? this : jQuery( this.context );
999 if ( typeof types === "object" && !types.preventDefault ) {
1000 for ( var key in types ) {
1001 context[ name ]( key, data, types[key], selector );
1007 if ( jQuery.isFunction( data ) ) {
1012 types = (types || "").split(" ");
1014 while ( (type = types[ i++ ]) != null ) {
1015 match = rnamespaces.exec( type );
1019 namespaces = match[0];
1020 type = type.replace( rnamespaces, "" );
1023 if ( type === "hover" ) {
1024 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1030 if ( type === "focus" || type === "blur" ) {
1031 types.push( liveMap[ type ] + namespaces );
1032 type = type + namespaces;
1035 type = (liveMap[ type ] || type) + namespaces;
1038 if ( name === "live" ) {
1039 // bind live handler
1040 for ( var j = 0, l = context.length; j < l; j++ ) {
1041 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1042 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1046 // unbind live handler
1047 context.unbind( "live." + liveConvert( type, selector ), fn );
1055 function liveHandler( event ) {
1056 var stop, maxLevel, elems = [], selectors = [],
1057 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1058 events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
1060 if ( typeof events === "function" ) {
1061 events = events.events;
1064 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1065 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1069 if ( event.namespace ) {
1070 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1073 event.liveFired = this;
1075 var live = events.live.slice(0);
1077 for ( j = 0; j < live.length; j++ ) {
1078 handleObj = live[j];
1080 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1081 selectors.push( handleObj.selector );
1084 live.splice( j--, 1 );
1088 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1090 for ( i = 0, l = match.length; i < l; i++ ) {
1093 for ( j = 0; j < live.length; j++ ) {
1094 handleObj = live[j];
1096 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1100 // Those two events require additional checking
1101 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1102 event.type = handleObj.preType;
1103 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1106 if ( !related || related !== elem ) {
1107 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1113 for ( i = 0, l = elems.length; i < l; i++ ) {
1116 if ( maxLevel && match.level > maxLevel ) {
1120 event.currentTarget = match.elem;
1121 event.data = match.handleObj.data;
1122 event.handleObj = match.handleObj;
1124 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1126 if ( ret === false || event.isPropagationStopped() ) {
1127 maxLevel = match.level;
1129 if ( ret === false ) {
1138 function liveConvert( type, selector ) {
1139 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1142 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1143 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1144 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1146 // Handle event binding
1147 jQuery.fn[ name ] = function( data, fn ) {
1153 return arguments.length > 0 ?
1154 this.bind( name, data, fn ) :
1155 this.trigger( name );
1158 if ( jQuery.attrFn ) {
1159 jQuery.attrFn[ name ] = true;
1163 // Prevent memory leaks in IE
1164 // Window isn't included so as not to unbind existing unload events
1166 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1167 if ( window.attachEvent && !window.addEventListener ) {
1168 jQuery(window).bind("unload", function() {
1169 for ( var id in jQuery.cache ) {
1170 if ( jQuery.cache[ id ].handle ) {
1171 // Try/Catch is to handle iframes being unloaded, see #4280
1173 jQuery.event.remove( jQuery.cache[ id ].handle.elem );