1 var fcleanup = function( nm ) {
2 return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
8 * A number of helper functions used for managing events.
9 * Many of the ideas behind this code originated from
10 * Dean Edwards' addEvent library.
14 // Bind an event to an element
15 // Original by Dean Edwards
16 add: function( elem, types, handler, data ) {
17 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
21 // For whatever reason, IE has trouble passing the window object
22 // around, causing it to be cloned in the process
23 if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
27 // Make sure that the function being executed has a unique ID
28 if ( !handler.guid ) {
29 handler.guid = jQuery.guid++;
32 // if data is passed, bind to handler
33 if ( data !== undefined ) {
34 // Create temporary function pointer to original handler
37 // Create unique handler function, wrapped around original handler
38 handler = jQuery.proxy( fn );
40 // Store data in unique handler
44 // Init the element's event structure
45 var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
46 handle = jQuery.data( elem, "handle" ), eventHandle;
49 eventHandle = function() {
50 // Handle the second event of a trigger and when
51 // an event is called after a page has unloaded
52 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
53 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
57 handle = jQuery.data( elem, "handle", eventHandle );
60 // If no handle is found then we must be trying to bind to one of the
61 // banned noData elements
66 // Add elem as a property of the handle function
67 // This is to prevent a memory leak with non-native
71 // Handle multiple events separated by a space
72 // jQuery(...).bind("mouseover mouseout", fn);
73 types = types.split( /\s+/ );
75 while ( (type = types[ i++ ]) ) {
76 // Namespaced event handlers
77 var namespaces = type.split(".");
78 type = namespaces.shift();
79 handler.type = namespaces.slice(0).sort().join(".");
81 // Get the current list of functions bound to this event
82 var handlers = events[ type ],
83 special = this.special[ type ] || {};
87 // Init the event handler queue
89 handlers = events[ type ] = {};
91 // Check for a special event handler
92 // Only use addEventListener/attachEvent if the special
93 // events handler returns false
94 if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
95 // Bind the global event handler to the element
96 if ( elem.addEventListener ) {
97 elem.addEventListener( type, handle, false );
98 } else if ( elem.attachEvent ) {
99 elem.attachEvent( "on" + type, handle );
105 var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
106 if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
107 modifiedHandler.guid = modifiedHandler.guid || handler.guid;
108 handler = modifiedHandler;
112 // Add the function to the element's handler list
113 handlers[ handler.guid ] = handler;
115 // Keep track of which events have been used, for global triggering
116 this.global[ type ] = true;
119 // Nullify elem to prevent memory leaks in IE
125 // Detach an event or set of events from an element
126 remove: function( elem, types, handler ) {
127 // don't do events on text and comment nodes
128 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
132 var events = jQuery.data( elem, "events" ), ret, type, fn;
135 // Unbind all events for the element
136 if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
137 for ( type in events ) {
138 this.remove( elem, type + (types || "") );
141 // types is actually an event object here
143 handler = types.handler;
147 // Handle multiple events separated by a space
148 // jQuery(...).unbind("mouseover mouseout", fn);
149 types = types.split(/\s+/);
151 while ( (type = types[ i++ ]) ) {
152 // Namespaced event handlers
153 var namespaces = type.split(".");
154 type = namespaces.shift();
155 var all = !namespaces.length,
156 cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
157 namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
158 special = this.special[ type ] || {};
160 if ( events[ type ] ) {
161 // remove the given handler for the given type
163 fn = events[ type ][ handler.guid ];
164 delete events[ type ][ handler.guid ];
166 // remove all handlers for the given type
168 for ( var handle in events[ type ] ) {
169 // Handle the removal of namespaced events
170 if ( all || namespace.test( events[ type ][ handle ].type ) ) {
171 delete events[ type ][ handle ];
176 if ( special.remove ) {
177 special.remove.call( elem, namespaces, fn);
180 // remove generic event handler if no more handlers exist
181 for ( ret in events[ type ] ) {
185 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
186 if ( elem.removeEventListener ) {
187 elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
188 } else if ( elem.detachEvent ) {
189 elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
193 delete events[ type ];
199 // Remove the expando if it's no longer used
200 for ( ret in events ) {
204 var handle = jQuery.data( elem, "handle" );
208 jQuery.removeData( elem, "events" );
209 jQuery.removeData( elem, "handle" );
214 // bubbling is internal
215 trigger: function( event, data, elem /*, bubbling */ ) {
216 // Event object or event type
217 var type = event.type || event,
218 bubbling = arguments[3];
221 event = typeof event === "object" ?
222 // jQuery.Event object
223 event[expando] ? event :
225 jQuery.extend( jQuery.Event(type), event ) :
226 // Just the event type (string)
229 if ( type.indexOf("!") >= 0 ) {
230 event.type = type = type.slice(0, -1);
231 event.exclusive = true;
234 // Handle a global trigger
236 // Don't bubble custom events when global (to avoid too much overhead)
237 event.stopPropagation();
239 // Only trigger if we've ever bound an event for it
240 if ( this.global[ type ] ) {
241 jQuery.each( jQuery.cache, function() {
242 if ( this.events && this.events[type] ) {
243 jQuery.event.trigger( event, data, this.handle.elem );
249 // Handle triggering a single element
251 // don't do events on text and comment nodes
252 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
256 // Clean up in case it is reused
257 event.result = undefined;
260 // Clone the incoming data, if any
261 data = jQuery.makeArray( data );
262 data.unshift( event );
265 event.currentTarget = elem;
267 // Trigger the event, it is assumed that "handle" is a function
268 var handle = jQuery.data( elem, "handle" );
270 handle.apply( elem, data );
273 var parent = elem.parentNode || elem.ownerDocument;
275 // Trigger an inline bound script
277 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
278 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
279 event.result = false;
283 // prevent IE from throwing an error for some elements with some event types, see #3533
286 if ( !event.isPropagationStopped() && parent ) {
287 jQuery.event.trigger( event, data, parent, true );
289 } else if ( !event.isDefaultPrevented() ) {
290 var target = event.target, old,
291 isClick = jQuery.nodeName(target, "a") && type === "click";
293 if ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
295 if ( target[ type ] ) {
296 // Make sure that we don't accidentally re-trigger the onFOO events
297 old = target[ "on" + type ];
300 target[ "on" + type ] = null;
303 this.triggered = true;
307 // prevent IE from throwing an error for some elements with some event types, see #3533
311 target[ "on" + type ] = old;
314 this.triggered = false;
319 handle: function( event ) {
320 // returned undefined or false
323 event = arguments[0] = jQuery.event.fix( event || window.event );
324 event.currentTarget = this;
326 // Namespaced event handlers
327 var namespaces = event.type.split(".");
328 event.type = namespaces.shift();
330 // Cache this now, all = true means, any handler
331 all = !namespaces.length && !event.exclusive;
333 var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
335 handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
337 for ( var j in handlers ) {
338 var handler = handlers[ j ];
340 // Filter the functions by class
341 if ( all || namespace.test(handler.type) ) {
342 // Pass in a reference to the handler function itself
343 // So that we can later remove it
344 event.handler = handler;
345 event.data = handler.data;
347 var ret = handler.apply( this, arguments );
349 if ( ret !== undefined ) {
351 if ( ret === false ) {
352 event.preventDefault();
353 event.stopPropagation();
357 if ( event.isImmediatePropagationStopped() ) {
367 props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
369 fix: function( event ) {
370 if ( event[ expando ] ) {
374 // store a copy of the original event object
375 // and "clone" to set read-only properties
376 var originalEvent = event;
377 event = jQuery.Event( originalEvent );
379 for ( var i = this.props.length, prop; i; ) {
380 prop = this.props[ --i ];
381 event[ prop ] = originalEvent[ prop ];
384 // Fix target property, if necessary
385 if ( !event.target ) {
386 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
389 // check if target is a textnode (safari)
390 if ( event.target.nodeType === 3 ) {
391 event.target = event.target.parentNode;
394 // Add relatedTarget, if necessary
395 if ( !event.relatedTarget && event.fromElement ) {
396 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
399 // Calculate pageX/Y if missing and clientX/Y available
400 if ( event.pageX == null && event.clientX != null ) {
401 var doc = document.documentElement, body = document.body;
402 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
403 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
406 // Add which for key events
407 if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
408 event.which = event.charCode || event.keyCode;
411 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
412 if ( !event.metaKey && event.ctrlKey ) {
413 event.metaKey = event.ctrlKey;
416 // Add which for click: 1 === left; 2 === middle; 3 === right
417 // Note: button is not normalized, so don't use it
418 if ( !event.which && event.button !== undefined ) {
419 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
425 // Deprecated, use jQuery.guid instead
428 // Deprecated, use jQuery.proxy instead
433 // Make sure the ready event is setup
434 setup: jQuery.bindReady,
435 teardown: jQuery.noop
439 add: function( proxy, data, namespaces, live ) {
440 jQuery.extend( proxy, data || {} );
442 proxy.guid += data.selector + data.live;
443 data.liveProxy = proxy;
445 jQuery.event.add( this, data.live, liveHandler, data );
449 remove: function( namespaces ) {
450 if ( namespaces.length ) {
451 var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
453 jQuery.each( (jQuery.data(this, "events").live || {}), function() {
454 if ( name.test(this.type) ) {
460 jQuery.event.remove( this, namespaces[0], liveHandler );
467 setup: function( data, namespaces, fn ) {
468 // We only want to do this special case on windows
469 if ( this.setInterval ) {
470 this.onbeforeunload = fn;
475 teardown: function( namespaces, fn ) {
476 if ( this.onbeforeunload === fn ) {
477 this.onbeforeunload = null;
484 jQuery.Event = function( src ) {
485 // Allow instantiation without the 'new' keyword
486 if ( !this.preventDefault ) {
487 return new jQuery.Event( src );
491 if ( src && src.type ) {
492 this.originalEvent = src;
493 this.type = src.type;
499 // timeStamp is buggy for some events on Firefox(#3843)
500 // So we won't rely on the native value
501 this.timeStamp = now();
504 this[ expando ] = true;
507 function returnFalse() {
510 function returnTrue() {
514 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
515 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
516 jQuery.Event.prototype = {
517 preventDefault: function() {
518 this.isDefaultPrevented = returnTrue;
520 var e = this.originalEvent;
525 // if preventDefault exists run it on the original event
526 if ( e.preventDefault ) {
529 // otherwise set the returnValue property of the original event to false (IE)
530 e.returnValue = false;
532 stopPropagation: function() {
533 this.isPropagationStopped = returnTrue;
535 var e = this.originalEvent;
539 // if stopPropagation exists run it on the original event
540 if ( e.stopPropagation ) {
543 // otherwise set the cancelBubble property of the original event to true (IE)
544 e.cancelBubble = true;
546 stopImmediatePropagation: function() {
547 this.isImmediatePropagationStopped = returnTrue;
548 this.stopPropagation();
550 isDefaultPrevented: returnFalse,
551 isPropagationStopped: returnFalse,
552 isImmediatePropagationStopped: returnFalse
555 // Checks if an event happened on an element within another element
556 // Used in jQuery.event.special.mouseenter and mouseleave handlers
557 var withinElement = function( event ) {
558 // Check if mouse(over|out) are still within the same parent element
559 var parent = event.relatedTarget;
561 // Traverse up the tree
562 while ( parent && parent !== this ) {
563 // Firefox sometimes assigns relatedTarget a XUL element
564 // which we cannot access the parentNode property of
566 parent = parent.parentNode;
568 // assuming we've left the element since we most likely mousedover a xul element
574 if ( parent !== this ) {
575 // set the correct event type
576 event.type = event.data;
578 // handle event if we actually just moused on to a non sub-element
579 jQuery.event.handle.apply( this, arguments );
584 // In case of event delegation, we only need to rename the event.type,
585 // liveHandler will take care of the rest.
586 delegate = function( event ) {
587 event.type = event.data;
588 jQuery.event.handle.apply( this, arguments );
591 // Create mouseenter and mouseleave events
593 mouseenter: "mouseover",
594 mouseleave: "mouseout"
595 }, function( orig, fix ) {
596 jQuery.event.special[ orig ] = {
597 setup: function( data ) {
598 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
600 teardown: function( data ) {
601 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
607 if ( !jQuery.support.submitBubbles ) {
609 jQuery.event.special.submit = {
610 setup: function( data, namespaces, fn ) {
611 if ( this.nodeName.toLowerCase() !== "form" ) {
612 jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
613 var elem = e.target, type = elem.type;
615 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
616 return trigger( "submit", this, arguments );
620 jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
621 var elem = e.target, type = elem.type;
623 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
624 return trigger( "submit", this, arguments );
633 remove: function( namespaces, fn ) {
634 jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
635 jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
641 // change delegation, happens here so we have bind.
642 if ( !jQuery.support.changeBubbles ) {
644 var formElems = /textarea|input|select/i;
646 function getVal( elem ) {
647 var type = elem.type, val = elem.value;
649 if ( type === "radio" || type === "checkbox" ) {
652 } else if ( type === "select-multiple" ) {
653 val = elem.selectedIndex > -1 ?
654 jQuery.map( elem.options, function( elem ) {
655 return elem.selected;
659 } else if ( elem.nodeName.toLowerCase() === "select" ) {
660 val = elem.selectedIndex;
666 function testChange( e ) {
667 var elem = e.target, data, val;
669 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
673 data = jQuery.data( elem, "_change_data" );
676 // the current data will be also retrieved by beforeactivate
677 if ( e.type !== "focusout" || elem.type !== "radio" ) {
678 jQuery.data( elem, "_change_data", val );
681 if ( data === undefined || val === data ) {
685 if ( data != null || val ) {
687 return jQuery.event.trigger( e, arguments[1], elem );
691 jQuery.event.special.change = {
693 focusout: testChange,
695 click: function( e ) {
696 var elem = e.target, type = elem.type;
698 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
699 return testChange.call( this, e );
703 // Change has to be called before submit
704 // Keydown will be called before keypress, which is used in submit-event delegation
705 keydown: function( e ) {
706 var elem = e.target, type = elem.type;
708 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
709 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
710 type === "select-multiple" ) {
711 return testChange.call( this, e );
715 // Beforeactivate happens also before the previous element is blurred
716 // with this event you can't trigger a change event, but you can store
717 // information/focus[in] is not needed anymore
718 beforeactivate: function( e ) {
721 if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
722 jQuery.data( elem, "_change_data", getVal(elem) );
726 setup: function( data, namespaces, fn ) {
727 for ( var type in changeFilters ) {
728 jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
731 return formElems.test( this.nodeName );
733 remove: function( namespaces, fn ) {
734 for ( var type in changeFilters ) {
735 jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
738 return formElems.test( this.nodeName );
742 var changeFilters = jQuery.event.special.change.filters;
746 function trigger( type, elem, args ) {
748 return jQuery.event.handle.apply( elem, args );
751 // Create "bubbling" focus and blur events
752 if ( document.addEventListener ) {
753 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
754 jQuery.event.special[ fix ] = {
756 this.addEventListener( orig, handler, true );
758 teardown: function() {
759 this.removeEventListener( orig, handler, true );
763 function handler( e ) {
764 e = jQuery.event.fix( e );
766 return jQuery.event.handle.call( this, e );
771 jQuery.each(["bind", "one"], function( i, name ) {
772 jQuery.fn[ name ] = function( type, data, fn ) {
773 // Handle object literals
774 if ( typeof type === "object" ) {
775 for ( var key in type ) {
776 this[ name ](key, data, type[key], fn);
781 if ( jQuery.isFunction( data ) ) {
786 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
787 jQuery( this ).unbind( event, handler );
788 return fn.apply( this, arguments );
791 return type === "unload" && name !== "one" ?
792 this.one( type, data, fn ) :
793 this.each(function() {
794 jQuery.event.add( this, type, handler, data );
800 unbind: function( type, fn ) {
801 // Handle object literals
802 if ( typeof type === "object" && !type.preventDefault ) {
803 for ( var key in type ) {
804 this.unbind(key, type[key]);
809 return this.each(function() {
810 jQuery.event.remove( this, type, fn );
813 trigger: function( type, data ) {
814 return this.each(function() {
815 jQuery.event.trigger( type, data, this );
819 triggerHandler: function( type, data ) {
821 var event = jQuery.Event( type );
822 event.preventDefault();
823 event.stopPropagation();
824 jQuery.event.trigger( event, data, this[0] );
829 toggle: function( fn ) {
830 // Save reference to arguments for access in closure
831 var args = arguments, i = 1;
833 // link all the functions, so any of them can unbind this click handler
834 while ( i < args.length ) {
835 jQuery.proxy( fn, args[ i++ ] );
838 return this.click( jQuery.proxy( fn, function( event ) {
839 // Figure out which function to execute
840 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
841 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
843 // Make sure that clicks stop
844 event.preventDefault();
846 // and execute the function
847 return args[ lastToggle ].apply( this, arguments ) || false;
851 hover: function( fnOver, fnOut ) {
852 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
856 jQuery.each(["live", "die"], function( i, name ) {
857 jQuery.fn[ name ] = function( types, data, fn ) {
860 if ( jQuery.isFunction( data ) ) {
865 types = (types || "").split( /\s+/ );
867 while ( (type = types[ i++ ]) != null ) {
868 type = type === "focus" ? "focusin" : // focus --> focusin
869 type === "blur" ? "focusout" : // blur --> focusout
870 type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
873 if ( name === "live" ) {
875 jQuery( this.context ).bind( liveConvert( type, this.selector ), {
876 data: data, selector: this.selector, live: type
880 // unbind live handler
881 jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
889 function liveHandler( event ) {
890 var stop, elems = [], selectors = [], args = arguments,
891 related, match, fn, elem, j, i, l, data,
892 live = jQuery.extend({}, jQuery.data( this, "events" ).live);
894 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
895 if ( event.button && event.type === "click" ) {
901 if ( fn.live === event.type ||
902 fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
905 if ( !(data.beforeFilter && data.beforeFilter[event.type] &&
906 !data.beforeFilter[event.type](event)) ) {
907 selectors.push( fn.selector );
914 match = jQuery( event.target ).closest( selectors, event.currentTarget );
916 for ( i = 0, l = match.length; i < l; i++ ) {
919 elem = match[i].elem;
922 if ( match[i].selector === fn.selector ) {
923 // Those two events require additional checking
924 if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
925 related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
928 if ( !related || related !== elem ) {
929 elems.push({ elem: elem, fn: fn });
935 for ( i = 0, l = elems.length; i < l; i++ ) {
937 event.currentTarget = match.elem;
938 event.data = match.fn.data;
939 if ( match.fn.apply( match.elem, args ) === false ) {
948 function liveConvert( type, selector ) {
949 return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
952 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
953 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
954 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
956 // Handle event binding
957 jQuery.fn[ name ] = function( fn ) {
958 return fn ? this.bind( name, fn ) : this.trigger( name );
961 if ( jQuery.attrFn ) {
962 jQuery.attrFn[ name ] = true;
966 // Prevent memory leaks in IE
967 // Window isn't included so as not to unbind existing unload events
969 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
970 if ( window.attachEvent && !window.addEventListener ) {
971 window.attachEvent("onunload", function() {
972 for ( var id in jQuery.cache ) {
973 if ( jQuery.cache[ id ].handle ) {
974 // Try/Catch is to handle iframes being unloaded, see #4280
976 jQuery.event.remove( jQuery.cache[ id ].handle.elem );