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 elemData = jQuery.data( elem );
47 // If no elemData is found then we must be trying to bind to one of the
48 // banned noData elements
53 var events = elemData.events || (elemData.events = {}),
54 handle = elemData.handle, eventHandle;
57 eventHandle = function() {
58 // Handle the second event of a trigger and when
59 // an event is called after a page has unloaded
60 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
61 jQuery.event.handle.apply( eventHandle.elem, arguments ) :
65 handle = elemData.handle = eventHandle;
68 // Add elem as a property of the handle function
69 // This is to prevent a memory leak with non-native
73 // Handle multiple events separated by a space
74 // jQuery(...).bind("mouseover mouseout", fn);
75 types = types.split(" ");
77 var type, i = 0, namespaces;
79 while ( (type = types[ i++ ]) ) {
81 handler = jQuery.proxy( handler );
83 if ( data !== undefined ) {
88 // Namespaced event handlers
89 if ( type.indexOf(".") > -1 ) {
90 namespaces = type.split(".");
91 type = namespaces.shift();
92 handler.type = namespaces.slice(0).sort().join(".");
99 // Get the current list of functions bound to this event
100 var handlers = events[ type ],
101 special = this.special[ type ] || {};
103 // Init the event handler queue
105 handlers = events[ type ] = {};
107 // Check for a special event handler
108 // Only use addEventListener/attachEvent if the special
109 // events handler returns false
110 if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
111 // Bind the global event handler to the element
112 if ( elem.addEventListener ) {
113 elem.addEventListener( type, handle, false );
115 } else if ( elem.attachEvent ) {
116 elem.attachEvent( "on" + type, handle );
122 var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
123 if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
124 modifiedHandler.guid = modifiedHandler.guid || handler.guid;
125 modifiedHandler.data = modifiedHandler.data || handler.data;
126 modifiedHandler.type = modifiedHandler.type || handler.type;
127 handler = modifiedHandler;
131 // Add the function to the element's handler list
132 handlers[ handler.guid ] = handler;
134 // Keep track of which events have been used, for global triggering
135 this.global[ type ] = true;
138 // Nullify elem to prevent memory leaks in IE
144 // Detach an event or set of events from an element
145 remove: function( elem, types, handler ) {
146 // don't do events on text and comment nodes
147 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
151 var elemData = jQuery.data( elem );
157 var events = elemData.events, ret, type, fn;
160 // Unbind all events for the element
161 if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
162 for ( type in events ) {
163 this.remove( elem, type + (types || "") );
167 // types is actually an event object here
169 handler = types.handler;
173 // Handle multiple events separated by a space
174 // jQuery(...).unbind("mouseover mouseout", fn);
175 types = types.split(" ");
177 var i = 0, all, namespaces, namespace;
179 while ( (type = types[ i++ ]) ) {
180 all = type.indexOf(".") < 0;
184 // Namespaced event handlers
185 namespaces = type.split(".");
186 type = namespaces.shift();
188 namespace = new RegExp("(^|\\.)" +
189 jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
195 var special = this.special[ type ] || {};
197 if ( events[ type ] ) {
198 // remove the given handler for the given type
200 fn = events[ type ][ handler.guid ];
201 delete events[ type ][ handler.guid ];
203 // remove all handlers for the given type
205 for ( var handle in events[ type ] ) {
206 // Handle the removal of namespaced events
207 if ( all || namespace.test( events[ type ][ handle ].type ) ) {
208 delete events[ type ][ handle ];
213 if ( special.remove ) {
214 special.remove.call( elem, namespaces, fn);
217 // remove generic event handler if no more handlers exist
218 for ( ret in events[ type ] ) {
223 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
224 removeEvent( elem, type, elemData.handle );
228 delete events[ type ];
234 // Remove the expando if it's no longer used
235 for ( ret in events ) {
240 var handle = elemData.handle;
245 delete elemData.events;
246 delete elemData.handle;
248 if ( jQuery.isEmptyObject( elemData ) ) {
249 jQuery.removeData( elem );
255 // bubbling is internal
256 trigger: function( event, data, elem /*, bubbling */ ) {
257 // Event object or event type
258 var type = event.type || event,
259 bubbling = arguments[3];
262 event = typeof event === "object" ?
263 // jQuery.Event object
264 event[expando] ? event :
266 jQuery.extend( jQuery.Event(type), event ) :
267 // Just the event type (string)
270 if ( type.indexOf("!") >= 0 ) {
271 event.type = type = type.slice(0, -1);
272 event.exclusive = true;
275 // Handle a global trigger
277 // Don't bubble custom events when global (to avoid too much overhead)
278 event.stopPropagation();
280 // Only trigger if we've ever bound an event for it
281 if ( this.global[ type ] ) {
282 jQuery.each( jQuery.cache, function() {
283 if ( this.events && this.events[type] ) {
284 jQuery.event.trigger( event, data, this.handle.elem );
290 // Handle triggering a single element
292 // don't do events on text and comment nodes
293 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
297 // Clean up in case it is reused
298 event.result = undefined;
301 // Clone the incoming data, if any
302 data = jQuery.makeArray( data );
303 data.unshift( event );
306 event.currentTarget = elem;
308 // Trigger the event, it is assumed that "handle" is a function
309 var handle = jQuery.data( elem, "handle" );
311 handle.apply( elem, data );
314 var parent = elem.parentNode || elem.ownerDocument;
316 // Trigger an inline bound script
318 if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
319 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
320 event.result = false;
324 // prevent IE from throwing an error for some elements with some event types, see #3533
327 if ( !event.isPropagationStopped() && parent ) {
328 jQuery.event.trigger( event, data, parent, true );
330 } else if ( !event.isDefaultPrevented() ) {
331 var target = event.target, old,
332 isClick = jQuery.nodeName(target, "a") && type === "click",
333 special = jQuery.event.special[ type ] || {};
335 if ( (!special._default || special._default.call( elem, event ) === false) &&
336 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
339 if ( target[ type ] ) {
340 // Make sure that we don't accidentally re-trigger the onFOO events
341 old = target[ "on" + type ];
344 target[ "on" + type ] = null;
347 this.triggered = true;
351 // prevent IE from throwing an error for some elements with some event types, see #3533
355 target[ "on" + type ] = old;
358 this.triggered = false;
363 handle: function( event ) {
364 // returned undefined or false
367 event = arguments[0] = jQuery.event.fix( event || window.event );
368 event.currentTarget = this;
370 // Namespaced event handlers
371 var namespaces = event.type.split(".");
372 event.type = namespaces.shift();
374 // Cache this now, all = true means, any handler
375 all = !namespaces.length && !event.exclusive;
377 var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
379 handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
381 for ( var j in handlers ) {
382 var handler = handlers[ j ];
384 // Filter the functions by class
385 if ( all || namespace.test(handler.type) ) {
386 // Pass in a reference to the handler function itself
387 // So that we can later remove it
388 event.handler = handler;
389 event.data = handler.data;
391 var ret = handler.apply( this, arguments );
393 if ( ret !== undefined ) {
395 if ( ret === false ) {
396 event.preventDefault();
397 event.stopPropagation();
401 if ( event.isImmediatePropagationStopped() ) {
411 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(" "),
413 fix: function( event ) {
414 if ( event[ expando ] ) {
418 // store a copy of the original event object
419 // and "clone" to set read-only properties
420 var originalEvent = event;
421 event = jQuery.Event( originalEvent );
423 for ( var i = this.props.length, prop; i; ) {
424 prop = this.props[ --i ];
425 event[ prop ] = originalEvent[ prop ];
428 // Fix target property, if necessary
429 if ( !event.target ) {
430 event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
433 // check if target is a textnode (safari)
434 if ( event.target.nodeType === 3 ) {
435 event.target = event.target.parentNode;
438 // Add relatedTarget, if necessary
439 if ( !event.relatedTarget && event.fromElement ) {
440 event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
443 // Calculate pageX/Y if missing and clientX/Y available
444 if ( event.pageX == null && event.clientX != null ) {
445 var doc = document.documentElement, body = document.body;
446 event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
447 event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
450 // Add which for key events
451 if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
452 event.which = event.charCode || event.keyCode;
455 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
456 if ( !event.metaKey && event.ctrlKey ) {
457 event.metaKey = event.ctrlKey;
460 // Add which for click: 1 === left; 2 === middle; 3 === right
461 // Note: button is not normalized, so don't use it
462 if ( !event.which && event.button !== undefined ) {
463 event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
469 // Deprecated, use jQuery.guid instead
472 // Deprecated, use jQuery.proxy instead
477 // Make sure the ready event is setup
478 setup: jQuery.bindReady,
479 teardown: jQuery.noop
483 add: function( proxy, data, namespaces, live ) {
484 jQuery.extend( proxy, data || {} );
486 proxy.guid += data.selector + data.live;
487 data.liveProxy = proxy;
489 jQuery.event.add( this, data.live, liveHandler, data );
493 remove: function( namespaces ) {
494 if ( namespaces.length ) {
495 var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
497 jQuery.each( (jQuery.data(this, "events").live || {}), function() {
498 if ( name.test(this.type) ) {
504 jQuery.event.remove( this, namespaces[0], liveHandler );
511 setup: function( data, namespaces, fn ) {
512 // We only want to do this special case on windows
513 if ( this.setInterval ) {
514 this.onbeforeunload = fn;
519 teardown: function( namespaces, fn ) {
520 if ( this.onbeforeunload === fn ) {
521 this.onbeforeunload = null;
528 var removeEvent = document.removeEventListener ?
529 function( elem, type, handle ) {
530 elem.removeEventListener( type, handle, false );
532 function( elem, type, handle ) {
533 elem.detachEvent( "on" + type, handle );
536 jQuery.Event = function( src ) {
537 // Allow instantiation without the 'new' keyword
538 if ( !this.preventDefault ) {
539 return new jQuery.Event( src );
543 if ( src && src.type ) {
544 this.originalEvent = src;
545 this.type = src.type;
551 // timeStamp is buggy for some events on Firefox(#3843)
552 // So we won't rely on the native value
553 this.timeStamp = now();
556 this[ expando ] = true;
559 function returnFalse() {
562 function returnTrue() {
566 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
567 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
568 jQuery.Event.prototype = {
569 preventDefault: function() {
570 this.isDefaultPrevented = returnTrue;
572 var e = this.originalEvent;
577 // if preventDefault exists run it on the original event
578 if ( e.preventDefault ) {
581 // otherwise set the returnValue property of the original event to false (IE)
582 e.returnValue = false;
584 stopPropagation: function() {
585 this.isPropagationStopped = returnTrue;
587 var e = this.originalEvent;
591 // if stopPropagation exists run it on the original event
592 if ( e.stopPropagation ) {
595 // otherwise set the cancelBubble property of the original event to true (IE)
596 e.cancelBubble = true;
598 stopImmediatePropagation: function() {
599 this.isImmediatePropagationStopped = returnTrue;
600 this.stopPropagation();
602 isDefaultPrevented: returnFalse,
603 isPropagationStopped: returnFalse,
604 isImmediatePropagationStopped: returnFalse
607 // Checks if an event happened on an element within another element
608 // Used in jQuery.event.special.mouseenter and mouseleave handlers
609 var withinElement = function( event ) {
610 // Check if mouse(over|out) are still within the same parent element
611 var parent = event.relatedTarget;
613 // Traverse up the tree
614 while ( parent && parent !== this ) {
615 // Firefox sometimes assigns relatedTarget a XUL element
616 // which we cannot access the parentNode property of
618 parent = parent.parentNode;
620 // assuming we've left the element since we most likely mousedover a xul element
626 if ( parent !== this ) {
627 // set the correct event type
628 event.type = event.data;
630 // handle event if we actually just moused on to a non sub-element
631 jQuery.event.handle.apply( this, arguments );
636 // In case of event delegation, we only need to rename the event.type,
637 // liveHandler will take care of the rest.
638 delegate = function( event ) {
639 event.type = event.data;
640 jQuery.event.handle.apply( this, arguments );
643 // Create mouseenter and mouseleave events
645 mouseenter: "mouseover",
646 mouseleave: "mouseout"
647 }, function( orig, fix ) {
648 jQuery.event.special[ orig ] = {
649 setup: function( data ) {
650 jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
652 teardown: function( data ) {
653 jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
659 if ( !jQuery.support.submitBubbles ) {
661 jQuery.event.special.submit = {
662 setup: function( data, namespaces, fn ) {
663 if ( this.nodeName.toLowerCase() !== "form" ) {
664 jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
665 var elem = e.target, type = elem.type;
667 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
668 return trigger( "submit", this, arguments );
672 jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
673 var elem = e.target, type = elem.type;
675 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
676 return trigger( "submit", this, arguments );
685 remove: function( namespaces, fn ) {
686 jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
687 jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
693 // change delegation, happens here so we have bind.
694 if ( !jQuery.support.changeBubbles ) {
696 var formElems = /textarea|input|select/i;
698 function getVal( elem ) {
699 var type = elem.type, val = elem.value;
701 if ( type === "radio" || type === "checkbox" ) {
704 } else if ( type === "select-multiple" ) {
705 val = elem.selectedIndex > -1 ?
706 jQuery.map( elem.options, function( elem ) {
707 return elem.selected;
711 } else if ( elem.nodeName.toLowerCase() === "select" ) {
712 val = elem.selectedIndex;
718 function testChange( e ) {
719 var elem = e.target, data, val;
721 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
725 data = jQuery.data( elem, "_change_data" );
728 // the current data will be also retrieved by beforeactivate
729 if ( e.type !== "focusout" || elem.type !== "radio" ) {
730 jQuery.data( elem, "_change_data", val );
733 if ( data === undefined || val === data ) {
737 if ( data != null || val ) {
739 return jQuery.event.trigger( e, arguments[1], elem );
743 jQuery.event.special.change = {
745 focusout: testChange,
747 click: function( e ) {
748 var elem = e.target, type = elem.type;
750 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
751 return testChange.call( this, e );
755 // Change has to be called before submit
756 // Keydown will be called before keypress, which is used in submit-event delegation
757 keydown: function( e ) {
758 var elem = e.target, type = elem.type;
760 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
761 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
762 type === "select-multiple" ) {
763 return testChange.call( this, e );
767 // Beforeactivate happens also before the previous element is blurred
768 // with this event you can't trigger a change event, but you can store
769 // information/focus[in] is not needed anymore
770 beforeactivate: function( e ) {
772 jQuery.data( elem, "_change_data", getVal(elem) );
775 setup: function( data, namespaces, fn ) {
776 for ( var type in changeFilters ) {
777 jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
780 return formElems.test( this.nodeName );
782 remove: function( namespaces, fn ) {
783 for ( var type in changeFilters ) {
784 jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
787 return formElems.test( this.nodeName );
791 var changeFilters = jQuery.event.special.change.filters;
795 function trigger( type, elem, args ) {
797 return jQuery.event.handle.apply( elem, args );
800 // Create "bubbling" focus and blur events
801 if ( document.addEventListener ) {
802 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
803 jQuery.event.special[ fix ] = {
805 this.addEventListener( orig, handler, true );
807 teardown: function() {
808 this.removeEventListener( orig, handler, true );
812 function handler( e ) {
813 e = jQuery.event.fix( e );
815 return jQuery.event.handle.call( this, e );
820 jQuery.each(["bind", "one"], function( i, name ) {
821 jQuery.fn[ name ] = function( type, data, fn ) {
822 // Handle object literals
823 if ( typeof type === "object" ) {
824 for ( var key in type ) {
825 this[ name ](key, data, type[key], fn);
830 if ( jQuery.isFunction( data ) ) {
835 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
836 jQuery( this ).unbind( event, handler );
837 return fn.apply( this, arguments );
840 if ( type === "unload" && name !== "one" ) {
841 this.one( type, data, fn );
844 for ( var i = 0, l = this.length; i < l; i++ ) {
845 jQuery.event.add( this[i], type, handler, data );
854 unbind: function( type, fn ) {
855 // Handle object literals
856 if ( typeof type === "object" && !type.preventDefault ) {
857 for ( var key in type ) {
858 this.unbind(key, type[key]);
862 for ( var i = 0, l = this.length; i < l; i++ ) {
863 jQuery.event.remove( this[i], type, fn );
869 trigger: function( type, data ) {
870 return this.each(function() {
871 jQuery.event.trigger( type, data, this );
875 triggerHandler: function( type, data ) {
877 var event = jQuery.Event( type );
878 event.preventDefault();
879 event.stopPropagation();
880 jQuery.event.trigger( event, data, this[0] );
885 toggle: function( fn ) {
886 // Save reference to arguments for access in closure
887 var args = arguments, i = 1;
889 // link all the functions, so any of them can unbind this click handler
890 while ( i < args.length ) {
891 jQuery.proxy( fn, args[ i++ ] );
894 return this.click( jQuery.proxy( fn, function( event ) {
895 // Figure out which function to execute
896 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
897 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
899 // Make sure that clicks stop
900 event.preventDefault();
902 // and execute the function
903 return args[ lastToggle ].apply( this, arguments ) || false;
907 hover: function( fnOver, fnOut ) {
908 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
912 jQuery.each(["live", "die"], function( i, name ) {
913 jQuery.fn[ name ] = function( types, data, fn ) {
916 if ( jQuery.isFunction( data ) ) {
921 types = (types || "").split( /\s+/ );
923 while ( (type = types[ i++ ]) != null ) {
924 type = type === "focus" ? "focusin" : // focus --> focusin
925 type === "blur" ? "focusout" : // blur --> focusout
926 type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
929 if ( name === "live" ) {
931 jQuery( this.context ).bind( liveConvert( type, this.selector ), {
932 data: data, selector: this.selector, live: type
936 // unbind live handler
937 jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
945 function liveHandler( event ) {
946 var stop, elems = [], selectors = [], args = arguments,
947 related, match, fn, elem, j, i, l, data,
948 live = jQuery.extend({}, jQuery.data( this, "events" ).live);
950 // Make sure we avoid non-left-click bubbling in Firefox (#3861)
951 if ( event.button && event.type === "click" ) {
957 if ( fn.live === event.type ||
958 fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
961 if ( !(data.beforeFilter && data.beforeFilter[event.type] &&
962 !data.beforeFilter[event.type](event)) ) {
963 selectors.push( fn.selector );
970 match = jQuery( event.target ).closest( selectors, event.currentTarget );
972 for ( i = 0, l = match.length; i < l; i++ ) {
975 elem = match[i].elem;
978 if ( match[i].selector === fn.selector ) {
979 // Those two events require additional checking
980 if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
981 related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
984 if ( !related || related !== elem ) {
985 elems.push({ elem: elem, fn: fn });
991 for ( i = 0, l = elems.length; i < l; i++ ) {
993 event.currentTarget = match.elem;
994 event.data = match.fn.data;
995 if ( match.fn.apply( match.elem, args ) === false ) {
1004 function liveConvert( type, selector ) {
1005 return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
1008 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1009 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1010 "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1012 // Handle event binding
1013 jQuery.fn[ name ] = function( fn ) {
1014 return fn ? this.bind( name, fn ) : this.trigger( name );
1017 if ( jQuery.attrFn ) {
1018 jQuery.attrFn[ name ] = true;
1022 // Prevent memory leaks in IE
1023 // Window isn't included so as not to unbind existing unload events
1025 // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1026 if ( window.attachEvent && !window.addEventListener ) {
1027 window.attachEvent("onunload", function() {
1028 for ( var id in jQuery.cache ) {
1029 if ( jQuery.cache[ id ].handle ) {
1030 // Try/Catch is to handle iframes being unloaded, see #4280
1032 jQuery.event.remove( jQuery.cache[ id ].handle.elem );