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