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