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