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