Make sure no exception is thrown if no event handler is found (which is the case...
[jquery.git] / src / event.js
1 var fcleanup = function( nm ) {
2         return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
3                 return "\\" + ch;
4         });
5 };
6
7 /*
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.
11  */
12 jQuery.event = {
13
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 ) {
18                         return;
19                 }
20
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 ) ) {
24                         elem = window;
25                 }
26
27                 // Make sure that the function being executed has a unique ID
28                 if ( !handler.guid ) {
29                         handler.guid = jQuery.guid++;
30                 }
31
32                 // if data is passed, bind to handler
33                 if ( data !== undefined ) {
34                         // Create temporary function pointer to original handler
35                         var fn = handler;
36
37                         // Create unique handler function, wrapped around original handler
38                         handler = jQuery.proxy( fn );
39
40                         // Store data in unique handler
41                         handler.data = data;
42                 }
43
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;
47
48                 if ( !handle ) {
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 ) :
54                                         undefined;
55                         };
56
57                         handle = jQuery.data( elem, "handle", eventHandle );
58                 }
59
60                 // If no handle is found then we must be trying to bind to one of the
61                 // banned noData elements
62                 if ( !handle ) {
63                         return;
64                 }
65
66                 // Add elem as a property of the handle function
67                 // This is to prevent a memory leak with non-native
68                 // event in IE.
69                 handle.elem = elem;
70
71                 // Handle multiple events separated by a space
72                 // jQuery(...).bind("mouseover mouseout", fn);
73                 types = types.split( /\s+/ );
74                 var type, i=0;
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(".");
80
81                         // Get the current list of functions bound to this event
82                         var handlers = events[ type ],
83                                 special = this.special[ type ] || {};
84
85                         
86
87                         // Init the event handler queue
88                         if ( !handlers ) {
89                                 handlers = events[ type ] = {};
90
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 );
100                                         }
101                                 }
102                         }
103                         
104                         if ( special.add ) { 
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; 
109                                 } 
110                         } 
111                         
112                         // Add the function to the element's handler list
113                         handlers[ handler.guid ] = handler;
114
115                         // Keep track of which events have been used, for global triggering
116                         this.global[ type ] = true;
117                 }
118
119                 // Nullify elem to prevent memory leaks in IE
120                 elem = null;
121         },
122
123         global: {},
124
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 ) {
129                         return;
130                 }
131
132                 var events = jQuery.data( elem, "events" ), ret, type, fn;
133
134                 if ( events ) {
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 || "") );
139                                 }
140                         } else {
141                                 // types is actually an event object here
142                                 if ( types.type ) {
143                                         handler = types.handler;
144                                         types = types.type;
145                                 }
146
147                                 // Handle multiple events separated by a space
148                                 // jQuery(...).unbind("mouseover mouseout", fn);
149                                 types = types.split(/\s+/);
150                                 var i = 0;
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 ] || {};
159
160                                         if ( events[ type ] ) {
161                                                 // remove the given handler for the given type
162                                                 if ( handler ) {
163                                                         fn = events[ type ][ handler.guid ];
164                                                         delete events[ type ][ handler.guid ];
165
166                                                 // remove all handlers for the given type
167                                                 } else {
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 ];
172                                                                 }
173                                                         }
174                                                 }
175
176                                                 if ( special.remove ) {
177                                                         special.remove.call( elem, namespaces, fn);
178                                                 }
179
180                                                 // remove generic event handler if no more handlers exist
181                                                 for ( ret in events[ type ] ) {
182                                                         break;
183                                                 }
184                                                 if ( !ret ) {
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" ) );
190                                                                 }
191                                                         }
192                                                         ret = null;
193                                                         delete events[ type ];
194                                                 }
195                                         }
196                                 }
197                         }
198
199                         // Remove the expando if it's no longer used
200                         for ( ret in events ) {
201                                 break;
202                         }
203                         if ( !ret ) {
204                                 var handle = jQuery.data( elem, "handle" );
205                                 if ( handle ) {
206                                         handle.elem = null;
207                                 }
208                                 jQuery.removeData( elem, "events" );
209                                 jQuery.removeData( elem, "handle" );
210                         }
211                 }
212         },
213
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];
219
220                 if ( !bubbling ) {
221                         event = typeof event === "object" ?
222                                 // jQuery.Event object
223                                 event[expando] ? event :
224                                 // Object literal
225                                 jQuery.extend( jQuery.Event(type), event ) :
226                                 // Just the event type (string)
227                                 jQuery.Event(type);
228
229                         if ( type.indexOf("!") >= 0 ) {
230                                 event.type = type = type.slice(0, -1);
231                                 event.exclusive = true;
232                         }
233
234                         // Handle a global trigger
235                         if ( !elem ) {
236                                 // Don't bubble custom events when global (to avoid too much overhead)
237                                 event.stopPropagation();
238
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 );
244                                                 }
245                                         });
246                                 }
247                         }
248
249                         // Handle triggering a single element
250
251                         // don't do events on text and comment nodes
252                         if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
253                                 return undefined;
254                         }
255
256                         // Clean up in case it is reused
257                         event.result = undefined;
258                         event.target = elem;
259
260                         // Clone the incoming data, if any
261                         data = jQuery.makeArray( data );
262                         data.unshift( event );
263                 }
264
265                 event.currentTarget = elem;
266
267                 // Trigger the event, it is assumed that "handle" is a function
268                 var handle = jQuery.data( elem, "handle" );
269                 if ( handle ) {
270                         handle.apply( elem, data );
271                 }
272
273                 var nativeFn, nativeHandler;
274                 try {
275                         if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
276                                 nativeFn = elem[ type ];
277                                 nativeHandler = elem[ "on" + type ];
278                         }
279                 // prevent IE from throwing an error for some elements with some event types, see #3533
280                 } catch (e) {}
281
282                 var isClick = jQuery.nodeName(elem, "a") && type === "click";
283
284                 // Trigger the native events (except for clicks on links)
285                 if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !isClick ) {
286                         this.triggered = true;
287                         try {
288                                 elem[ type ]();
289                         // prevent IE from throwing an error for some hidden elements
290                         } catch (e) {}
291
292                 // Handle triggering native .onfoo handlers
293                 } else if ( nativeHandler && elem[ "on" + type ].apply( elem, data ) === false ) {
294                         event.result = false;
295                 }
296
297                 this.triggered = false;
298
299                 if ( !event.isPropagationStopped() ) {
300                         var parent = elem.parentNode || elem.ownerDocument;
301                         if ( parent ) {
302                                 jQuery.event.trigger( event, data, parent, true );
303                         }
304                 }
305         },
306
307         handle: function( event ) {
308                 // returned undefined or false
309                 var all, handlers;
310
311                 event = arguments[0] = jQuery.event.fix( event || window.event );
312                 event.currentTarget = this;
313
314                 // Namespaced event handlers
315                 var namespaces = event.type.split(".");
316                 event.type = namespaces.shift();
317
318                 // Cache this now, all = true means, any handler
319                 all = !namespaces.length && !event.exclusive;
320
321                 var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
322
323                 handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
324
325                 for ( var j in handlers ) {
326                         var handler = handlers[ j ];
327
328                         // Filter the functions by class
329                         if ( all || namespace.test(handler.type) ) {
330                                 // Pass in a reference to the handler function itself
331                                 // So that we can later remove it
332                                 event.handler = handler;
333                                 event.data = handler.data;
334
335                                 var ret = handler.apply( this, arguments );
336
337                                 if ( ret !== undefined ) {
338                                         event.result = ret;
339                                         if ( ret === false ) {
340                                                 event.preventDefault();
341                                                 event.stopPropagation();
342                                         }
343                                 }
344
345                                 if ( event.isImmediatePropagationStopped() ) {
346                                         break;
347                                 }
348
349                         }
350                 }
351
352                 return event.result;
353         },
354
355         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(" "),
356
357         fix: function( event ) {
358                 if ( event[ expando ] ) {
359                         return event;
360                 }
361
362                 // store a copy of the original event object
363                 // and "clone" to set read-only properties
364                 var originalEvent = event;
365                 event = jQuery.Event( originalEvent );
366
367                 for ( var i = this.props.length, prop; i; ) {
368                         prop = this.props[ --i ];
369                         event[ prop ] = originalEvent[ prop ];
370                 }
371
372                 // Fix target property, if necessary
373                 if ( !event.target ) {
374                         event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
375                 }
376
377                 // check if target is a textnode (safari)
378                 if ( event.target.nodeType === 3 ) {
379                         event.target = event.target.parentNode;
380                 }
381
382                 // Add relatedTarget, if necessary
383                 if ( !event.relatedTarget && event.fromElement ) {
384                         event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
385                 }
386
387                 // Calculate pageX/Y if missing and clientX/Y available
388                 if ( event.pageX == null && event.clientX != null ) {
389                         var doc = document.documentElement, body = document.body;
390                         event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
391                         event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
392                 }
393
394                 // Add which for key events
395                 if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
396                         event.which = event.charCode || event.keyCode;
397                 }
398
399                 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
400                 if ( !event.metaKey && event.ctrlKey ) {
401                         event.metaKey = event.ctrlKey;
402                 }
403
404                 // Add which for click: 1 === left; 2 === middle; 3 === right
405                 // Note: button is not normalized, so don't use it
406                 if ( !event.which && event.button !== undefined ) {
407                         event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
408                 }
409
410                 return event;
411         },
412
413         // Deprecated, use jQuery.guid instead
414         guid: 1E8,
415
416         // Deprecated, use jQuery.proxy instead
417         proxy: jQuery.proxy,
418
419         special: {
420                 ready: {
421                         // Make sure the ready event is setup
422                         setup: jQuery.bindReady,
423                         teardown: jQuery.noop
424                 },
425
426                 live: {
427                         add: function( proxy, data, namespaces, live ) {
428                                 jQuery.extend( proxy, data || {} );
429
430                                 proxy.guid += data.selector + data.live; 
431                                 jQuery.event.add( this, data.live, liveHandler, data ); 
432                                 
433                         },
434
435                         remove: function( namespaces ) {
436                                 if ( namespaces.length ) {
437                                         var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
438
439                                         jQuery.each( (jQuery.data(this, "events").live || {}), function() {
440                                                 if ( name.test(this.type) ) {
441                                                         remove++;
442                                                 }
443                                         });
444
445                                         if ( remove < 1 ) {
446                                                 jQuery.event.remove( this, namespaces[0], liveHandler );
447                                         }
448                                 }
449                         },
450                         special: {}
451                 },
452                 beforeunload: {
453                         setup: function( data, namespaces, fn ) {
454                                 // We only want to do this special case on windows
455                                 if ( this.setInterval ) {
456                                         this.onbeforeunload = fn;
457                                 }
458
459                                 return false;
460                         },
461                         teardown: function( namespaces, fn ) {
462                                 if ( this.onbeforeunload === fn ) {
463                                         this.onbeforeunload = null;
464                                 }
465                         }
466                 }
467         }
468 };
469
470 jQuery.Event = function( src ) {
471         // Allow instantiation without the 'new' keyword
472         if ( !this.preventDefault ) {
473                 return new jQuery.Event( src );
474         }
475
476         // Event object
477         if ( src && src.type ) {
478                 this.originalEvent = src;
479                 this.type = src.type;
480         // Event type
481         } else {
482                 this.type = src;
483         }
484
485         // timeStamp is buggy for some events on Firefox(#3843)
486         // So we won't rely on the native value
487         this.timeStamp = now();
488
489         // Mark it as fixed
490         this[ expando ] = true;
491 };
492
493 function returnFalse() {
494         return false;
495 }
496 function returnTrue() {
497         return true;
498 }
499
500 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
501 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
502 jQuery.Event.prototype = {
503         preventDefault: function() {
504                 this.isDefaultPrevented = returnTrue;
505
506                 var e = this.originalEvent;
507                 if ( !e ) {
508                         return;
509                 }
510                 
511                 // if preventDefault exists run it on the original event
512                 if ( e.preventDefault ) {
513                         e.preventDefault();
514                 }
515                 // otherwise set the returnValue property of the original event to false (IE)
516                 e.returnValue = false;
517         },
518         stopPropagation: function() {
519                 this.isPropagationStopped = returnTrue;
520
521                 var e = this.originalEvent;
522                 if ( !e ) {
523                         return;
524                 }
525                 // if stopPropagation exists run it on the original event
526                 if ( e.stopPropagation ) {
527                         e.stopPropagation();
528                 }
529                 // otherwise set the cancelBubble property of the original event to true (IE)
530                 e.cancelBubble = true;
531         },
532         stopImmediatePropagation: function() {
533                 this.isImmediatePropagationStopped = returnTrue;
534                 this.stopPropagation();
535         },
536         isDefaultPrevented: returnFalse,
537         isPropagationStopped: returnFalse,
538         isImmediatePropagationStopped: returnFalse
539 };
540
541 // Checks if an event happened on an element within another element
542 // Used in jQuery.event.special.mouseenter and mouseleave handlers
543 var withinElement = function( event ) {
544         // Check if mouse(over|out) are still within the same parent element
545         var parent = event.relatedTarget;
546
547         // Traverse up the tree
548         while ( parent && parent !== this ) {
549                 // Firefox sometimes assigns relatedTarget a XUL element
550                 // which we cannot access the parentNode property of
551                 try {
552                         parent = parent.parentNode;
553
554                 // assuming we've left the element since we most likely mousedover a xul element
555                 } catch(e) {
556                         break;
557                 }
558         }
559
560         if ( parent !== this ) {
561                 // set the correct event type
562                 event.type = event.data;
563
564                 // handle event if we actually just moused on to a non sub-element
565                 jQuery.event.handle.apply( this, arguments );
566         }
567
568 },
569
570 // In case of event delegation, we only need to rename the event.type,
571 // liveHandler will take care of the rest.
572 delegate = function( event ) {
573         event.type = event.data;
574         jQuery.event.handle.apply( this, arguments );
575 };
576
577 // Create mouseenter and mouseleave events
578 jQuery.each({
579         mouseenter: "mouseover",
580         mouseleave: "mouseout"
581 }, function( orig, fix ) {
582         jQuery.event.special[ orig ] = {
583                 setup: function( data ) {
584                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
585                 },
586                 teardown: function( data ) {
587                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
588                 }
589         };
590 });
591
592 // submit delegation
593 if ( !jQuery.support.submitBubbles ) {
594
595 jQuery.event.special.submit = {
596         setup: function( data, namespaces, fn ) {
597                 if ( this.nodeName.toLowerCase() !== "form" ) {
598                         jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
599                                 var elem = e.target, type = elem.type;
600
601                                 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
602                                         return trigger( "submit", this, arguments );
603                                 }
604                         });
605          
606                         jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
607                                 var elem = e.target, type = elem.type;
608
609                                 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
610                                         return trigger( "submit", this, arguments );
611                                 }
612                         });
613
614                 } else {
615                         return false;
616                 }
617         },
618
619         remove: function( namespaces, fn ) {
620                 jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
621                 jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
622         }
623 };
624
625 }
626
627 // change delegation, happens here so we have bind.
628 if ( !jQuery.support.changeBubbles ) {
629
630 var formElems = /textarea|input|select/i;
631
632 function getVal( elem ) {
633         var type = elem.type, val = elem.value;
634
635         if ( type === "radio" || type === "checkbox" ) {
636                 val = elem.checked;
637
638         } else if ( type === "select-multiple" ) {
639                 val = elem.selectedIndex > -1 ?
640                         jQuery.map( elem.options, function( elem ) {
641                                 return elem.selected;
642                         }).join("-") :
643                         "";
644
645         } else if ( elem.nodeName.toLowerCase() === "select" ) {
646                 val = elem.selectedIndex;
647         }
648
649         return val;
650 }
651
652 function testChange( e ) {
653                 var elem = e.target, data, val;
654
655                 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
656                         return;
657                 }
658
659                 data = jQuery.data( elem, "_change_data" );
660                 val = getVal(elem);
661
662                 if ( val === data ) {
663                         return;
664                 }
665
666                 // the current data will be also retrieved by beforeactivate
667                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
668                         jQuery.data( elem, "_change_data", val );
669                 }
670
671                 if ( elem.type !== "select" && (data != null || val) ) {
672                         e.type = "change";
673                         return jQuery.event.trigger( e, arguments[1], this );
674                 }
675 }
676
677 jQuery.event.special.change = {
678         filters: {
679                 focusout: testChange, 
680
681                 click: function( e ) {
682                         var elem = e.target, type = elem.type;
683
684                         if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
685                                 return testChange.call( this, e );
686                         }
687                 },
688
689                 // Change has to be called before submit
690                 // Keydown will be called before keypress, which is used in submit-event delegation
691                 keydown: function( e ) {
692                         var elem = e.target, type = elem.type;
693
694                         if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
695                                 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
696                                 type === "select-multiple" ) {
697                                 return testChange.call( this, e );
698                         }
699                 },
700
701                 // Beforeactivate happens also before the previous element is blurred
702                 // with this event you can't trigger a change event, but you can store
703                 // information/focus[in] is not needed anymore
704                 beforeactivate: function( e ) {
705                         var elem = e.target;
706
707                         if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
708                                 jQuery.data( elem, "_change_data", getVal(elem) );
709                         }
710                 }
711         },
712         setup: function( data, namespaces, fn ) {
713                 for ( var type in changeFilters ) {
714                         jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
715                 }
716
717                 return formElems.test( this.nodeName );
718         },
719         remove: function( namespaces, fn ) {
720                 for ( var type in changeFilters ) {
721                         jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
722                 }
723
724                 return formElems.test( this.nodeName );
725         }
726 };
727
728 var changeFilters = jQuery.event.special.change.filters;
729
730 }
731
732 function trigger( type, elem, args ) {
733         args[0].type = type;
734         return jQuery.event.handle.apply( elem, args );
735 }
736
737 // Create "bubbling" focus and blur events
738 if ( document.addEventListener ) {
739         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
740                 jQuery.event.special[ fix ] = {
741                         setup: function() {
742                                 this.addEventListener( orig, handler, true );
743                         }, 
744                         teardown: function() { 
745                                 this.removeEventListener( orig, handler, true );
746                         }
747                 };
748
749                 function handler( e ) { 
750                         e = jQuery.event.fix( e );
751                         e.type = fix;
752                         return jQuery.event.handle.call( this, e );
753                 }
754         });
755 }
756
757 jQuery.each(["bind", "one"], function( i, name ) {
758         jQuery.fn[ name ] = function( type, data, fn ) {
759                 // Handle object literals
760                 if ( typeof type === "object" ) {
761                         for ( var key in type ) {
762                                 this[ name ](key, data, type[key], fn);
763                         }
764                         return this;
765                 }
766                 
767                 if ( jQuery.isFunction( data ) ) {
768                         thisObject = fn;
769                         fn = data;
770                         data = undefined;
771                 }
772
773                 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
774                         jQuery( this ).unbind( event, handler );
775                         return fn.apply( this, arguments );
776                 }) : fn;
777
778                 return type === "unload" && name !== "one" ?
779                         this.one( type, data, fn, thisObject ) :
780                         this.each(function() {
781                                 jQuery.event.add( this, type, handler, data );
782                         });
783         };
784 });
785
786 jQuery.fn.extend({
787         unbind: function( type, fn ) {
788                 // Handle object literals
789                 if ( typeof type === "object" && !type.preventDefault ) {
790                         for ( var key in type ) {
791                                 this.unbind(key, type[key]);
792                         }
793                         return this;
794                 }
795
796                 return this.each(function() {
797                         jQuery.event.remove( this, type, fn );
798                 });
799         },
800         trigger: function( type, data ) {
801                 return this.each(function() {
802                         jQuery.event.trigger( type, data, this );
803                 });
804         },
805
806         triggerHandler: function( type, data ) {
807                 if ( this[0] ) {
808                         var event = jQuery.Event( type );
809                         event.preventDefault();
810                         event.stopPropagation();
811                         jQuery.event.trigger( event, data, this[0] );
812                         return event.result;
813                 }
814         },
815
816         toggle: function( fn ) {
817                 // Save reference to arguments for access in closure
818                 var args = arguments, i = 1;
819
820                 // link all the functions, so any of them can unbind this click handler
821                 while ( i < args.length ) {
822                         jQuery.proxy( fn, args[ i++ ] );
823                 }
824
825                 return this.click( jQuery.proxy( fn, function( event ) {
826                         // Figure out which function to execute
827                         var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
828                         jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
829
830                         // Make sure that clicks stop
831                         event.preventDefault();
832
833                         // and execute the function
834                         return args[ lastToggle ].apply( this, arguments ) || false;
835                 }));
836         },
837
838         hover: function( fnOver, fnOut ) {
839                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
840         },
841
842         live: function( type, data, fn ) {
843                 if ( jQuery.isFunction( data ) ) {
844                         fn = data;
845                         data = undefined;
846                 }
847
848                 jQuery( this.context ).bind( liveConvert( type, this.selector ), {
849                         data: data, selector: this.selector, live: type
850                 }, fn );
851
852                 return this;
853         },
854
855         die: function( type, fn ) {
856                 jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
857                 return this;
858         }
859 });
860
861 function liveHandler( event ) {
862         var stop = true, elems = [], selectors = [], args = arguments,
863                 related, match, fn, elem, j, i, data,
864                 live = jQuery.extend({}, jQuery.data( this, "events" ).live);
865
866         for ( j in live ) {
867                 fn = live[j];
868                 if ( fn.live === event.type ||
869                                 fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
870
871                         data = fn.data;
872                         if ( !(data.beforeFilter && data.beforeFilter[event.type] && 
873                                         !data.beforeFilter[event.type](event)) ) {
874                                 selectors.push( fn.selector );
875                         }
876                 } else {
877                         delete live[j];
878                 }
879         }
880
881         match = jQuery( event.target ).closest( selectors, event.currentTarget );
882
883         for ( i = 0, l = match.length; i < l; i++ ) {
884                 for ( j in live ) {
885                         fn = live[j];
886                         elem = match[i].elem;
887                         related = null;
888
889                         if ( match[i].selector === fn.selector ) {
890                                 // Those two events require additional checking
891                                 if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
892                                         related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
893                                 }
894
895                                 if ( !related || related !== elem ) {
896                                         elems.push({ elem: elem, fn: fn });
897                                 }
898                         }
899                 }
900         }
901
902         for ( i = 0, l = elems.length; i < l; i++ ) {
903                 match = elems[i];
904                 event.currentTarget = match.elem;
905                 event.data = match.fn.data;
906                 if ( match.fn.apply( match.elem, args ) === false ) {
907                         stop = false;
908                         break;
909                 }
910         }
911
912         return stop;
913 }
914
915 function liveConvert( type, selector ) {
916         return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
917 }
918
919 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
920         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
921         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
922
923         // Handle event binding
924         jQuery.fn[ name ] = function( fn ) {
925                 return fn ? this.bind( name, fn ) : this.trigger( name );
926         };
927
928         if ( jQuery.attrFn ) {
929                 jQuery.attrFn[ name ] = true;
930         }
931 });
932
933 // Prevent memory leaks in IE
934 // Window isn't included so as not to unbind existing unload events
935 // More info:
936 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
937 if ( window.attachEvent && !window.addEventListener ) {
938         window.attachEvent("onunload", function() {
939                 for ( var id in jQuery.cache ) {
940                         if ( jQuery.cache[ id ].handle ) {
941                                 // Try/Catch is to handle iframes being unloaded, see #4280
942                                 try {
943                                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
944                                 } catch(e) {}
945                         }
946                 }
947         });
948 }