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
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;
840 // Handle when the input is .focus()'d
841 changeFilters.focus = changeFilters.beforeactivate;
844 function trigger( type, elem, args ) {
846 return jQuery.event.handle.apply( elem, args );
849 // Create "bubbling" focus and blur events
850 if ( document.addEventListener ) {
851 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
852 jQuery.event.special[ fix ] = {
854 this.addEventListener( orig, handler, true );
856 teardown: function() {
857 this.removeEventListener( orig, handler, true );
861 function handler( e ) {
862 e = jQuery.event.fix( e );
864 return jQuery.event.handle.call( this, e );
869 jQuery.each(["bind", "one"], function( i, name ) {
870 jQuery.fn[ name ] = function( type, data, fn ) {
871 // Handle object literals
872 if ( typeof type === "object" ) {
873 for ( var key in type ) {
874 this[ name ](key, data, type[key], fn);
879 if ( jQuery.isFunction( data ) || data === false ) {
884 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
885 jQuery( this ).unbind( event, handler );
886 return fn.apply( this, arguments );
889 if ( type === "unload" && name !== "one" ) {
890 this.one( type, data, fn );
893 for ( var i = 0, l = this.length; i < l; i++ ) {
894 jQuery.event.add( this[i], type, handler, data );
903 unbind: function( type, fn ) {
904 // Handle object literals
905 if ( typeof type === "object" && !type.preventDefault ) {
906 for ( var key in type ) {
907 this.unbind(key, type[key]);
911 for ( var i = 0, l = this.length; i < l; i++ ) {
912 jQuery.event.remove( this[i], type, fn );
919 delegate: function( selector, types, data, fn ) {
920 return this.live( types, data, fn, selector );
923 undelegate: function( selector, types, fn ) {
924 if ( arguments.length === 0 ) {
925 return this.unbind( "live" );
928 return this.die( types, null, fn, selector );
932 trigger: function( type, data ) {
933 return this.each(function() {
934 jQuery.event.trigger( type, data, this );
938 triggerHandler: function( type, data ) {
940 var event = jQuery.Event( type );
941 event.preventDefault();
942 event.stopPropagation();
943 jQuery.event.trigger( event, data, this[0] );
948 toggle: function( fn ) {
949 // Save reference to arguments for access in closure
950 var args = arguments, i = 1;
952 // link all the functions, so any of them can unbind this click handler
953 while ( i < args.length ) {
954 jQuery.proxy( fn, args[ i++ ] );
957 return this.click( jQuery.proxy( fn, function( event ) {
958 // Figure out which function to execute
959 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
960 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
962 // Make sure that clicks stop
963 event.preventDefault();
965 // and execute the function
966 return args[ lastToggle ].apply( this, arguments ) || false;
970 hover: function( fnOver, fnOut ) {
971 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
978 mouseenter: "mouseover",
979 mouseleave: "mouseout"
982 jQuery.each(["live", "die"], function( i, name ) {
983 jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
984 var type, i = 0, match, namespaces, preType,
985 selector = origSelector || this.selector,
986 context = origSelector ? this : jQuery( this.context );
988 if ( typeof types === "object" && !types.preventDefault ) {
989 for ( var key in types ) {
990 context[ name ]( key, data, types[key], selector );
996 if ( jQuery.isFunction( data ) ) {
1001 types = (types || "").split(" ");
1003 while ( (type = types[ i++ ]) != null ) {
1004 match = rnamespaces.exec( type );
1008 namespaces = match[0];
1009 type = type.replace( rnamespaces, "" );
1012 if ( type === "hover" ) {
1013 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1019 if ( type === "focus" || type === "blur" ) {
1020 types.push( liveMap[ type ] + namespaces );
1021 type = type + namespaces;
1024 type = (liveMap[ type ] || type) + namespaces;
1027 if ( name === "live" ) {
1028 // bind live handler
1029 for ( var j = 0, l = context.length; j < l; j++ ) {
1030 jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1031 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1035 // unbind live handler
1036 context.unbind( "live." + liveConvert( type, selector ), fn );
1044 function liveHandler( event ) {
1045 var stop, maxLevel, elems = [], selectors = [],
1046 related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1047 events = jQuery.data( this, "events" );
1049 if ( typeof events === "function" ) {
1050 events = events.events;
1053 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
1054 if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
1058 if ( event.namespace ) {
1059 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1062 event.liveFired = this;
1064 var live = events.live.slice(0);
1066 for ( j = 0; j < live.length; j++ ) {
1067 handleObj = live[j];
1069 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1070 selectors.push( handleObj.selector );
1073 live.splice( j--, 1 );
1077 match = jQuery( event.target ).closest( selectors, event.currentTarget );
1079 for ( i = 0, l = match.length; i < l; i++ ) {
1082 for ( j = 0; j < live.length; j++ ) {
1083 handleObj = live[j];
1085 if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1089 // Those two events require additional checking
1090 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1091 event.type = handleObj.preType;
1092 related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1095 if ( !related || related !== elem ) {
1096 elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1102 for ( i = 0, l = elems.length; i < l; i++ ) {
1105 if ( maxLevel && match.level > maxLevel ) {
1109 event.currentTarget = match.elem;
1110 event.data = match.handleObj.data;
1111 event.handleObj = match.handleObj;
1113 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1115 if ( ret === false || event.isPropagationStopped() ) {
1116 maxLevel = match.level;
1118 if ( ret === false ) {
1127 function liveConvert( type, selector ) {
1128 return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1131 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1132 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1133 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1135 // Handle event binding
1136 jQuery.fn[ name ] = function( data, fn ) {
1142 return arguments.length > 0 ?
1143 this.bind( name, data, fn ) :
1144 this.trigger( name );
1147 if ( jQuery.attrFn ) {
1148 jQuery.attrFn[ name ] = true;
1152 // Prevent memory leaks in IE
1153 // Window isn't included so as not to unbind existing unload events
1155 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1156 if ( window.attachEvent && !window.addEventListener ) {
1157 window.attachEvent("onunload", function() {
1158 for ( var id in jQuery.cache ) {
1159 if ( jQuery.cache[ id ].handle ) {
1160 // Try/Catch is to handle iframes being unloaded, see #4280
1162 jQuery.event.remove( jQuery.cache[ id ].handle.elem );