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