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