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