Make sure that live handlers don't stop inline scripts from executing. Fixes #5835.
[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                                 data.liveProxy = proxy;
432
433                                 jQuery.event.add( this, data.live, liveHandler, data ); 
434                                 
435                         },
436
437                         remove: function( namespaces ) {
438                                 if ( namespaces.length ) {
439                                         var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
440
441                                         jQuery.each( (jQuery.data(this, "events").live || {}), function() {
442                                                 if ( name.test(this.type) ) {
443                                                         remove++;
444                                                 }
445                                         });
446
447                                         if ( remove < 1 ) {
448                                                 jQuery.event.remove( this, namespaces[0], liveHandler );
449                                         }
450                                 }
451                         },
452                         special: {}
453                 },
454                 beforeunload: {
455                         setup: function( data, namespaces, fn ) {
456                                 // We only want to do this special case on windows
457                                 if ( this.setInterval ) {
458                                         this.onbeforeunload = fn;
459                                 }
460
461                                 return false;
462                         },
463                         teardown: function( namespaces, fn ) {
464                                 if ( this.onbeforeunload === fn ) {
465                                         this.onbeforeunload = null;
466                                 }
467                         }
468                 }
469         }
470 };
471
472 jQuery.Event = function( src ) {
473         // Allow instantiation without the 'new' keyword
474         if ( !this.preventDefault ) {
475                 return new jQuery.Event( src );
476         }
477
478         // Event object
479         if ( src && src.type ) {
480                 this.originalEvent = src;
481                 this.type = src.type;
482         // Event type
483         } else {
484                 this.type = src;
485         }
486
487         // timeStamp is buggy for some events on Firefox(#3843)
488         // So we won't rely on the native value
489         this.timeStamp = now();
490
491         // Mark it as fixed
492         this[ expando ] = true;
493 };
494
495 function returnFalse() {
496         return false;
497 }
498 function returnTrue() {
499         return true;
500 }
501
502 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
503 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
504 jQuery.Event.prototype = {
505         preventDefault: function() {
506                 this.isDefaultPrevented = returnTrue;
507
508                 var e = this.originalEvent;
509                 if ( !e ) {
510                         return;
511                 }
512                 
513                 // if preventDefault exists run it on the original event
514                 if ( e.preventDefault ) {
515                         e.preventDefault();
516                 }
517                 // otherwise set the returnValue property of the original event to false (IE)
518                 e.returnValue = false;
519         },
520         stopPropagation: function() {
521                 this.isPropagationStopped = returnTrue;
522
523                 var e = this.originalEvent;
524                 if ( !e ) {
525                         return;
526                 }
527                 // if stopPropagation exists run it on the original event
528                 if ( e.stopPropagation ) {
529                         e.stopPropagation();
530                 }
531                 // otherwise set the cancelBubble property of the original event to true (IE)
532                 e.cancelBubble = true;
533         },
534         stopImmediatePropagation: function() {
535                 this.isImmediatePropagationStopped = returnTrue;
536                 this.stopPropagation();
537         },
538         isDefaultPrevented: returnFalse,
539         isPropagationStopped: returnFalse,
540         isImmediatePropagationStopped: returnFalse
541 };
542
543 // Checks if an event happened on an element within another element
544 // Used in jQuery.event.special.mouseenter and mouseleave handlers
545 var withinElement = function( event ) {
546         // Check if mouse(over|out) are still within the same parent element
547         var parent = event.relatedTarget;
548
549         // Traverse up the tree
550         while ( parent && parent !== this ) {
551                 // Firefox sometimes assigns relatedTarget a XUL element
552                 // which we cannot access the parentNode property of
553                 try {
554                         parent = parent.parentNode;
555
556                 // assuming we've left the element since we most likely mousedover a xul element
557                 } catch(e) {
558                         break;
559                 }
560         }
561
562         if ( parent !== this ) {
563                 // set the correct event type
564                 event.type = event.data;
565
566                 // handle event if we actually just moused on to a non sub-element
567                 jQuery.event.handle.apply( this, arguments );
568         }
569
570 },
571
572 // In case of event delegation, we only need to rename the event.type,
573 // liveHandler will take care of the rest.
574 delegate = function( event ) {
575         event.type = event.data;
576         jQuery.event.handle.apply( this, arguments );
577 };
578
579 // Create mouseenter and mouseleave events
580 jQuery.each({
581         mouseenter: "mouseover",
582         mouseleave: "mouseout"
583 }, function( orig, fix ) {
584         jQuery.event.special[ orig ] = {
585                 setup: function( data ) {
586                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
587                 },
588                 teardown: function( data ) {
589                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
590                 }
591         };
592 });
593
594 // submit delegation
595 if ( !jQuery.support.submitBubbles ) {
596
597 jQuery.event.special.submit = {
598         setup: function( data, namespaces, fn ) {
599                 if ( this.nodeName.toLowerCase() !== "form" ) {
600                         jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
601                                 var elem = e.target, type = elem.type;
602
603                                 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
604                                         return trigger( "submit", this, arguments );
605                                 }
606                         });
607          
608                         jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
609                                 var elem = e.target, type = elem.type;
610
611                                 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
612                                         return trigger( "submit", this, arguments );
613                                 }
614                         });
615
616                 } else {
617                         return false;
618                 }
619         },
620
621         remove: function( namespaces, fn ) {
622                 jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
623                 jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
624         }
625 };
626
627 }
628
629 // change delegation, happens here so we have bind.
630 if ( !jQuery.support.changeBubbles ) {
631
632 var formElems = /textarea|input|select/i;
633
634 function getVal( elem ) {
635         var type = elem.type, val = elem.value;
636
637         if ( type === "radio" || type === "checkbox" ) {
638                 val = elem.checked;
639
640         } else if ( type === "select-multiple" ) {
641                 val = elem.selectedIndex > -1 ?
642                         jQuery.map( elem.options, function( elem ) {
643                                 return elem.selected;
644                         }).join("-") :
645                         "";
646
647         } else if ( elem.nodeName.toLowerCase() === "select" ) {
648                 val = elem.selectedIndex;
649         }
650
651         return val;
652 }
653
654 function testChange( e ) {
655                 var elem = e.target, data, val;
656
657                 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
658                         return;
659                 }
660
661                 data = jQuery.data( elem, "_change_data" );
662                 val = getVal(elem);
663
664                 if ( val === data ) {
665                         return;
666                 }
667
668                 // the current data will be also retrieved by beforeactivate
669                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
670                         jQuery.data( elem, "_change_data", val );
671                 }
672
673                 if ( data != null || val ) {
674                         e.type = "change";
675                         return jQuery.event.trigger( e, arguments[1], elem );
676                 }
677 }
678
679 jQuery.event.special.change = {
680         filters: {
681                 focusout: testChange, 
682
683                 click: function( e ) {
684                         var elem = e.target, type = elem.type;
685
686                         if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
687                                 return testChange.call( this, e );
688                         }
689                 },
690
691                 // Change has to be called before submit
692                 // Keydown will be called before keypress, which is used in submit-event delegation
693                 keydown: function( e ) {
694                         var elem = e.target, type = elem.type;
695
696                         if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
697                                 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
698                                 type === "select-multiple" ) {
699                                 return testChange.call( this, e );
700                         }
701                 },
702
703                 // Beforeactivate happens also before the previous element is blurred
704                 // with this event you can't trigger a change event, but you can store
705                 // information/focus[in] is not needed anymore
706                 beforeactivate: function( e ) {
707                         var elem = e.target;
708
709                         if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
710                                 jQuery.data( elem, "_change_data", getVal(elem) );
711                         }
712                 }
713         },
714         setup: function( data, namespaces, fn ) {
715                 for ( var type in changeFilters ) {
716                         jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
717                 }
718
719                 return formElems.test( this.nodeName );
720         },
721         remove: function( namespaces, fn ) {
722                 for ( var type in changeFilters ) {
723                         jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
724                 }
725
726                 return formElems.test( this.nodeName );
727         }
728 };
729
730 var changeFilters = jQuery.event.special.change.filters;
731
732 }
733
734 function trigger( type, elem, args ) {
735         args[0].type = type;
736         return jQuery.event.handle.apply( elem, args );
737 }
738
739 // Create "bubbling" focus and blur events
740 if ( document.addEventListener ) {
741         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
742                 jQuery.event.special[ fix ] = {
743                         setup: function() {
744                                 this.addEventListener( orig, handler, true );
745                         }, 
746                         teardown: function() { 
747                                 this.removeEventListener( orig, handler, true );
748                         }
749                 };
750
751                 function handler( e ) { 
752                         e = jQuery.event.fix( e );
753                         e.type = fix;
754                         return jQuery.event.handle.call( this, e );
755                 }
756         });
757 }
758
759 jQuery.each(["bind", "one"], function( i, name ) {
760         jQuery.fn[ name ] = function( type, data, fn ) {
761                 // Handle object literals
762                 if ( typeof type === "object" ) {
763                         for ( var key in type ) {
764                                 this[ name ](key, data, type[key], fn);
765                         }
766                         return this;
767                 }
768                 
769                 if ( jQuery.isFunction( data ) ) {
770                         fn = data;
771                         data = undefined;
772                 }
773
774                 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
775                         jQuery( this ).unbind( event, handler );
776                         return fn.apply( this, arguments );
777                 }) : fn;
778
779                 return type === "unload" && name !== "one" ?
780                         this.one( type, data, fn ) :
781                         this.each(function() {
782                                 jQuery.event.add( this, type, handler, data );
783                         });
784         };
785 });
786
787 jQuery.fn.extend({
788         unbind: function( type, fn ) {
789                 // Handle object literals
790                 if ( typeof type === "object" && !type.preventDefault ) {
791                         for ( var key in type ) {
792                                 this.unbind(key, type[key]);
793                         }
794                         return this;
795                 }
796
797                 return this.each(function() {
798                         jQuery.event.remove( this, type, fn );
799                 });
800         },
801         trigger: function( type, data ) {
802                 return this.each(function() {
803                         jQuery.event.trigger( type, data, this );
804                 });
805         },
806
807         triggerHandler: function( type, data ) {
808                 if ( this[0] ) {
809                         var event = jQuery.Event( type );
810                         event.preventDefault();
811                         event.stopPropagation();
812                         jQuery.event.trigger( event, data, this[0] );
813                         return event.result;
814                 }
815         },
816
817         toggle: function( fn ) {
818                 // Save reference to arguments for access in closure
819                 var args = arguments, i = 1;
820
821                 // link all the functions, so any of them can unbind this click handler
822                 while ( i < args.length ) {
823                         jQuery.proxy( fn, args[ i++ ] );
824                 }
825
826                 return this.click( jQuery.proxy( fn, function( event ) {
827                         // Figure out which function to execute
828                         var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
829                         jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
830
831                         // Make sure that clicks stop
832                         event.preventDefault();
833
834                         // and execute the function
835                         return args[ lastToggle ].apply( this, arguments ) || false;
836                 }));
837         },
838
839         hover: function( fnOver, fnOut ) {
840                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
841         },
842
843         live: function( type, data, fn ) {
844                 if ( jQuery.isFunction( data ) ) {
845                         fn = data;
846                         data = undefined;
847                 }
848
849                 jQuery( this.context ).bind( liveConvert( type, this.selector ), {
850                         data: data, selector: this.selector, live: type
851                 }, fn );
852
853                 return this;
854         },
855
856         die: function( type, fn ) {
857                 jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
858                 return this;
859         }
860 });
861
862 function liveHandler( event ) {
863         var stop, elems = [], selectors = [], args = arguments,
864                 related, match, fn, elem, j, i, l, data,
865                 live = jQuery.extend({}, jQuery.data( this, "events" ).live);
866
867         // Make sure we avoid non-left-click bubbling in Firefox (#3861)
868         if ( event.button && event.type === "click" ) {
869                 return;
870         }
871
872         for ( j in live ) {
873                 fn = live[j];
874                 if ( fn.live === event.type ||
875                                 fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
876
877                         data = fn.data;
878                         if ( !(data.beforeFilter && data.beforeFilter[event.type] && 
879                                         !data.beforeFilter[event.type](event)) ) {
880                                 selectors.push( fn.selector );
881                         }
882                 } else {
883                         delete live[j];
884                 }
885         }
886
887         match = jQuery( event.target ).closest( selectors, event.currentTarget );
888
889         for ( i = 0, l = match.length; i < l; i++ ) {
890                 for ( j in live ) {
891                         fn = live[j];
892                         elem = match[i].elem;
893                         related = null;
894
895                         if ( match[i].selector === fn.selector ) {
896                                 // Those two events require additional checking
897                                 if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
898                                         related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
899                                 }
900
901                                 if ( !related || related !== elem ) {
902                                         elems.push({ elem: elem, fn: fn });
903                                 }
904                         }
905                 }
906         }
907
908         for ( i = 0, l = elems.length; i < l; i++ ) {
909                 match = elems[i];
910                 event.currentTarget = match.elem;
911                 event.data = match.fn.data;
912                 if ( match.fn.apply( match.elem, args ) === false ) {
913                         stop = false;
914                         break;
915                 }
916         }
917
918         return stop;
919 }
920
921 function liveConvert( type, selector ) {
922         return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
923 }
924
925 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
926         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
927         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
928
929         // Handle event binding
930         jQuery.fn[ name ] = function( fn ) {
931                 return fn ? this.bind( name, fn ) : this.trigger( name );
932         };
933
934         if ( jQuery.attrFn ) {
935                 jQuery.attrFn[ name ] = true;
936         }
937 });
938
939 // Prevent memory leaks in IE
940 // Window isn't included so as not to unbind existing unload events
941 // More info:
942 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
943 if ( window.attachEvent && !window.addEventListener ) {
944         window.attachEvent("onunload", function() {
945                 for ( var id in jQuery.cache ) {
946                         if ( jQuery.cache[ id ].handle ) {
947                                 // Try/Catch is to handle iframes being unloaded, see #4280
948                                 try {
949                                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
950                                 } catch(e) {}
951                         }
952                 }
953         });
954 }