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