a17cf8947beadcd359c775a85aed48cbfc05346e
[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         // Chrome does something similar, the parentNode property
656         // can be accessed but is null.
657         try {
658                 // Traverse up the tree
659                 while ( parent && parent !== this ) {
660                         parent = parent.parentNode;
661                 }
662
663                 if ( parent && parent !== this ) {
664                         // set the correct event type
665                         event.type = event.data;
666
667                         // handle event if we actually just moused on to a non sub-element
668                         jQuery.event.handle.apply( this, arguments );
669                 }
670
671         // assuming we've left the element since we most likely mousedover a xul element
672         } catch(e) { }
673 },
674
675 // In case of event delegation, we only need to rename the event.type,
676 // liveHandler will take care of the rest.
677 delegate = function( event ) {
678         event.type = event.data;
679         jQuery.event.handle.apply( this, arguments );
680 };
681
682 // Create mouseenter and mouseleave events
683 jQuery.each({
684         mouseenter: "mouseover",
685         mouseleave: "mouseout"
686 }, function( orig, fix ) {
687         jQuery.event.special[ orig ] = {
688                 setup: function( data ) {
689                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
690                 },
691                 teardown: function( data ) {
692                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
693                 }
694         };
695 });
696
697 // submit delegation
698 if ( !jQuery.support.submitBubbles ) {
699
700         jQuery.event.special.submit = {
701                 setup: function( data, namespaces ) {
702                         if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) {
703                                 jQuery.event.add(this, "click.specialSubmit", function( e ) {
704                                         var elem = e.target,
705                                                 type = elem.type;
706
707                                         if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
708                                                 e.liveFired = undefined;
709                                                 return trigger( "submit", this, arguments );
710                                         }
711                                 });
712
713                                 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
714                                         var elem = e.target,
715                                                 type = elem.type;
716
717                                         if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
718                                                 e.liveFired = undefined;
719                                                 return trigger( "submit", this, arguments );
720                                         }
721                                 });
722
723                         } else {
724                                 return false;
725                         }
726                 },
727
728                 teardown: function( namespaces ) {
729                         jQuery.event.remove( this, ".specialSubmit" );
730                 }
731         };
732
733 }
734
735 // change delegation, happens here so we have bind.
736 if ( !jQuery.support.changeBubbles ) {
737
738         var changeFilters,
739
740         getVal = function( elem ) {
741                 var type = elem.type, val = elem.value;
742
743                 if ( type === "radio" || type === "checkbox" ) {
744                         val = elem.checked;
745
746                 } else if ( type === "select-multiple" ) {
747                         val = elem.selectedIndex > -1 ?
748                                 jQuery.map( elem.options, function( elem ) {
749                                         return elem.selected;
750                                 }).join("-") :
751                                 "";
752
753                 } else if ( elem.nodeName.toLowerCase() === "select" ) {
754                         val = elem.selectedIndex;
755                 }
756
757                 return val;
758         },
759
760         testChange = function testChange( e ) {
761                 var elem = e.target, data, val;
762
763                 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
764                         return;
765                 }
766
767                 data = jQuery._data( elem, "_change_data" );
768                 val = getVal(elem);
769
770                 // the current data will be also retrieved by beforeactivate
771                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
772                         jQuery._data( elem, "_change_data", val );
773                 }
774
775                 if ( data === undefined || val === data ) {
776                         return;
777                 }
778
779                 if ( data != null || val ) {
780                         e.type = "change";
781                         e.liveFired = undefined;
782                         return jQuery.event.trigger( e, arguments[1], elem );
783                 }
784         };
785
786         jQuery.event.special.change = {
787                 filters: {
788                         focusout: testChange,
789
790                         beforedeactivate: testChange,
791
792                         click: function( e ) {
793                                 var elem = e.target, type = elem.type;
794
795                                 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
796                                         return testChange.call( this, e );
797                                 }
798                         },
799
800                         // Change has to be called before submit
801                         // Keydown will be called before keypress, which is used in submit-event delegation
802                         keydown: function( e ) {
803                                 var elem = e.target, type = elem.type;
804
805                                 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
806                                         (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
807                                         type === "select-multiple" ) {
808                                         return testChange.call( this, e );
809                                 }
810                         },
811
812                         // Beforeactivate happens also before the previous element is blurred
813                         // with this event you can't trigger a change event, but you can store
814                         // information
815                         beforeactivate: function( e ) {
816                                 var elem = e.target;
817                                 jQuery._data( elem, "_change_data", getVal(elem) );
818                         }
819                 },
820
821                 setup: function( data, namespaces ) {
822                         if ( this.type === "file" ) {
823                                 return false;
824                         }
825
826                         for ( var type in changeFilters ) {
827                                 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
828                         }
829
830                         return rformElems.test( this.nodeName );
831                 },
832
833                 teardown: function( namespaces ) {
834                         jQuery.event.remove( this, ".specialChange" );
835
836                         return rformElems.test( this.nodeName );
837                 }
838         };
839
840         changeFilters = jQuery.event.special.change.filters;
841
842         // Handle when the input is .focus()'d
843         changeFilters.focus = changeFilters.beforeactivate;
844 }
845
846 function trigger( type, elem, args ) {
847         args[0].type = type;
848         return jQuery.event.handle.apply( elem, args );
849 }
850
851 // Create "bubbling" focus and blur events
852 if ( document.addEventListener ) {
853         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
854                 jQuery.event.special[ fix ] = {
855                         setup: function() {
856                                 this.addEventListener( orig, handler, true );
857                         },
858                         teardown: function() {
859                                 this.removeEventListener( orig, handler, true );
860                         }
861                 };
862
863                 function handler( e ) {
864                         e = jQuery.event.fix( e );
865                         e.type = fix;
866                         return jQuery.event.handle.call( this, e );
867                 }
868         });
869 }
870
871 jQuery.each(["bind", "one"], function( i, name ) {
872         jQuery.fn[ name ] = function( type, data, fn ) {
873                 // Handle object literals
874                 if ( typeof type === "object" ) {
875                         for ( var key in type ) {
876                                 this[ name ](key, data, type[key], fn);
877                         }
878                         return this;
879                 }
880
881                 if ( jQuery.isFunction( data ) || data === false ) {
882                         fn = data;
883                         data = undefined;
884                 }
885
886                 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
887                         jQuery( this ).unbind( event, handler );
888                         return fn.apply( this, arguments );
889                 }) : fn;
890
891                 if ( type === "unload" && name !== "one" ) {
892                         this.one( type, data, fn );
893
894                 } else {
895                         for ( var i = 0, l = this.length; i < l; i++ ) {
896                                 jQuery.event.add( this[i], type, handler, data );
897                         }
898                 }
899
900                 return this;
901         };
902 });
903
904 jQuery.fn.extend({
905         unbind: function( type, fn ) {
906                 // Handle object literals
907                 if ( typeof type === "object" && !type.preventDefault ) {
908                         for ( var key in type ) {
909                                 this.unbind(key, type[key]);
910                         }
911
912                 } else {
913                         for ( var i = 0, l = this.length; i < l; i++ ) {
914                                 jQuery.event.remove( this[i], type, fn );
915                         }
916                 }
917
918                 return this;
919         },
920
921         delegate: function( selector, types, data, fn ) {
922                 return this.live( types, data, fn, selector );
923         },
924
925         undelegate: function( selector, types, fn ) {
926                 if ( arguments.length === 0 ) {
927                                 return this.unbind( "live" );
928
929                 } else {
930                         return this.die( types, null, fn, selector );
931                 }
932         },
933
934         trigger: function( type, data ) {
935                 return this.each(function() {
936                         jQuery.event.trigger( type, data, this );
937                 });
938         },
939
940         triggerHandler: function( type, data ) {
941                 if ( this[0] ) {
942                         var event = jQuery.Event( type );
943                         event.preventDefault();
944                         event.stopPropagation();
945                         jQuery.event.trigger( event, data, this[0] );
946                         return event.result;
947                 }
948         },
949
950         toggle: function( fn ) {
951                 // Save reference to arguments for access in closure
952                 var args = arguments,
953                         i = 1;
954
955                 // link all the functions, so any of them can unbind this click handler
956                 while ( i < args.length ) {
957                         jQuery.proxy( fn, args[ i++ ] );
958                 }
959
960                 return this.click( jQuery.proxy( fn, function( event ) {
961                         // Figure out which function to execute
962                         var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
963                         jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
964
965                         // Make sure that clicks stop
966                         event.preventDefault();
967
968                         // and execute the function
969                         return args[ lastToggle ].apply( this, arguments ) || false;
970                 }));
971         },
972
973         hover: function( fnOver, fnOut ) {
974                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
975         }
976 });
977
978 var liveMap = {
979         focus: "focusin",
980         blur: "focusout",
981         mouseenter: "mouseover",
982         mouseleave: "mouseout"
983 };
984
985 jQuery.each(["live", "die"], function( i, name ) {
986         jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
987                 var type, i = 0, match, namespaces, preType,
988                         selector = origSelector || this.selector,
989                         context = origSelector ? this : jQuery( this.context );
990
991                 if ( typeof types === "object" && !types.preventDefault ) {
992                         for ( var key in types ) {
993                                 context[ name ]( key, data, types[key], selector );
994                         }
995
996                         return this;
997                 }
998
999                 if ( jQuery.isFunction( data ) ) {
1000                         fn = data;
1001                         data = undefined;
1002                 }
1003
1004                 types = (types || "").split(" ");
1005
1006                 while ( (type = types[ i++ ]) != null ) {
1007                         match = rnamespaces.exec( type );
1008                         namespaces = "";
1009
1010                         if ( match )  {
1011                                 namespaces = match[0];
1012                                 type = type.replace( rnamespaces, "" );
1013                         }
1014
1015                         if ( type === "hover" ) {
1016                                 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1017                                 continue;
1018                         }
1019
1020                         preType = type;
1021
1022                         if ( type === "focus" || type === "blur" ) {
1023                                 types.push( liveMap[ type ] + namespaces );
1024                                 type = type + namespaces;
1025
1026                         } else {
1027                                 type = (liveMap[ type ] || type) + namespaces;
1028                         }
1029
1030                         if ( name === "live" ) {
1031                                 // bind live handler
1032                                 for ( var j = 0, l = context.length; j < l; j++ ) {
1033                                         jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1034                                                 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1035                                 }
1036
1037                         } else {
1038                                 // unbind live handler
1039                                 context.unbind( "live." + liveConvert( type, selector ), fn );
1040                         }
1041                 }
1042
1043                 return this;
1044         };
1045 });
1046
1047 function liveHandler( event ) {
1048         var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1049                 elems = [],
1050                 selectors = [],
1051                 events = jQuery._data( this, "events" );
1052
1053         // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1054         if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1055                 return;
1056         }
1057
1058         if ( event.namespace ) {
1059                 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1060         }
1061
1062         event.liveFired = this;
1063
1064         var live = events.live.slice(0);
1065
1066         for ( j = 0; j < live.length; j++ ) {
1067                 handleObj = live[j];
1068
1069                 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1070                         selectors.push( handleObj.selector );
1071
1072                 } else {
1073                         live.splice( j--, 1 );
1074                 }
1075         }
1076
1077         match = jQuery( event.target ).closest( selectors, event.currentTarget );
1078
1079         for ( i = 0, l = match.length; i < l; i++ ) {
1080                 close = match[i];
1081
1082                 for ( j = 0; j < live.length; j++ ) {
1083                         handleObj = live[j];
1084
1085                         if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
1086                                 elem = close.elem;
1087                                 related = null;
1088
1089                                 // Those two events require additional checking
1090                                 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1091                                         event.type = handleObj.preType;
1092                                         related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1093                                 }
1094
1095                                 if ( !related || related !== elem ) {
1096                                         elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1097                                 }
1098                         }
1099                 }
1100         }
1101
1102         for ( i = 0, l = elems.length; i < l; i++ ) {
1103                 match = elems[i];
1104
1105                 if ( maxLevel && match.level > maxLevel ) {
1106                         break;
1107                 }
1108
1109                 event.currentTarget = match.elem;
1110                 event.data = match.handleObj.data;
1111                 event.handleObj = match.handleObj;
1112
1113                 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1114
1115                 if ( ret === false || event.isPropagationStopped() ) {
1116                         maxLevel = match.level;
1117
1118                         if ( ret === false ) {
1119                                 stop = false;
1120                         }
1121                         if ( event.isImmediatePropagationStopped() ) {
1122                                 break;
1123                         }
1124                 }
1125         }
1126
1127         return stop;
1128 }
1129
1130 function liveConvert( type, selector ) {
1131         return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
1132 }
1133
1134 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1135         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1136         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1137
1138         // Handle event binding
1139         jQuery.fn[ name ] = function( data, fn ) {
1140                 if ( fn == null ) {
1141                         fn = data;
1142                         data = null;
1143                 }
1144
1145                 return arguments.length > 0 ?
1146                         this.bind( name, data, fn ) :
1147                         this.trigger( name );
1148         };
1149
1150         if ( jQuery.attrFn ) {
1151                 jQuery.attrFn[ name ] = true;
1152         }
1153 });
1154
1155 })( jQuery );