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