7a28080aaf06cd03422f754fb3d173842a5cd60a
[jquery.git] / src / event.js
1 /*
2  * A number of helper functions used for managing events.
3  * Many of the ideas behind this code originated from
4  * Dean Edwards' addEvent library.
5  */
6 jQuery.event = {
7
8         // Bind an event to an element
9         // Original by Dean Edwards
10         add: function( elem, types, handler, data ) {
11                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
12                         return;
13                 }
14
15                 // For whatever reason, IE has trouble passing the window object
16                 // around, causing it to be cloned in the process
17                 if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
18                         elem = window;
19                 }
20
21                 // Make sure that the function being executed has a unique ID
22                 if ( !handler.guid ) {
23                         handler.guid = this.guid++;
24                 }
25
26                 // if data is passed, bind to handler
27                 if ( data !== undefined ) {
28                         // Create temporary function pointer to original handler
29                         var fn = handler;
30
31                         // Create unique handler function, wrapped around original handler
32                         handler = this.proxy( fn );
33
34                         // Store data in unique handler
35                         handler.data = data;
36                 }
37
38                 // Init the element's event structure
39                 var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
40                         handle = jQuery.data( elem, "handle" ) || jQuery.data( elem, "handle", function() {
41                                 // Handle the second event of a trigger and when
42                                 // an event is called after a page has unloaded
43                                 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
44                                         jQuery.event.handle.apply( arguments.callee.elem, arguments ) :
45                                         undefined;
46                         });
47                 // Add elem as a property of the handle function
48                 // This is to prevent a memory leak with non-native
49                 // event in IE.
50                 handle.elem = elem;
51
52                 // Handle multiple events separated by a space
53                 // jQuery(...).bind("mouseover mouseout", fn);
54                 types = types.split( /\s+/ );
55                 var type, i=0;
56                 while ( (type = types[ i++ ]) ) {
57                         // Namespaced event handlers
58                         var namespaces = type.split(".");
59                         type = namespaces.shift();
60                         handler.type = namespaces.slice().sort().join(".");
61
62                         // Get the current list of functions bound to this event
63                         var handlers = events[ type ];
64
65                         if ( this.specialAll[ type ] ) {
66                                 this.specialAll[ type ].setup.call( elem, data, namespaces );
67                         }
68
69                         // Init the event handler queue
70                         if ( !handlers ) {
71                                 handlers = events[ type ] = {};
72
73                                 // Check for a special event handler
74                                 // Only use addEventListener/attachEvent if the special
75                                 // events handler returns false
76                                 if ( !this.special[ type ] || this.special[ type ].setup.call( elem, data, namespaces ) === false ) {
77                                         // Bind the global event handler to the element
78                                         if ( elem.addEventListener ) {
79                                                 elem.addEventListener( type, handle, false );
80                                         } else if ( elem.attachEvent ) {
81                                                 elem.attachEvent( "on" + type, handle );
82                                         }
83                                 }
84                         }
85
86                         // Add the function to the element's handler list
87                         handlers[ handler.guid ] = handler;
88
89                         // Keep track of which events have been used, for global triggering
90                         this.global[ type ] = true;
91                 }
92
93                 // Nullify elem to prevent memory leaks in IE
94                 elem = null;
95         },
96
97         guid: 1,
98         global: {},
99
100         // Detach an event or set of events from an element
101         remove: function( elem, types, handler ) {
102                 // don't do events on text and comment nodes
103                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
104                         return;
105                 }
106
107                 var events = jQuery.data( elem, "events" ), ret, type;
108
109                 if ( events ) {
110                         // Unbind all events for the element
111                         if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
112                                 for ( type in events ) {
113                                         this.remove( elem, type + (types || "") );
114                                 }
115                         } else {
116                                 // types is actually an event object here
117                                 if ( types.type ) {
118                                         handler = types.handler;
119                                         types = types.type;
120                                 }
121
122                                 // Handle multiple events seperated by a space
123                                 // jQuery(...).unbind("mouseover mouseout", fn);
124                                 types = types.split(/\s+/);
125                                 var i = 0;
126                                 while ( (type = types[ i++ ]) ) {
127                                         // Namespaced event handlers
128                                         var namespaces = type.split(".");
129                                         type = namespaces.shift();
130                                         var all = !namespaces.length,
131                                                 namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
132
133                                         if ( events[type] ) {
134                                                 // remove the given handler for the given type
135                                                 if ( handler ) {
136                                                         delete events[ type ][ handler.guid ];
137
138                                                 // remove all handlers for the given type
139                                                 } else {
140                                                         for ( var handle in events[ type ] ) {
141                                                                 // Handle the removal of namespaced events
142                                                                 if ( all || namespace.test( events[ type ][ handle ].type ) ) {
143                                                                         delete events[ type ][ handle ];
144                                                                 }
145                                                         }
146                                                 }
147
148                                                 if ( this.specialAll[ type ] ) {
149                                                         this.specialAll[ type ].teardown.call( elem, namespaces );
150                                                 }
151
152                                                 // remove generic event handler if no more handlers exist
153                                                 for ( ret in events[ type ] ) {
154                                                         break;
155                                                 }
156                                                 if ( !ret ) {
157                                                         if ( !this.special[ type ] || this.special[ type ].teardown.call( elem, namespaces ) === false ) {
158                                                                 if ( elem.removeEventListener ) {
159                                                                         elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
160                                                                 } else if ( elem.detachEvent ) {
161                                                                         elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
162                                                                 }
163                                                         }
164                                                         ret = null;
165                                                         delete events[ type ];
166                                                 }
167                                         }
168                                 }
169                         }
170
171                         // Remove the expando if it's no longer used
172                         for ( ret in events ) {
173                                 break;
174                         }
175                         if ( !ret ) {
176                                 var handle = jQuery.data( elem, "handle" );
177                                 if ( handle ) {
178                                         handle.elem = null;
179                                 }
180                                 jQuery.removeData( elem, "events" );
181                                 jQuery.removeData( elem, "handle" );
182                         }
183                 }
184         },
185
186         // bubbling is internal
187         trigger: function( event, data, elem, bubbling ) {
188                 // Event object or event type
189                 var type = event.type || event;
190
191                 if ( !bubbling ) {
192                         event = typeof event === "object" ?
193                                 // jQuery.Event object
194                                 event[expando] ? event :
195                                 // Object literal
196                                 jQuery.extend( jQuery.Event(type), event ) :
197                                 // Just the event type (string)
198                                 jQuery.Event(type);
199
200                         if ( type.indexOf("!") >= 0 ) {
201                                 event.type = type = type.slice(0, -1);
202                                 event.exclusive = true;
203                         }
204
205                         // Handle a global trigger
206                         if ( !elem ) {
207                                 // Don't bubble custom events when global (to avoid too much overhead)
208                                 event.stopPropagation();
209                                 // Only trigger if we've ever bound an event for it
210                                 if ( this.global[ type ] ) {
211                                         for ( var cached in jQuery.cache ) {
212                                                 if ( cached.events && cached.events[ type ] ) {
213                                                         this.trigger( event, data, cached.handle.elem );
214                                                 }
215                                         }
216                                 }
217                         }
218
219                         // Handle triggering a single element
220
221                         // don't do events on text and comment nodes
222                         if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
223                                 return undefined;
224                         }
225
226                         // Clean up in case it is reused
227                         event.result = undefined;
228                         event.target = elem;
229
230                         // Clone the incoming data, if any
231                         data = jQuery.makeArray( data );
232                         data.unshift( event );
233                 }
234
235                 event.currentTarget = elem;
236
237                 // Trigger the event, it is assumed that "handle" is a function
238                 var handle = jQuery.data( elem, "handle" );
239                 if ( handle ) {
240                         handle.apply( elem, data );
241                 }
242
243                 // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
244                 if ( (!elem[ type ] || (jQuery.nodeName(elem, 'a') && type === "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false ) {
245                         event.result = false;
246                 }
247
248                 // Trigger the native events (except for clicks on links)
249                 if ( !bubbling && elem[ type ] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) {
250                         this.triggered = true;
251                         try {
252                                 elem[ type ]();
253                         // prevent IE from throwing an error for some hidden elements
254                         } catch (e) {}
255                 }
256
257                 this.triggered = false;
258
259                 if ( !event.isPropagationStopped() ) {
260                         var parent = elem.parentNode || elem.ownerDocument;
261                         if ( parent ) {
262                                 jQuery.event.trigger( event, data, parent, true );
263                         }
264                 }
265         },
266
267         handle: function( event ) {
268                 // returned undefined or false
269                 var all, handlers;
270
271                 event = arguments[0] = jQuery.event.fix( event || window.event );
272                 event.currentTarget = this;
273
274                 // Namespaced event handlers
275                 var namespaces = event.type.split(".");
276                 event.type = namespaces.shift();
277
278                 // Cache this now, all = true means, any handler
279                 all = !namespaces.length && !event.exclusive;
280
281                 var namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
282
283                 handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
284
285                 for ( var j in handlers ) {
286                         var handler = handlers[ j ];
287
288                         // Filter the functions by class
289                         if ( all || namespace.test(handler.type) ) {
290                                 // Pass in a reference to the handler function itself
291                                 // So that we can later remove it
292                                 event.handler = handler;
293                                 event.data = handler.data;
294
295                                 var ret = handler.apply( this, arguments );
296
297                                 if ( ret !== undefined ) {
298                                         event.result = ret;
299                                         if ( ret === false ) {
300                                                 event.preventDefault();
301                                                 event.stopPropagation();
302                                         }
303                                 }
304
305                                 if ( event.isImmediatePropagationStopped() ) {
306                                         break;
307                                 }
308
309                         }
310                 }
311         },
312
313         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(" "),
314
315         fix: function( event ) {
316                 if ( event[ expando ] ) {
317                         return event;
318                 }
319
320                 // store a copy of the original event object
321                 // and "clone" to set read-only properties
322                 var originalEvent = event;
323                 event = jQuery.Event( originalEvent );
324
325                 for ( var i = this.props.length, prop; i; ) {
326                         prop = this.props[ --i ];
327                         event[ prop ] = originalEvent[ prop ];
328                 }
329
330                 // Fix target property, if necessary
331                 if ( !event.target ) {
332                         event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
333                 }
334
335                 // check if target is a textnode (safari)
336                 if ( event.target.nodeType === 3 ) {
337                         event.target = event.target.parentNode;
338                 }
339
340                 // Add relatedTarget, if necessary
341                 if ( !event.relatedTarget && event.fromElement ) {
342                         event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
343                 }
344
345                 // Calculate pageX/Y if missing and clientX/Y available
346                 if ( event.pageX == null && event.clientX != null ) {
347                         var doc = document.documentElement, body = document.body;
348                         event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
349                         event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc.clientTop  || 0);
350                 }
351
352                 // Add which for key events
353                 if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
354                         event.which = event.charCode || event.keyCode;
355                 }
356
357                 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
358                 if ( !event.metaKey && event.ctrlKey ) {
359                         event.metaKey = event.ctrlKey;
360                 }
361
362                 // Add which for click: 1 == left; 2 == middle; 3 == right
363                 // Note: button is not normalized, so don't use it
364                 if ( !event.which && event.button ) {
365                         event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
366                 }
367
368                 return event;
369         },
370
371         proxy: function( fn, proxy ) {
372                 proxy = proxy || function() { return fn.apply( this, arguments ); };
373                 // Set the guid of unique handler to the same of original handler, so it can be removed
374                 proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
375                 // So proxy can be declared as an argument
376                 return proxy;
377         },
378
379         special: {
380                 ready: {
381                         // Make sure the ready event is setup
382                         setup: bindReady,
383                         teardown: function() {}
384                 }
385         },
386
387         specialAll: {
388                 live: {
389                         setup: function( selector, namespaces ) {
390                                 jQuery.event.add( this, namespaces[0], liveHandler );
391                         },
392                         teardown:  function( namespaces ) {
393                                 if ( namespaces.length ) {
394                                         var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
395
396                                         jQuery.each( (jQuery.data(this, "events").live || {}), function() {
397                                                 if ( name.test(this.type) ) {
398                                                         remove++;
399                                                 }
400                                         });
401
402                                         if ( remove < 1 ) {
403                                                 jQuery.event.remove( this, namespaces[0], liveHandler );
404                                         }
405                                 }
406                         }
407                 }
408         }
409 };
410
411 jQuery.Event = function( src ){
412         // Allow instantiation without the 'new' keyword
413         if ( !this.preventDefault ) {
414                 return new jQuery.Event( src );
415         }
416
417         // Event object
418         if ( src && src.type ) {
419                 this.originalEvent = src;
420                 this.type = src.type;
421         // Event type
422         } else {
423                 this.type = src;
424         }
425
426         // timeStamp is buggy for some events on Firefox(#3843)
427         // So we won't rely on the native value
428         this.timeStamp = now();
429
430         // Mark it as fixed
431         this[ expando ] = true;
432 };
433
434 function returnFalse() {
435         return false;
436 }
437 function returnTrue() {
438         return true;
439 }
440
441 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
442 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
443 jQuery.Event.prototype = {
444         preventDefault: function() {
445                 this.isDefaultPrevented = returnTrue;
446
447                 var e = this.originalEvent;
448                 if ( !e ) {
449                         return;
450                 }
451                 // if preventDefault exists run it on the original event
452                 if ( e.preventDefault ) {
453                         e.preventDefault();
454                 }
455                 // otherwise set the returnValue property of the original event to false (IE)
456                 e.returnValue = false;
457         },
458         stopPropagation: function() {
459                 this.isPropagationStopped = returnTrue;
460
461                 var e = this.originalEvent;
462                 if ( !e ) {
463                         return;
464                 }
465                 // if stopPropagation exists run it on the original event
466                 if ( e.stopPropagation ) {
467                         e.stopPropagation();
468                 }
469                 // otherwise set the cancelBubble property of the original event to true (IE)
470                 e.cancelBubble = true;
471         },
472         stopImmediatePropagation: function(){
473                 this.isImmediatePropagationStopped = returnTrue;
474                 this.stopPropagation();
475         },
476         isDefaultPrevented: returnFalse,
477         isPropagationStopped: returnFalse,
478         isImmediatePropagationStopped: returnFalse
479 };
480 // Checks if an event happened on an element within another element
481 // Used in jQuery.event.special.mouseenter and mouseleave handlers
482 var withinElement = function( event ) {
483         // Check if mouse(over|out) are still within the same parent element
484         var parent = event.relatedTarget;
485         // Traverse up the tree
486         while ( parent && parent != this ) {
487                 try { parent = parent.parentNode; }
488                 catch(e) { parent = this; }
489         }
490
491         if ( parent != this ) {
492                 // set the correct event type
493                 event.type = event.data;
494                 // handle event if we actually just moused on to a non sub-element
495                 jQuery.event.handle.apply( this, arguments );
496         }
497 };
498
499 jQuery.each({
500         mouseover: 'mouseenter',
501         mouseout: 'mouseleave'
502 }, function( orig, fix ) {
503         jQuery.event.special[ fix ] = {
504                 setup: function(){
505                         jQuery.event.add( this, orig, withinElement, fix );
506                 },
507                 teardown: function(){
508                         jQuery.event.remove( this, orig, withinElement );
509                 }
510         };
511 });
512
513 jQuery.fn.extend({
514         bind: function( type, data, fn ) {
515                 return type === "unload" ? this.one(type, data, fn) : this.each(function() {
516                         jQuery.event.add( this, type, fn || data, fn && data );
517                 });
518         },
519
520         one: function( type, data, fn ) {
521                 var one = jQuery.event.proxy( fn || data, function( event ) {
522                         jQuery( this ).unbind( event, one );
523                         return (fn || data).apply( this, arguments );
524                 });
525                 return this.each(function() {
526                         jQuery.event.add( this, type, one, fn && data );
527                 });
528         },
529
530         unbind: function( type, fn ) {
531                 return this.each(function() {
532                         jQuery.event.remove( this, type, fn );
533                 });
534         },
535
536         trigger: function( type, data ) {
537                 return this.each(function() {
538                         jQuery.event.trigger( type, data, this );
539                 });
540         },
541
542         triggerHandler: function( type, data ) {
543                 if ( this[0] ) {
544                         var event = jQuery.Event( type );
545                         event.preventDefault();
546                         event.stopPropagation();
547                         jQuery.event.trigger( event, data, this[0] );
548                         return event.result;
549                 }
550         },
551
552         toggle: function( fn ) {
553                 // Save reference to arguments for access in closure
554                 var args = arguments, i = 1;
555
556                 // link all the functions, so any of them can unbind this click handler
557                 while( i < args.length ) {
558                         jQuery.event.proxy( fn, args[ i++ ] );
559                 }
560
561                 return this.click( jQuery.event.proxy( fn, function( event ) {
562                         // Figure out which function to execute
563                         this.lastToggle = ( this.lastToggle || 0 ) % i;
564
565                         // Make sure that clicks stop
566                         event.preventDefault();
567
568                         // and execute the function
569                         return args[ this.lastToggle++ ].apply( this, arguments ) || false;
570                 }));
571         },
572
573         hover: function( fnOver, fnOut ) {
574                 return this.mouseenter( fnOver ).mouseleave( fnOut );
575         },
576
577         ready: function( fn ) {
578                 // Attach the listeners
579                 bindReady();
580
581                 // If the DOM is already ready
582                 if ( jQuery.isReady ) {
583                         // Execute the function immediately
584                         fn.call( document, jQuery );
585
586                 // Otherwise, remember the function for later
587                 } else {
588                         // Add the function to the wait list
589                         jQuery.readyList.push( fn );
590                 }
591
592                 return this;
593         },
594
595         live: function( type, fn ) {
596                 var proxy = jQuery.event.proxy( fn );
597                 proxy.guid += this.selector + type;
598
599                 jQuery( this.context ).bind( liveConvert( type, this.selector ), this.selector, proxy );
600
601                 return this;
602         },
603
604         die: function( type, fn ) {
605                 jQuery( this.context ).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
606                 return this;
607         }
608 });
609
610 function liveHandler( event ) {
611         var check = new RegExp("(^|\\.)" + event.type + "(\\.|$)"),
612                 stop = true, elems = [];
613
614         jQuery.each( jQuery.data( this, "events" ).live || [], function( i, fn ) {
615                 if ( check.test( fn.type ) ) {
616                         var elem = jQuery( event.target ).closest( fn.data )[0];
617                         if ( elem ) {
618                                 elems.push({ elem: elem, fn: fn });
619                         }
620                 }
621         });
622
623         elems.sort(function( a, b ) {
624                 return jQuery.data( a.elem, "closest" ) - jQuery.data( b.elem, "closest" );
625         });
626
627         jQuery.each(elems, function() {
628                 event.currentTarget = this.elem;
629                 if ( this.fn.call( this.elem, event, this.fn.data ) === false ) {
630                         return (stop = false);
631                 }
632         });
633
634         return stop;
635 }
636
637 function liveConvert( type, selector ) {
638         return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
639 }
640
641 jQuery.extend({
642         isReady: false,
643         readyList: [],
644         // Handle when the DOM is ready
645         ready: function() {
646                 // Make sure that the DOM is not already loaded
647                 if ( !jQuery.isReady ) {
648                         // Remember that the DOM is ready
649                         jQuery.isReady = true;
650
651                         // If there are functions bound, to execute
652                         if ( jQuery.readyList ) {
653                                 // Execute all of them
654                                 var fn, i = 0;
655                                 while ( (fn = jQuery.readyList[ i++ ]) ) {
656                                         fn.call( document, jQuery );
657                                 }
658
659                                 // Reset the list of functions
660                                 jQuery.readyList = null;
661                         }
662
663                         // Trigger any bound ready events
664                         jQuery( document ).triggerHandler( "ready" );
665                 }
666         }
667 });
668
669 var readyBound = false;
670
671 function bindReady() {
672         if ( readyBound ) return;
673         readyBound = true;
674
675         // Mozilla, Opera and webkit nightlies currently support this event
676         if ( document.addEventListener ) {
677                 // Use the handy event callback
678                 document.addEventListener( "DOMContentLoaded", function() {
679                         document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
680                         jQuery.ready();
681                 }, false );
682
683         // If IE event model is used
684         } else if ( document.attachEvent ) {
685                 // ensure firing before onload,
686                 // maybe late but safe also for iframes
687                 document.attachEvent("onreadystatechange", function() {
688                         if ( document.readyState === "complete" ) {
689                                 document.detachEvent( "onreadystatechange", arguments.callee );
690                                 jQuery.ready();
691                         }
692                 });
693
694                 // If IE and not an iframe
695                 // continually check to see if the document is ready
696                 if ( document.documentElement.doScroll && window === window.top ) (function() {
697                         if ( jQuery.isReady ) {
698                                 return;
699                         }
700
701                         try {
702                                 // If IE is used, use the trick by Diego Perini
703                                 // http://javascript.nwbox.com/IEContentLoaded/
704                                 document.documentElement.doScroll("left");
705                         } catch( error ) {
706                                 setTimeout( arguments.callee, 0 );
707                                 return;
708                         }
709
710                         // and execute any waiting functions
711                         jQuery.ready();
712                 })();
713         }
714
715         // A fallback to window.onload, that will always work
716         jQuery.event.add( window, "load", jQuery.ready );
717 }
718
719 jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
720         "mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave," +
721         "change,select,submit,keydown,keypress,keyup,error").split(","), function( i, name ) {
722
723         // Handle event binding
724         jQuery.fn[ name ] = function( fn ) {
725                 return fn ? this.bind (name, fn ) : this.trigger( name );
726         };
727 });
728
729 // Prevent memory leaks in IE
730 // And prevent errors on refresh with events like mouseover in other browsers
731 // Window isn't included so as not to unbind existing unload events
732 // More info:
733 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
734 //  - https://bugzilla.mozilla.org/show_bug.cgi?id=252542
735 jQuery( window ).bind( 'unload', function() {
736         for ( var id in jQuery.cache ) {
737                 // Skip the window
738                 if ( id != 1 && jQuery.cache[ id ].handle ) {
739                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
740                 }
741         }
742 });