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