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