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