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