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;
36 var handleObjIn, handleObj;
38 if ( handler.handler ) {
39 handleObjIn = handler;
40 handler = handleObjIn.handler;
43 // Make sure that the function being executed has a unique ID
44 if ( !handler.guid ) {
45 handler.guid = jQuery.guid++;
48 // Init the element's event structure
49 var elemData = jQuery.data( elem );
51 // If no elemData is found then we must be trying to bind to one of the
52 // banned noData elements
57 var events = elemData.events,
58 eventHandle = elemData.handle;
60 if ( typeof events === "function" ) {
61 // On plain objects events is a fn that holds the the data
62 // which prevents this data from being JSON serialized
63 // the function does not need to be called, it just contains the data
64 eventHandle = events.handle;
65 events = events.events;
67 } else if ( !events ) {
68 if ( !elem.nodeType ) {
69 // On plain objects, create a fn that acts as the holder
70 // of the values to avoid JSON serialization of event data
71 elemData.events = elemData = function(){};
74 elemData.events = events = {};
78 elemData.handle = eventHandle = function() {
79 // Handle the second event of a trigger and when
80 // an event is called after a page has unloaded
81 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
82 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
87 // Add elem as a property of the handle function
88 // This is to prevent a memory leak with non-native events in IE.
89 eventHandle.elem = elem;
91 // Handle multiple events separated by a space
92 // jQuery(...).bind("mouseover mouseout", fn);
93 types = types.split(" ");
95 var type, i = 0, namespaces;
97 while ( (type = types[ i++ ]) ) {
98 handleObj = handleObjIn ?
99 jQuery.extend({}, handleObjIn) :
100 { handler: handler, data: data };
102 // Namespaced event handlers
103 if ( type.indexOf(".") > -1 ) {
104 namespaces = type.split(".");
105 type = namespaces.shift();
106 handleObj.namespace = namespaces.slice(0).sort().join(".");
110 handleObj.namespace = "";
113 handleObj.type = type;
114 if ( !handleObj.guid ) {
115 handleObj.guid = handler.guid;
118 // Get the current list of functions bound to this event
119 var handlers = events[ type ],
120 special = jQuery.event.special[ type ] || {};
122 // Init the event handler queue
124 handlers = events[ type ] = [];
126 // Check for a special event handler
127 // Only use addEventListener/attachEvent if the special
128 // events handler returns false
129 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
130 // Bind the global event handler to the element
131 if ( elem.addEventListener ) {
132 elem.addEventListener( type, eventHandle, false );
134 } else if ( elem.attachEvent ) {
135 elem.attachEvent( "on" + type, eventHandle );
141 special.add.call( elem, handleObj );
143 if ( !handleObj.handler.guid ) {
144 handleObj.handler.guid = handler.guid;
148 // Add the function to the element's handler list
149 handlers.push( handleObj );
151 // Keep track of which events have been used, for global triggering
152 jQuery.event.global[ type ] = true;
155 // Nullify elem to prevent memory leaks in IE
161 // Detach an event or set of events from an element
162 remove: function( elem, types, handler, pos ) {
163 // don't do events on text and comment nodes
164 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
168 if ( handler === false ) {
169 handler = returnFalse;
172 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
173 elemData = jQuery.data( elem ),
174 events = elemData && elemData.events;
176 if ( !elemData || !events ) {
180 if ( typeof events === "function" ) {
182 events = events.events;
185 // types is actually an event object here
186 if ( types && types.type ) {
187 handler = types.handler;
191 // Unbind all events for the element
192 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
195 for ( type in events ) {
196 jQuery.event.remove( elem, type + types );
202 // Handle multiple events separated by a space
203 // jQuery(...).unbind("mouseover mouseout", fn);
204 types = types.split(" ");
206 while ( (type = types[ i++ ]) ) {
209 all = type.indexOf(".") < 0;
213 // Namespaced event handlers
214 namespaces = type.split(".");
215 type = namespaces.shift();
217 namespace = new RegExp("(^|\\.)" +
218 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
221 eventType = events[ type ];
228 for ( j = 0; j < eventType.length; j++ ) {
229 handleObj = eventType[ j ];
231 if ( all || namespace.test( handleObj.namespace ) ) {
232 jQuery.event.remove( elem, origType, handleObj.handler, j );
233 eventType.splice( j--, 1 );
240 special = jQuery.event.special[ type ] || {};
242 for ( j = pos || 0; j < eventType.length; j++ ) {
243 handleObj = eventType[ j ];
245 if ( handler.guid === handleObj.guid ) {
246 // remove the given handler for the given type
247 if ( all || namespace.test( handleObj.namespace ) ) {
249 eventType.splice( j--, 1 );
252 if ( special.remove ) {
253 special.remove.call( elem, handleObj );
263 // remove generic event handler if no more handlers exist
264 if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
265 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
266 jQuery.removeEvent( elem, type, elemData.handle );
270 delete events[ type ];
274 // Remove the expando if it's no longer used
275 if ( jQuery.isEmptyObject( events ) ) {
276 var handle = elemData.handle;
281 delete elemData.events;
282 delete elemData.handle;
284 if ( typeof elemData === "function" ) {
287 } else if ( jQuery.isEmptyObject( elemData ) ) {
288 jQuery.removeData( elem );
293 // bubbling is internal
294 trigger: function( event, data, elem /*, bubbling */ ) {
295 // Event object or event type
296 var type = event.type || event,
297 bubbling = arguments[3];
300 event = typeof event === "object" ?
301 // jQuery.Event object
302 event[ jQuery.expando ] ? event :
304 jQuery.extend( jQuery.Event(type), event ) :
305 // Just the event type (string)
308 if ( type.indexOf("!") >= 0 ) {
309 event.type = type = type.slice(0, -1);
310 event.exclusive = true;
313 // Handle a global trigger
315 // Don't bubble custom events when global (to avoid too much overhead)
316 event.stopPropagation();
318 // Only trigger if we've ever bound an event for it
319 if ( jQuery.event.global[ type ] ) {
320 jQuery.each( jQuery.cache, function() {
321 if ( this.events && this.events[type] ) {
322 jQuery.event.trigger( event, data, this.handle.elem );
328 // Handle triggering a single element
330 // don't do events on text and comment nodes
331 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
335 // Clean up in case it is reused
336 event.result = undefined;
339 // Clone the incoming data, if any
340 data = jQuery.makeArray( data );
341 data.unshift( event );
344 event.currentTarget = elem;
346 // Trigger the event, it is assumed that "handle" is a function
347 var handle = elem.nodeType ?
348 jQuery.data( elem, "handle" ) :
349 elem.events && elem.events.handle;
352 handle.apply( elem, data );
355 var parent = elem.parentNode || elem.ownerDocument;
357 // Trigger an inline bound script
359 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
360 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
361 event.result = false;
362 event.preventDefault();
366 // prevent IE from throwing an error for some elements with some event types, see #3533
367 } catch (inlineError) {}
369 if ( !event.isPropagationStopped() && parent ) {
370 jQuery.event.trigger( event, data, parent, true );
372 } else if ( !event.isDefaultPrevented() ) {
373 var target = event.target, old, targetType = type.replace(rnamespaces, ""),
374 isClick = jQuery.nodeName(target, "a") && targetType === "click",
375 special = jQuery.event.special[ targetType ] || {};
377 if ( (!special._default || special._default.call( elem, event ) === false) &&
378 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
381 if ( target[ targetType ] ) {
382 // Make sure that we don't accidentally re-trigger the onFOO events
383 old = target[ "on" + targetType ];
386 target[ "on" + targetType ] = null;
389 jQuery.event.triggered = true;
390 target[ targetType ]();
393 // prevent IE from throwing an error for some elements with some event types, see #3533
394 } catch (triggerError) {}
397 target[ "on" + targetType ] = old;
400 jQuery.event.triggered = false;
405 handle: function( event ) {
406 var all, handlers, namespaces, namespace_sort = [], namespace_re, events, args = jQuery.makeArray( arguments );
408 event = args[0] = jQuery.event.fix( event || window.event );
409 event.currentTarget = this;
411 // Namespaced event handlers
412 all = event.type.indexOf(".") < 0 && !event.exclusive;
415 namespaces = event.type.split(".");
416 event.type = namespaces.shift();
417 namespace_sort = namespaces.slice(0).sort();
418 namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
421 event.namespace = event.namespace || namespace_sort.join(".");
423 events = jQuery.data(this, "events");
425 if ( typeof events === "function" ) {
426 events = events.events;
429 handlers = (events || {})[ event.type ];
431 if ( events && handlers ) {
432 // Clone the handlers to prevent manipulation
433 handlers = handlers.slice(0);
435 for ( var j = 0, l = handlers.length; j < l; j++ ) {
436 var handleObj = handlers[ j ];
438 // Filter the functions by class
439 if ( all || namespace_re.test( handleObj.namespace ) ) {
440 // Pass in a reference to the handler function itself
441 // So that we can later remove it
442 event.handler = handleObj.handler;
443 event.data = handleObj.data;
444 event.handleObj = handleObj;
446 var ret = handleObj.handler.apply( this, args );
448 if ( ret !== undefined ) {
450 if ( ret === false ) {
451 event.preventDefault();
452 event.stopPropagation();
456 if ( event.isImmediatePropagationStopped() ) {
466 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(" "),
468 fix: function( event ) {
469 if ( event[ jQuery.expando ] ) {
473 // store a copy of the original event object
474 // and "clone" to set read-only properties
475 var originalEvent = event;
476 event = jQuery.Event( originalEvent );
478 for ( var i = this.props.length, prop; i; ) {
479 prop = this.props[ --i ];
480 event[ prop ] = originalEvent[ prop ];
483 // Fix target property, if necessary
484 if ( !event.target ) {
485 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
488 // check if target is a textnode (safari)
489 if ( event.target.nodeType === 3 ) {
490 event.target = event.target.parentNode;
493 // Add relatedTarget, if necessary
494 if ( !event.relatedTarget && event.fromElement ) {
495 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
498 // Calculate pageX/Y if missing and clientX/Y available
499 if ( event.pageX == null && event.clientX != null ) {
500 var doc = document.documentElement, body = document.body;
501 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
502 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
505 // Add which for key events
506 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
507 event.which = event.charCode != null ? event.charCode : event.keyCode;
510 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
511 if ( !event.metaKey && event.ctrlKey ) {
512 event.metaKey = event.ctrlKey;
515 // Add which for click: 1 === left; 2 === middle; 3 === right
516 // Note: button is not normalized, so don't use it
517 if ( !event.which && event.button !== undefined ) {
518 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
524 // Deprecated, use jQuery.guid instead
527 // Deprecated, use jQuery.proxy instead
532 // Make sure the ready event is setup
533 setup: jQuery.bindReady,
534 teardown: jQuery.noop
538 add: function( handleObj ) {
539 jQuery.event.add( this,
540 liveConvert( handleObj.origType, handleObj.selector ),
541 jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
544 remove: function( handleObj ) {
545 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
550 setup: function( data, namespaces, eventHandle ) {
551 // We only want to do this special case on windows
552 if ( jQuery.isWindow( this ) ) {
553 this.onbeforeunload = eventHandle;
557 teardown: function( namespaces, eventHandle ) {
558 if ( this.onbeforeunload === eventHandle ) {
559 this.onbeforeunload = null;
566 jQuery.removeEvent = document.removeEventListener ?
567 function( elem, type, handle ) {
568 if ( elem.removeEventListener ) {
569 elem.removeEventListener( type, handle, false );
572 function( elem, type, handle ) {
573 if ( elem.detachEvent ) {
574 elem.detachEvent( "on" + type, handle );
578 jQuery.Event = function( src ) {
579 // Allow instantiation without the 'new' keyword
580 if ( !this.preventDefault ) {
581 return new jQuery.Event( src );
585 if ( src && src.type ) {
586 this.originalEvent = src;
587 this.type = src.type;
593 // timeStamp is buggy for some events on Firefox(#3843)
594 // So we won't rely on the native value
595 this.timeStamp = jQuery.now();
598 this[ jQuery.expando ] = true;
601 function returnFalse() {
604 function returnTrue() {
608 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
609 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
610 jQuery.Event.prototype = {
611 preventDefault: function() {
612 this.isDefaultPrevented = returnTrue;
614 var e = this.originalEvent;
619 // if preventDefault exists run it on the original event
620 if ( e.preventDefault ) {
623 // otherwise set the returnValue property of the original event to false (IE)
625 e.returnValue = false;
628 stopPropagation: function() {
629 this.isPropagationStopped = returnTrue;
631 var e = this.originalEvent;
635 // if stopPropagation exists run it on the original event
636 if ( e.stopPropagation ) {
639 // otherwise set the cancelBubble property of the original event to true (IE)
640 e.cancelBubble = true;
642 stopImmediatePropagation: function() {
643 this.isImmediatePropagationStopped = returnTrue;
644 this.stopPropagation();
646 isDefaultPrevented: returnFalse,
647 isPropagationStopped: returnFalse,
648 isImmediatePropagationStopped: returnFalse
651 // Checks if an event happened on an element within another element
652 // Used in jQuery.event.special.mouseenter and mouseleave handlers
653 var withinElement = function( event ) {
654 // Check if mouse(over|out) are still within the same parent element
655 var parent = event.relatedTarget;
657 // Firefox sometimes assigns relatedTarget a XUL element
658 // which we cannot access the parentNode property of
660 // Traverse up the tree
661 while ( parent && parent !== this ) {
662 parent = parent.parentNode;
665 if ( parent !== this ) {
666 // set the correct event type
667 event.type = event.data;
669 // handle event if we actually just moused on to a non sub-element
670 jQuery.event.handle.apply( this, arguments );
673 // assuming we've left the element since we most likely mousedover a xul element
677 // In case of event delegation, we only need to rename the event.type,
678 // liveHandler will take care of the rest.
679 delegate = function( event ) {
680 event.type = event.data;
681 jQuery.event.handle.apply( this, arguments );
684 // Create mouseenter and mouseleave events
686 mouseenter: "mouseover",
687 mouseleave: "mouseout"
688 }, function( orig, fix ) {
689 jQuery.event.special[ orig ] = {
690 setup: function( data ) {
691 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
693 teardown: function( data ) {
694 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
700 if ( !jQuery.support.submitBubbles ) {
702 jQuery.event.special.submit = {
703 setup: function( data, namespaces ) {
704 if ( this.nodeName.toLowerCase() !== "form" ) {
705 jQuery.event.add(this, "click.specialSubmit", function( e ) {
706 var elem = e.target, type = elem.type;
708 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
709 e.liveFired = undefined;
710 return trigger( "submit", this, arguments );
714 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
715 var elem = e.target, type = elem.type;
717 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
718 e.liveFired = undefined;
719 return trigger( "submit", this, arguments );
728 teardown: function( namespaces ) {
729 jQuery.event.remove( this, ".specialSubmit" );
735 // change delegation, happens here so we have bind.
736 if ( !jQuery.support.changeBubbles ) {
740 getVal = function( elem ) {
741 var type = elem.type, val = elem.value;
743 if ( type === "radio" || type === "checkbox" ) {
746 } else if ( type === "select-multiple" ) {
747 val = elem.selectedIndex > -1 ?
748 jQuery.map( elem.options, function( elem ) {
749 return elem.selected;
753 } else if ( elem.nodeName.toLowerCase() === "select" ) {
754 val = elem.selectedIndex;
760 testChange = function testChange( e ) {
761 var elem = e.target, data, val;
763 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
767 data = jQuery.data( elem, "_change_data" );
770 // the current data will be also retrieved by beforeactivate
771 if ( e.type !== "focusout" || elem.type !== "radio" ) {
772 jQuery.data( elem, "_change_data", val );
775 if ( data === undefined || val === data ) {
779 if ( data != null || val ) {
781 e.liveFired = undefined;
782 return jQuery.event.trigger( e, arguments[1], elem );
786 jQuery.event.special.change = {
788 focusout: testChange,
790 click: function( e ) {
791 var elem = e.target, type = elem.type;
793 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
794 return testChange.call( this, e );
798 // Change has to be called before submit
799 // Keydown will be called before keypress, which is used in submit-event delegation
800 keydown: function( e ) {
801 var elem = e.target, type = elem.type;
803 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
804 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
805 type === "select-multiple" ) {
806 return testChange.call( this, e );
810 // Beforeactivate happens also before the previous element is blurred
811 // with this event you can't trigger a change event, but you can store
812 // information/focus[in] is not needed anymore
813 beforeactivate: function( e ) {
815 jQuery.data( elem, "_change_data", getVal(elem) );
819 setup: function( data, namespaces ) {
820 if ( this.type === "file" ) {
824 for ( var type in changeFilters ) {
825 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
828 return rformElems.test( this.nodeName );
831 teardown: function( namespaces ) {
832 jQuery.event.remove( this, ".specialChange" );
834 return rformElems.test( this.nodeName );
838 changeFilters = jQuery.event.special.change.filters;
841 function trigger( type, elem, args ) {
843 return jQuery.event.handle.apply( elem, args );
846 // Create "bubbling" focus and blur events
847 if ( document.addEventListener ) {
848 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
849 jQuery.event.special[ fix ] = {
851 this.addEventListener( orig, handler, true );
853 teardown: function() {
854 this.removeEventListener( orig, handler, true );
858 function handler( e ) {
859 e = jQuery.event.fix( e );
861 return jQuery.event.handle.call( this, e );
866 jQuery.each(["bind", "one"], function( i, name ) {
867 jQuery.fn[ name ] = function( type, data, fn ) {
868 // Handle object literals
869 if ( typeof type === "object" ) {
870 for ( var key in type ) {
871 this[ name ](key, data, type[key], fn);
876 if ( jQuery.isFunction( data ) || data === false ) {
881 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
882 jQuery( this ).unbind( event, handler );
883 return fn.apply( this, arguments );
886 if ( type === "unload" && name !== "one" ) {
887 this.one( type, data, fn );
890 for ( var i = 0, l = this.length; i < l; i++ ) {
891 jQuery.event.add( this[i], type, handler, data );
900 unbind: function( type, fn ) {
901 // Handle object literals
902 if ( typeof type === "object" && !type.preventDefault ) {
903 for ( var key in type ) {
904 this.unbind(key, type[key]);
908 for ( var i = 0, l = this.length; i < l; i++ ) {
909 jQuery.event.remove( this[i], type, fn );
916 delegate: function( selector, types, data, fn ) {
917 return this.live( types, data, fn, selector );
920 undelegate: function( selector, types, fn ) {
921 if ( arguments.length === 0 ) {
922 return this.unbind( "live" );
925 return this.die( types, null, fn, selector );
929 trigger: function( type, data ) {
930 return this.each(function() {
931 jQuery.event.trigger( type, data, this );
935 triggerHandler: function( type, data ) {
937 var event = jQuery.Event( type );
938 event.preventDefault();
939 event.stopPropagation();
940 jQuery.event.trigger( event, data, this[0] );
945 toggle: function( fn ) {
946 // Save reference to arguments for access in closure
947 var args = arguments, i = 1;
949 // link all the functions, so any of them can unbind this click handler
950 while ( i < args.length ) {
951 jQuery.proxy( fn, args[ i++ ] );
954 return this.click( jQuery.proxy( fn, function( event ) {
955 // Figure out which function to execute
956 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
957 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
959 // Make sure that clicks stop
960 event.preventDefault();
962 // and execute the function
963 return args[ lastToggle ].apply( this, arguments ) || false;
967 hover: function( fnOver, fnOut ) {
968 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
975 mouseenter: "mouseover",
976 mouseleave: "mouseout"
979 jQuery.each(["live", "die"], function( i, name ) {
980 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
981 var type, i = 0, match, namespaces, preType,
982 selector = origSelector || this.selector,
983 context = origSelector ? this : jQuery( this.context );
985 if ( typeof types === "object" && !types.preventDefault ) {
986 for ( var key in types ) {
987 context[ name ]( key, data, types[key], selector );
993 if ( jQuery.isFunction( data ) ) {
998 types = (types || "").split(" ");
1000 while ( (type = types[ i++ ]) != null ) {
1001 match = rnamespaces.exec( type );
1005 namespaces = match[0];
1006 type = type.replace( rnamespaces, "" );
1009 if ( type === "hover" ) {
1010 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1016 if ( type === "focus" || type === "blur" ) {
1017 types.push( liveMap[ type ] + namespaces );
1018 type = type + namespaces;
1021 type = (liveMap[ type ] || type) + namespaces;
1024 if ( name === "live" ) {
1025 // bind live handler
1026 for ( var j = 0, l = context.length; j < l; j++ ) {
1027 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1028 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1032 // unbind live handler
1033 context.unbind( "live." + liveConvert( type, selector ), fn );
1041 function liveHandler( event ) {
1042 var stop, maxLevel, elems = [], selectors = [],
1043 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1044 events = jQuery.data( this, "events" );
1046 if ( typeof events === "function" ) {
1047 events = events.events;
1050 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1051 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1055 if ( event.namespace ) {
1056 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1059 event.liveFired = this;
1061 var live = events.live.slice(0);
1063 for ( j = 0; j < live.length; j++ ) {
1064 handleObj = live[j];
1066 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1067 selectors.push( handleObj.selector );
1070 live.splice( j--, 1 );
1074 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1076 for ( i = 0, l = match.length; i < l; i++ ) {
1079 for ( j = 0; j < live.length; j++ ) {
1080 handleObj = live[j];
1082 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1086 // Those two events require additional checking
1087 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1088 event.type = handleObj.preType;
1089 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1092 if ( !related || related !== elem ) {
1093 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1099 for ( i = 0, l = elems.length; i < l; i++ ) {
1102 if ( maxLevel && match.level > maxLevel ) {
1106 event.currentTarget = match.elem;
1107 event.data = match.handleObj.data;
1108 event.handleObj = match.handleObj;
1110 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1112 if ( ret === false || event.isPropagationStopped() ) {
1113 maxLevel = match.level;
1115 if ( ret === false ) {
1124 function liveConvert( type, selector ) {
1125 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1128 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1129 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1130 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1132 // Handle event binding
1133 jQuery.fn[ name ] = function( data, fn ) {
1139 return arguments.length > 0 ?
1140 this.bind( name, data, fn ) :
1141 this.trigger( name );
1144 if ( jQuery.attrFn ) {
1145 jQuery.attrFn[ name ] = true;
1149 // Prevent memory leaks in IE
1150 // Window isn't included so as not to unbind existing unload events
1152 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1153 if ( window.attachEvent && !window.addEventListener ) {
1154 window.attachEvent("onunload", function() {
1155 for ( var id in jQuery.cache ) {
1156 if ( jQuery.cache[ id ].handle ) {
1157 // Try/Catch is to handle iframes being unloaded, see #4280
1159 jQuery.event.remove( jQuery.cache[ id ].handle.elem );