Made a number of spacing changes to bring the code more-inline with the jQuery Core...
[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 = this.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 = this.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         guid: 1,
118         global: {},
119
120         // Detach an event or set of events from an element
121         remove: function( elem, types, handler ) {
122                 // don't do events on text and comment nodes
123                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
124                         return;
125                 }
126
127                 var events = jQuery.data( elem, "events" ), ret, type, fn;
128
129                 if ( events ) {
130                         // Unbind all events for the element
131                         if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
132                                 for ( type in events ) {
133                                         this.remove( elem, type + (types || "") );
134                                 }
135                         } else {
136                                 // types is actually an event object here
137                                 if ( types.type ) {
138                                         handler = types.handler;
139                                         types = types.type;
140                                 }
141
142                                 // Handle multiple events separated by a space
143                                 // jQuery(...).unbind("mouseover mouseout", fn);
144                                 types = types.split(/\s+/);
145                                 var i = 0;
146                                 while ( (type = types[ i++ ]) ) {
147                                         // Namespaced event handlers
148                                         var namespaces = type.split(".");
149                                         type = namespaces.shift();
150                                         var all = !namespaces.length,
151                                                 cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
152                                                 namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
153                                                 special = this.special[ type ] || {};
154
155                                         if ( events[ type ] ) {
156                                                 // remove the given handler for the given type
157                                                 if ( handler ) {
158                                                         fn = events[ type ][ handler.guid ];
159                                                         delete events[ type ][ handler.guid ];
160
161                                                 // remove all handlers for the given type
162                                                 } else {
163                                                         for ( var handle in events[ type ] ) {
164                                                                 // Handle the removal of namespaced events
165                                                                 if ( all || namespace.test( events[ type ][ handle ].type ) ) {
166                                                                         delete events[ type ][ handle ];
167                                                                 }
168                                                         }
169                                                 }
170
171                                                 if ( special.remove ) {
172                                                         special.remove.call( elem, namespaces, fn);
173                                                 }
174
175                                                 // remove generic event handler if no more handlers exist
176                                                 for ( ret in events[ type ] ) {
177                                                         break;
178                                                 }
179                                                 if ( !ret ) {
180                                                         if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
181                                                                 if ( elem.removeEventListener ) {
182                                                                         elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
183                                                                 } else if ( elem.detachEvent ) {
184                                                                         elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
185                                                                 }
186                                                         }
187                                                         ret = null;
188                                                         delete events[ type ];
189                                                 }
190                                         }
191                                 }
192                         }
193
194                         // Remove the expando if it's no longer used
195                         for ( ret in events ) {
196                                 break;
197                         }
198                         if ( !ret ) {
199                                 var handle = jQuery.data( elem, "handle" );
200                                 if ( handle ) {
201                                         handle.elem = null;
202                                 }
203                                 jQuery.removeData( elem, "events" );
204                                 jQuery.removeData( elem, "handle" );
205                         }
206                 }
207         },
208
209         // bubbling is internal
210         trigger: function( event, data, elem /*, bubbling */ ) {
211                 // Event object or event type
212                 var type = event.type || event,
213                         bubbling = arguments[3];
214
215                 if ( !bubbling ) {
216                         event = typeof event === "object" ?
217                                 // jQuery.Event object
218                                 event[expando] ? event :
219                                 // Object literal
220                                 jQuery.extend( jQuery.Event(type), event ) :
221                                 // Just the event type (string)
222                                 jQuery.Event(type);
223
224                         if ( type.indexOf("!") >= 0 ) {
225                                 event.type = type = type.slice(0, -1);
226                                 event.exclusive = true;
227                         }
228
229                         // Handle a global trigger
230                         if ( !elem ) {
231                                 // Don't bubble custom events when global (to avoid too much overhead)
232                                 event.stopPropagation();
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         proxy: function( fn, proxy, thisObject ) {
408                 if ( proxy !== undefined && !jQuery.isFunction( proxy ) ) {
409                         thisObject = proxy;
410                         proxy = undefined;
411                 }
412
413                 // FIXME: Should proxy be redefined to be applied with thisObject if defined?
414                 proxy = proxy || function() {
415                         return fn.apply( thisObject !== undefined ? thisObject : this, arguments );
416                 };
417
418                 // Set the guid of unique handler to the same of original handler, so it can be removed
419                 proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
420
421                 // So proxy can be declared as an argument
422                 return proxy;
423         },
424
425         special: {
426                 ready: {
427                         // Make sure the ready event is setup
428                         setup: jQuery.bindReady,
429                         teardown: function() {}
430                 },
431
432                 live: {
433                         add: function( proxy, data, namespaces, live ) {
434                                 jQuery.extend( proxy, data || {} );
435
436                                 proxy.guid += data.selector + data.live; 
437                                 jQuery.event.add( this, data.live, liveHandler, data ); 
438                                 
439                         },
440
441                         remove: function( namespaces ) {
442                                 if ( namespaces.length ) {
443                                         var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
444
445                                         jQuery.each( (jQuery.data(this, "events").live || {}), function() {
446                                                 if ( name.test(this.type) ) {
447                                                         remove++;
448                                                 }
449                                         });
450
451                                         if ( remove < 1 ) {
452                                                 jQuery.event.remove( this, namespaces[0], liveHandler );
453                                         }
454                                 }
455                         },
456                         special: {}
457                 },
458                 beforeunload: {
459                         setup: function( data, namespaces, fn ) {
460                                 // We only want to do this special case on windows
461                                 if ( this.setInterval ) {
462                                         this.onbeforeunload = fn;
463                                 }
464
465                                 return false;
466                         },
467                         teardown: function( namespaces, fn ) {
468                                 if ( this.onbeforeunload === fn ) {
469                                         this.onbeforeunload = null;
470                                 }
471                         }
472                 }
473         }
474 };
475
476 jQuery.Event = function( src ) {
477         // Allow instantiation without the 'new' keyword
478         if ( !this.preventDefault ) {
479                 return new jQuery.Event( src );
480         }
481
482         // Event object
483         if ( src && src.type ) {
484                 this.originalEvent = src;
485                 this.type = src.type;
486         // Event type
487         } else {
488                 this.type = src;
489         }
490
491         // timeStamp is buggy for some events on Firefox(#3843)
492         // So we won't rely on the native value
493         this.timeStamp = now();
494
495         // Mark it as fixed
496         this[ expando ] = true;
497 };
498
499 function returnFalse() {
500         return false;
501 }
502 function returnTrue() {
503         return true;
504 }
505
506 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
507 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
508 jQuery.Event.prototype = {
509         preventDefault: function() {
510                 this.isDefaultPrevented = returnTrue;
511
512                 var e = this.originalEvent;
513                 if ( !e ) {
514                         return;
515                 }
516                 
517                 // if preventDefault exists run it on the original event
518                 if ( e.preventDefault ) {
519                         e.preventDefault();
520                 }
521                 // otherwise set the returnValue property of the original event to false (IE)
522                 e.returnValue = false;
523         },
524         stopPropagation: function() {
525                 this.isPropagationStopped = returnTrue;
526
527                 var e = this.originalEvent;
528                 if ( !e ) {
529                         return;
530                 }
531                 // if stopPropagation exists run it on the original event
532                 if ( e.stopPropagation ) {
533                         e.stopPropagation();
534                 }
535                 // otherwise set the cancelBubble property of the original event to true (IE)
536                 e.cancelBubble = true;
537         },
538         stopImmediatePropagation: function() {
539                 this.isImmediatePropagationStopped = returnTrue;
540                 this.stopPropagation();
541         },
542         isDefaultPrevented: returnFalse,
543         isPropagationStopped: returnFalse,
544         isImmediatePropagationStopped: returnFalse
545 };
546
547 // Checks if an event happened on an element within another element
548 // Used in jQuery.event.special.mouseenter and mouseleave handlers
549 var withinElement = function( event ) {
550         // Check if mouse(over|out) are still within the same parent element
551         var parent = event.relatedTarget;
552
553         // Traverse up the tree
554         while ( parent && parent !== this ) {
555                 // Firefox sometimes assigns relatedTarget a XUL element
556                 // which we cannot access the parentNode property of
557                 try {
558                         parent = parent.parentNode;
559
560                 // assuming we've left the element since we most likely mousedover a xul element
561                 } catch(e) {
562                         break;
563                 }
564         }
565
566         if ( parent !== this ) {
567                 // set the correct event type
568                 event.type = event.data;
569
570                 // handle event if we actually just moused on to a non sub-element
571                 jQuery.event.handle.apply( this, arguments );
572         }
573
574 },
575
576 // In case of event delegation, we only need to rename the event.type,
577 // liveHandler will take care of the rest.
578 delegate = function( event ) {
579         event.type = event.data;
580         jQuery.event.handle.apply( this, arguments );
581 };
582
583 // Create mouseenter and mouseleave events
584 jQuery.each({
585         mouseenter: "mouseover",
586         mouseleave: "mouseout"
587 }, function( orig, fix ) {
588         jQuery.event.special[ orig ] = {
589                 setup: function( data ) {
590                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
591                 },
592                 teardown: function( data ) {
593                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
594                 }
595         };
596 });
597
598 // submit delegation
599 if ( !jQuery.support.submitBubbles ) {
600
601 jQuery.event.special.submit = {
602         setup: function( data, namespaces, fn ) {
603                 if ( this.nodeName.toLowerCase() !== "form" ) {
604                         jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
605                                 var elem = e.target, type = elem.type;
606
607                                 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
608                                         return trigger( "submit", this, arguments );
609                                 }
610                         });
611          
612                         jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
613                                 var elem = e.target, type = elem.type;
614
615                                 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
616                                         return trigger( "submit", this, arguments );
617                                 }
618                         });
619                 }
620         },
621
622         remove: function( namespaces, fn ) {
623                 jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
624                 jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
625         }
626 };
627
628 }
629
630 // change delegation, happens here so we have bind.
631 if ( !jQuery.support.changeBubbles ) {
632
633 var formElems = /textarea|input|select/i;
634
635 function getVal( elem ) {
636         var type = elem.type, val = elem.value;
637
638         if ( type === "radio" || type === "checkbox" ) {
639                 val = elem.checked;
640
641         } else if ( type === "select-multiple" ) {
642                 val = elem.selectedIndex > -1 ?
643                         jQuery.map( elem.options, function( elem ) {
644                                 return elem.selected;
645                         }).join("-") :
646                         "";
647
648         } else if ( elem.nodeName.toLowerCase() === "select" ) {
649                 val = elem.selectedIndex;
650         }
651
652         return val;
653 }
654
655 function testChange( e ) {
656                 var elem = e.target, data, val;
657
658                 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
659                         return;
660                 }
661
662                 data = jQuery.data( elem, "_change_data" );
663                 val = getVal(elem);
664
665                 if ( val === data ) {
666                         return;
667                 }
668
669                 // the current data will be also retrieved by beforeactivate
670                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
671                         jQuery.data( elem, "_change_data", val );
672                 }
673
674                 if ( elem.type !== "select" && (data != null || val) ) {
675                         e.type = "change";
676                         return jQuery.event.trigger( e, arguments[1], this );
677                 }
678 }
679
680 jQuery.event.special.change = {
681         filters: {
682                 focusout: testChange, 
683
684                 click: function( e ) {
685                         var elem = e.target, type = elem.type;
686
687                         if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
688                                 return testChange.call( this, e );
689                         }
690                 },
691
692                 // Change has to be called before submit
693                 // Keydown will be called before keypress, wich is used in submit-event delegation
694                 keydown: function( e ) {
695                         var elem = e.target, type = elem.type;
696
697                         if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
698                                 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
699                                 type === "select-multiple" ) {
700                                 return testChange.call( this, e );
701                         }
702                 },
703
704                 // Beforeactivate happens also before the previous element is blurred
705                 // with this event you can't trigger a change event, but you can store
706                 // information/focus[in] is not needed anymore
707                 beforeactivate: function( e ) {
708                         var elem = e.target;
709
710                         if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
711                                 jQuery.data( elem, "_change_data", getVal(elem) );
712                         }
713                 }
714         },
715         setup: function( data, namespaces, fn ) {
716                 for ( var type in changeFilters ) {
717                         jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
718                 }
719
720                 return formElems.test( this.nodeName );
721         },
722         remove: function( namespaces, fn ) {
723                 for ( var type in changeFilters ) {
724                         jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
725                 }
726
727                 return formElems.test( this.nodeName );
728         }
729 };
730
731 var changeFilters = jQuery.event.special.change.filters;
732
733 }
734
735 function trigger( type, elem, args ) {
736         args[0].type = type;
737         return jQuery.event.handle.apply( elem, args );
738 }
739
740 // Create "bubbling" focus and blur events
741 if ( document.addEventListener ) {
742         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
743                 jQuery.event.special[ fix ] = {
744                         setup: function() {
745                                 this.addEventListener( orig, handler, true );
746                         }, 
747                         teardown: function() { 
748                                 this.removeEventListener( orig, handler, true );
749                         }
750                 };
751
752                 function handler( e ) { 
753                         e = jQuery.event.fix( e );
754                         e.type = fix;
755                         return jQuery.event.handle.call( this, e );
756                 }
757         });
758 }
759
760 jQuery.each(["bind", "one"], function( i, name ) {
761         jQuery.fn[ name ] = function( type, data, fn, thisObject ) {
762                 // Handle object literals
763                 if ( typeof type === "object" ) {
764                         for ( var key in type ) {
765                                 this[ name ](key, data, type[key], fn);
766                         }
767                         return this;
768                 }
769                 
770                 if ( jQuery.isFunction( data ) ) {
771                         thisObject = fn;
772                         fn = data;
773                         data = undefined;
774                 }
775                 fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
776                 var handler = name === "one" ? jQuery.event.proxy( fn, function( event ) {
777                         jQuery( this ).unbind( event, handler );
778                         return fn.apply( this, arguments );
779                 }) : fn;
780                 return type === "unload" ? this.one(type, data, handler, thisObject) : 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.event.proxy( fn, args[ i++ ] );
823                 }
824
825                 return this.click( jQuery.event.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, thisObject ) {
843                 if ( jQuery.isFunction( data ) ) {
844                         if ( fn !== undefined ) {
845                                 thisObject = fn;
846                         }
847                         fn = data;
848                         data = undefined;
849                 }
850                 jQuery( this.context ).bind( liveConvert( type, this.selector ), {
851                         data: data, selector: this.selector, live: type
852                 }, fn, thisObject );
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 = true, elems = [], selectors = [], args = arguments,
864                 related, match, fn, elem, j, i, data,
865                 live = jQuery.extend({}, jQuery.data( this, "events" ).live);
866
867         for ( j in live ) {
868                 fn = live[j];
869                 if ( fn.live === event.type ||
870                                 fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
871
872                         data = fn.data;
873                         if ( !(data.beforeFilter && data.beforeFilter[event.type] && 
874                                         !data.beforeFilter[event.type](event)) ) {
875                                 selectors.push( fn.selector );
876                         }
877                 } else {
878                         delete live[j];
879                 }
880         }
881
882         match = jQuery( event.target ).closest( selectors, event.currentTarget );
883
884         for ( i = 0, l = match.length; i < l; i++ ) {
885                 for ( j in live ) {
886                         fn = live[j];
887                         elem = match[i].elem;
888                         related = null;
889
890                         if ( match[i].selector === fn.selector ) {
891                                 // Those two events require additional checking
892                                 if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
893                                         related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
894                                 }
895
896                                 if ( !related || related !== elem ) {
897                                         elems.push({ elem: elem, fn: fn });
898                                 }
899                         }
900                 }
901         }
902
903         for ( i = 0, l = elems.length; i < l; i++ ) {
904                 match = elems[i];
905                 event.currentTarget = match.elem;
906                 event.data = match.fn.data;
907                 if ( match.fn.apply( match.elem, args ) === false ) {
908                         stop = false;
909                         break;
910                 }
911         }
912
913         return stop;
914 }
915
916 function liveConvert( type, selector ) {
917         return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
918 }
919
920 jQuery.each( ("blur focus load resize scroll unload click dblclick " +
921         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
922         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
923
924         // Handle event binding
925         jQuery.fn[ name ] = function( fn ) {
926                 return fn ? this.bind( name, fn ) : this.trigger( name );
927         };
928
929         if ( jQuery.fnAttr ) {
930                 jQuery.fnAttr[ name ] = true;
931         }
932 });
933
934 // Prevent memory leaks in IE
935 // Window isn't included so as not to unbind existing unload events
936 // More info:
937 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
938 if ( window.attachEvent && !window.addEventListener ) {
939         window.attachEvent("onunload", function() {
940                 for ( var id in jQuery.cache ) {
941                         if ( jQuery.cache[ id ].handle ) {
942                                 // Try/Catch is to handle iframes being unloaded, see #4280
943                                 try {
944                                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
945                                 } catch(e) {}
946                         }
947                 }
948         });
949 }