3 var rnamespaces = /\.(.*)$/,
4 rformElems = /^(?:textarea|input|select)$/i,
7 rescape = /[^\w\s.|`]/g,
8 fcleanup = function( nm ) {
9 return nm.replace(rescape, "\\$&");
13 * A number of helper functions used for managing events.
14 * Many of the ideas behind this code originated from
15 * Dean Edwards' addEvent library.
19 // Bind an event to an element
20 // Original by Dean Edwards
21 add: function( elem, types, handler, data ) {
22 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
26 // For whatever reason, IE has trouble passing the window object
27 // around, causing it to be cloned in the process
28 if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
32 if ( handler === false ) {
33 handler = returnFalse;
34 } else if ( !handler ) {
35 // Fixes bug #7229. Fix recommended by jdalton
39 var handleObjIn, handleObj;
41 if ( handler.handler ) {
42 handleObjIn = handler;
43 handler = handleObjIn.handler;
46 // Make sure that the function being executed has a unique ID
47 if ( !handler.guid ) {
48 handler.guid = jQuery.guid++;
51 // Init the element's event structure
52 var elemData = jQuery._data( elem );
54 // If no elemData is found then we must be trying to bind to one of the
55 // banned noData elements
60 var events = elemData.events,
61 eventHandle = elemData.handle;
64 elemData.events = events = {};
68 elemData.handle = eventHandle = function() {
69 // Handle the second event of a trigger and when
70 // an event is called after a page has unloaded
71 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
72 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
77 // Add elem as a property of the handle function
78 // This is to prevent a memory leak with non-native events in IE.
79 eventHandle.elem = elem;
81 // Handle multiple events separated by a space
82 // jQuery(...).bind("mouseover mouseout", fn);
83 types = types.split(" ");
85 var type, i = 0, namespaces;
87 while ( (type = types[ i++ ]) ) {
88 handleObj = handleObjIn ?
89 jQuery.extend({}, handleObjIn) :
90 { handler: handler, data: data };
92 // Namespaced event handlers
93 if ( type.indexOf(".") > -1 ) {
94 namespaces = type.split(".");
95 type = namespaces.shift();
96 handleObj.namespace = namespaces.slice(0).sort().join(".");
100 handleObj.namespace = "";
103 handleObj.type = type;
104 if ( !handleObj.guid ) {
105 handleObj.guid = handler.guid;
108 // Get the current list of functions bound to this event
109 var handlers = events[ type ],
110 special = jQuery.event.special[ type ] || {};
112 // Init the event handler queue
114 handlers = events[ type ] = [];
116 // Check for a special event handler
117 // Only use addEventListener/attachEvent if the special
118 // events handler returns false
119 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
120 // Bind the global event handler to the element
121 if ( elem.addEventListener ) {
122 elem.addEventListener( type, eventHandle, false );
124 } else if ( elem.attachEvent ) {
125 elem.attachEvent( "on" + type, eventHandle );
131 special.add.call( elem, handleObj );
133 if ( !handleObj.handler.guid ) {
134 handleObj.handler.guid = handler.guid;
138 // Add the function to the element's handler list
139 handlers.push( handleObj );
141 // Keep track of which events have been used, for global triggering
142 jQuery.event.global[ type ] = true;
145 // Nullify elem to prevent memory leaks in IE
151 // Detach an event or set of events from an element
152 remove: function( elem, types, handler, pos ) {
153 // don't do events on text and comment nodes
154 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
158 if ( handler === false ) {
159 handler = returnFalse;
162 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
163 elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
164 events = elemData && elemData.events;
166 if ( !elemData || !events ) {
170 // types is actually an event object here
171 if ( types && types.type ) {
172 handler = types.handler;
176 // Unbind all events for the element
177 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
180 for ( type in events ) {
181 jQuery.event.remove( elem, type + types );
187 // Handle multiple events separated by a space
188 // jQuery(...).unbind("mouseover mouseout", fn);
189 types = types.split(" ");
191 while ( (type = types[ i++ ]) ) {
194 all = type.indexOf(".") < 0;
198 // Namespaced event handlers
199 namespaces = type.split(".");
200 type = namespaces.shift();
202 namespace = new RegExp("(^|\\.)" +
203 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
206 eventType = events[ type ];
213 for ( j = 0; j < eventType.length; j++ ) {
214 handleObj = eventType[ j ];
216 if ( all || namespace.test( handleObj.namespace ) ) {
217 jQuery.event.remove( elem, origType, handleObj.handler, j );
218 eventType.splice( j--, 1 );
225 special = jQuery.event.special[ type ] || {};
227 for ( j = pos || 0; j < eventType.length; j++ ) {
228 handleObj = eventType[ j ];
230 if ( handler.guid === handleObj.guid ) {
231 // remove the given handler for the given type
232 if ( all || namespace.test( handleObj.namespace ) ) {
234 eventType.splice( j--, 1 );
237 if ( special.remove ) {
238 special.remove.call( elem, handleObj );
248 // remove generic event handler if no more handlers exist
249 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
250 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
251 jQuery.removeEvent( elem, type, elemData.handle );
255 delete events[ type ];
259 // Remove the expando if it's no longer used
260 if ( jQuery.isEmptyObject( events ) ) {
261 var handle = elemData.handle;
266 delete elemData.events;
267 delete elemData.handle;
269 if ( jQuery.isEmptyObject( elemData ) ) {
270 jQuery.removeData( elem, undefined, true );
275 // bubbling is internal
276 trigger: function( event, data, elem /*, bubbling */ ) {
277 // Event object or event type
278 var type = event.type || event,
279 bubbling = arguments[3];
282 event = typeof event === "object" ?
283 // jQuery.Event object
284 event[ jQuery.expando ] ? event :
286 jQuery.extend( jQuery.Event(type), event ) :
287 // Just the event type (string)
290 if ( type.indexOf("!") >= 0 ) {
291 event.type = type = type.slice(0, -1);
292 event.exclusive = true;
295 // Handle a global trigger
297 // Don't bubble custom events when global (to avoid too much overhead)
298 event.stopPropagation();
300 // Only trigger if we've ever bound an event for it
301 if ( jQuery.event.global[ type ] ) {
302 // XXX This code smells terrible. event.js should not be directly
303 // inspecting the data cache
304 jQuery.each( jQuery.cache, function() {
305 // internalKey variable is just used to make it easier to find
306 // and potentially change this stuff later; currently it just
307 // points to jQuery.expando
308 var internalKey = jQuery.expando,
309 internalCache = this[ internalKey ];
310 if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
311 jQuery.event.trigger( event, data, internalCache.handle.elem );
317 // Handle triggering a single element
319 // don't do events on text and comment nodes
320 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
324 // Clean up in case it is reused
325 event.result = undefined;
328 // Clone the incoming data, if any
329 data = jQuery.makeArray( data );
330 data.unshift( event );
333 event.currentTarget = elem;
335 // Trigger the event, it is assumed that "handle" is a function
336 var handle = jQuery._data( elem, "handle" );
339 handle.apply( elem, data );
342 var parent = elem.parentNode || elem.ownerDocument;
344 // Trigger an inline bound script
346 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
347 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
348 event.result = false;
349 event.preventDefault();
353 // prevent IE from throwing an error for some elements with some event types, see #3533
354 } catch (inlineError) {}
356 if ( !event.isPropagationStopped() && parent ) {
357 jQuery.event.trigger( event, data, parent, true );
359 } else if ( !event.isDefaultPrevented() ) {
361 target = event.target,
362 targetType = type.replace( rnamespaces, "" ),
363 isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
364 special = jQuery.event.special[ targetType ] || {};
366 if ( (!special._default || special._default.call( elem, event ) === false) &&
367 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
370 if ( target[ targetType ] ) {
371 // Make sure that we don't accidentally re-trigger the onFOO events
372 old = target[ "on" + targetType ];
375 target[ "on" + targetType ] = null;
378 jQuery.event.triggered = true;
379 target[ targetType ]();
382 // prevent IE from throwing an error for some elements with some event types, see #3533
383 } catch (triggerError) {}
386 target[ "on" + targetType ] = old;
389 jQuery.event.triggered = false;
394 handle: function( event ) {
395 var all, handlers, namespaces, namespace_re, events,
397 args = jQuery.makeArray( arguments );
399 event = args[0] = jQuery.event.fix( event || window.event );
400 event.currentTarget = this;
402 // Namespaced event handlers
403 all = event.type.indexOf(".") < 0 && !event.exclusive;
406 namespaces = event.type.split(".");
407 event.type = namespaces.shift();
408 namespace_sort = namespaces.slice(0).sort();
409 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
412 event.namespace = event.namespace || namespace_sort.join(".");
414 events = jQuery._data(this, "events");
416 handlers = (events || {})[ event.type ];
418 if ( events && handlers ) {
419 // Clone the handlers to prevent manipulation
420 handlers = handlers.slice(0);
422 for ( var j = 0, l = handlers.length; j < l; j++ ) {
423 var handleObj = handlers[ j ];
425 // Filter the functions by class
426 if ( all || namespace_re.test( handleObj.namespace ) ) {
427 // Pass in a reference to the handler function itself
428 // So that we can later remove it
429 event.handler = handleObj.handler;
430 event.data = handleObj.data;
431 event.handleObj = handleObj;
433 var ret = handleObj.handler.apply( this, args );
435 if ( ret !== undefined ) {
437 if ( ret === false ) {
438 event.preventDefault();
439 event.stopPropagation();
443 if ( event.isImmediatePropagationStopped() ) {
453 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(" "),
455 fix: function( event ) {
456 if ( event[ jQuery.expando ] ) {
460 // store a copy of the original event object
461 // and "clone" to set read-only properties
462 var originalEvent = event;
463 event = jQuery.Event( originalEvent );
465 for ( var i = this.props.length, prop; i; ) {
466 prop = this.props[ --i ];
467 event[ prop ] = originalEvent[ prop ];
470 // Fix target property, if necessary
471 if ( !event.target ) {
472 // Fixes #1925 where srcElement might not be defined either
473 event.target = event.srcElement || document;
476 // check if target is a textnode (safari)
477 if ( event.target.nodeType === 3 ) {
478 event.target = event.target.parentNode;
481 // Add relatedTarget, if necessary
482 if ( !event.relatedTarget && event.fromElement ) {
483 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
486 // Calculate pageX/Y if missing and clientX/Y available
487 if ( event.pageX == null && event.clientX != null ) {
488 var doc = document.documentElement,
489 body = document.body;
491 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
492 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
495 // Add which for key events
496 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
497 event.which = event.charCode != null ? event.charCode : event.keyCode;
500 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
501 if ( !event.metaKey && event.ctrlKey ) {
502 event.metaKey = event.ctrlKey;
505 // Add which for click: 1 === left; 2 === middle; 3 === right
506 // Note: button is not normalized, so don't use it
507 if ( !event.which && event.button !== undefined ) {
508 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
514 // Deprecated, use jQuery.guid instead
517 // Deprecated, use jQuery.proxy instead
522 // Make sure the ready event is setup
523 setup: jQuery.bindReady,
524 teardown: jQuery.noop
528 add: function( handleObj ) {
529 jQuery.event.add( this,
530 liveConvert( handleObj.origType, handleObj.selector ),
531 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
534 remove: function( handleObj ) {
535 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
540 setup: function( data, namespaces, eventHandle ) {
541 // We only want to do this special case on windows
542 if ( jQuery.isWindow( this ) ) {
543 this.onbeforeunload = eventHandle;
547 teardown: function( namespaces, eventHandle ) {
548 if ( this.onbeforeunload === eventHandle ) {
549 this.onbeforeunload = null;
556 jQuery.removeEvent = document.removeEventListener ?
557 function( elem, type, handle ) {
558 if ( elem.removeEventListener ) {
559 elem.removeEventListener( type, handle, false );
562 function( elem, type, handle ) {
563 if ( elem.detachEvent ) {
564 elem.detachEvent( "on" + type, handle );
568 jQuery.Event = function( src ) {
569 // Allow instantiation without the 'new' keyword
570 if ( !this.preventDefault ) {
571 return new jQuery.Event( src );
575 if ( src && src.type ) {
576 this.originalEvent = src;
577 this.type = src.type;
579 // Events bubbling up the document may have been marked as prevented
580 // by a handler lower down the tree; reflect the correct value.
581 this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
582 src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
589 // timeStamp is buggy for some events on Firefox(#3843)
590 // So we won't rely on the native value
591 this.timeStamp = jQuery.now();
594 this[ jQuery.expando ] = true;
597 function returnFalse() {
600 function returnTrue() {
604 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
605 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
606 jQuery.Event.prototype = {
607 preventDefault: function() {
608 this.isDefaultPrevented = returnTrue;
610 var e = this.originalEvent;
615 // if preventDefault exists run it on the original event
616 if ( e.preventDefault ) {
619 // otherwise set the returnValue property of the original event to false (IE)
621 e.returnValue = false;
624 stopPropagation: function() {
625 this.isPropagationStopped = returnTrue;
627 var e = this.originalEvent;
631 // if stopPropagation exists run it on the original event
632 if ( e.stopPropagation ) {
635 // otherwise set the cancelBubble property of the original event to true (IE)
636 e.cancelBubble = true;
638 stopImmediatePropagation: function() {
639 this.isImmediatePropagationStopped = returnTrue;
640 this.stopPropagation();
642 isDefaultPrevented: returnFalse,
643 isPropagationStopped: returnFalse,
644 isImmediatePropagationStopped: returnFalse
647 // Checks if an event happened on an element within another element
648 // Used in jQuery.event.special.mouseenter and mouseleave handlers
649 var withinElement = function( event ) {
650 // Check if mouse(over|out) are still within the same parent element
651 var parent = event.relatedTarget;
653 // Firefox sometimes assigns relatedTarget a XUL element
654 // which we cannot access the parentNode property of
657 // Chrome does something similar, the parentNode property
658 // can be accessed but is null.
659 if ( parent !== document && !parent.parentNode ) {
662 // Traverse up the tree
663 while ( parent && parent !== this ) {
664 parent = parent.parentNode;
667 if ( parent !== this ) {
668 // set the correct event type
669 event.type = event.data;
671 // handle event if we actually just moused on to a non sub-element
672 jQuery.event.handle.apply( this, arguments );
675 // assuming we've left the element since we most likely mousedover a xul element
679 // In case of event delegation, we only need to rename the event.type,
680 // liveHandler will take care of the rest.
681 delegate = function( event ) {
682 event.type = event.data;
683 jQuery.event.handle.apply( this, arguments );
686 // Create mouseenter and mouseleave events
688 mouseenter: "mouseover",
689 mouseleave: "mouseout"
690 }, function( orig, fix ) {
691 jQuery.event.special[ orig ] = {
692 setup: function( data ) {
693 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
695 teardown: function( data ) {
696 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
702 if ( !jQuery.support.submitBubbles ) {
704 jQuery.event.special.submit = {
705 setup: function( data, namespaces ) {
706 if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
707 jQuery.event.add(this, "click.specialSubmit", function( e ) {
711 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
712 trigger( "submit", this, arguments );
716 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
720 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
721 trigger( "submit", this, arguments );
730 teardown: function( namespaces ) {
731 jQuery.event.remove( this, ".specialSubmit" );
737 // change delegation, happens here so we have bind.
738 if ( !jQuery.support.changeBubbles ) {
742 getVal = function( elem ) {
743 var type = elem.type, val = elem.value;
745 if ( type === "radio" || type === "checkbox" ) {
748 } else if ( type === "select-multiple" ) {
749 val = elem.selectedIndex > -1 ?
750 jQuery.map( elem.options, function( elem ) {
751 return elem.selected;
755 } else if ( elem.nodeName.toLowerCase() === "select" ) {
756 val = elem.selectedIndex;
762 testChange = function testChange( e ) {
763 var elem = e.target, data, val;
765 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
769 data = jQuery._data( elem, "_change_data" );
772 // the current data will be also retrieved by beforeactivate
773 if ( e.type !== "focusout" || elem.type !== "radio" ) {
774 jQuery._data( elem, "_change_data", val );
777 if ( data === undefined || val === data ) {
781 if ( data != null || val ) {
783 e.liveFired = undefined;
784 jQuery.event.trigger( e, arguments[1], elem );
788 jQuery.event.special.change = {
790 focusout: testChange,
792 beforedeactivate: testChange,
794 click: function( e ) {
795 var elem = e.target, type = elem.type;
797 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
798 testChange.call( this, e );
802 // Change has to be called before submit
803 // Keydown will be called before keypress, which is used in submit-event delegation
804 keydown: function( e ) {
805 var elem = e.target, type = elem.type;
807 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
808 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
809 type === "select-multiple" ) {
810 testChange.call( this, e );
814 // Beforeactivate happens also before the previous element is blurred
815 // with this event you can't trigger a change event, but you can store
817 beforeactivate: function( e ) {
819 jQuery._data( elem, "_change_data", getVal(elem) );
823 setup: function( data, namespaces ) {
824 if ( this.type === "file" ) {
828 for ( var type in changeFilters ) {
829 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
832 return rformElems.test( this.nodeName );
835 teardown: function( namespaces ) {
836 jQuery.event.remove( this, ".specialChange" );
838 return rformElems.test( this.nodeName );
842 changeFilters = jQuery.event.special.change.filters;
844 // Handle when the input is .focus()'d
845 changeFilters.focus = changeFilters.beforeactivate;
848 function trigger( type, elem, args ) {
849 // Piggyback on a donor event to simulate a different one.
850 // Fake originalEvent to avoid donor's stopPropagation, but if the
851 // simulated event prevents default then we do the same on the donor.
852 // Don't pass args or remember liveFired; they apply to the donor event.
853 var event = jQuery.extend( {}, args[ 0 ] );
855 event.originalEvent = {};
856 event.liveFired = undefined;
857 jQuery.event.handle.call( elem, event );
858 if ( event.isDefaultPrevented() ) {
859 args[ 0 ].preventDefault();
863 // Create "bubbling" focus and blur events
864 if ( document.addEventListener ) {
865 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
866 jQuery.event.special[ fix ] = {
868 this.addEventListener( orig, handler, true );
870 teardown: function() {
871 this.removeEventListener( orig, handler, true );
875 function handler( e ) {
876 e = jQuery.event.fix( e );
878 return jQuery.event.handle.call( this, e );
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,
967 // link all the functions, so any of them can unbind this click handler
968 while ( i < args.length ) {
969 jQuery.proxy( fn, args[ i++ ] );
972 return this.click( jQuery.proxy( fn, function( event ) {
973 // Figure out which function to execute
974 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
975 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
977 // Make sure that clicks stop
978 event.preventDefault();
980 // and execute the function
981 return args[ lastToggle ].apply( this, arguments ) || false;
985 hover: function( fnOver, fnOut ) {
986 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
993 mouseenter: "mouseover",
994 mouseleave: "mouseout"
997 jQuery.each(["live", "die"], function( i, name ) {
998 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
999 var type, i = 0, match, namespaces, preType,
1000 selector = origSelector || this.selector,
1001 context = origSelector ? this : jQuery( this.context );
1003 if ( typeof types === "object" && !types.preventDefault ) {
1004 for ( var key in types ) {
1005 context[ name ]( key, data, types[key], selector );
1011 if ( jQuery.isFunction( data ) ) {
1016 types = (types || "").split(" ");
1018 while ( (type = types[ i++ ]) != null ) {
1019 match = rnamespaces.exec( type );
1023 namespaces = match[0];
1024 type = type.replace( rnamespaces, "" );
1027 if ( type === "hover" ) {
1028 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1034 if ( type === "focus" || type === "blur" ) {
1035 types.push( liveMap[ type ] + namespaces );
1036 type = type + namespaces;
1039 type = (liveMap[ type ] || type) + namespaces;
1042 if ( name === "live" ) {
1043 // bind live handler
1044 for ( var j = 0, l = context.length; j < l; j++ ) {
1045 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1046 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1050 // unbind live handler
1051 context.unbind( "live." + liveConvert( type, selector ), fn );
1059 function liveHandler( event ) {
1060 var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1063 events = jQuery._data( this, "events" );
1065 // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1066 if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1070 if ( event.namespace ) {
1071 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1074 event.liveFired = this;
1076 var live = events.live.slice(0);
1078 for ( j = 0; j < live.length; j++ ) {
1079 handleObj = live[j];
1081 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1082 selectors.push( handleObj.selector );
1085 live.splice( j--, 1 );
1089 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1091 for ( i = 0, l = match.length; i < l; i++ ) {
1094 for ( j = 0; j < live.length; j++ ) {
1095 handleObj = live[j];
1097 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1101 // Those two events require additional checking
1102 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1103 event.type = handleObj.preType;
1104 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1107 if ( !related || related !== elem ) {
1108 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1114 for ( i = 0, l = elems.length; i < l; i++ ) {
1117 if ( maxLevel && match.level > maxLevel ) {
1121 event.currentTarget = match.elem;
1122 event.data = match.handleObj.data;
1123 event.handleObj = match.handleObj;
1125 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1127 if ( ret === false || event.isPropagationStopped() ) {
1128 maxLevel = match.level;
1130 if ( ret === false ) {
1133 if ( event.isImmediatePropagationStopped() ) {
1142 function liveConvert( type, selector ) {
1143 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1146 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1147 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1148 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1150 // Handle event binding
1151 jQuery.fn[ name ] = function( data, fn ) {
1157 return arguments.length > 0 ?
1158 this.bind( name, data, fn ) :
1159 this.trigger( name );
1162 if ( jQuery.attrFn ) {
1163 jQuery.attrFn[ name ] = true;