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