Make sure that mousing over XUL elements results in no trigger of a mouseleave. Fixes...
[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 ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
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         // Firefox sometimes assigns relatedTarget a XUL element
608         // which we cannot access the parentNode property of
609         try {
610                 // Traverse up the tree
611                 while ( parent && parent !== this ) {
612                         parent = parent.parentNode;
613                 }
614
615                 if ( parent !== this ) {
616                         // set the correct event type
617                         event.type = event.data;
618
619                         // handle event if we actually just moused on to a non sub-element
620                         jQuery.event.handle.apply( this, arguments );
621                 }
622
623         // assuming we've left the element since we most likely mousedover a xul element
624         } catch(e) { }
625 },
626
627 // In case of event delegation, we only need to rename the event.type,
628 // liveHandler will take care of the rest.
629 delegate = function( event ) {
630         event.type = event.data;
631         jQuery.event.handle.apply( this, arguments );
632 };
633
634 // Create mouseenter and mouseleave events
635 jQuery.each({
636         mouseenter: "mouseover",
637         mouseleave: "mouseout"
638 }, function( orig, fix ) {
639         jQuery.event.special[ orig ] = {
640                 setup: function( data ) {
641                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
642                 },
643                 teardown: function( data ) {
644                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
645                 }
646         };
647 });
648
649 // submit delegation
650 if ( !jQuery.support.submitBubbles ) {
651
652         jQuery.event.special.submit = {
653                 setup: function( data, namespaces ) {
654                         if ( this.nodeName.toLowerCase() !== "form" ) {
655                                 jQuery.event.add(this, "click.specialSubmit", function( e ) {
656                                         var elem = e.target, type = elem.type;
657
658                                         if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
659                                                 return trigger( "submit", this, arguments );
660                                         }
661                                 });
662          
663                                 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
664                                         var elem = e.target, type = elem.type;
665
666                                         if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
667                                                 return trigger( "submit", this, arguments );
668                                         }
669                                 });
670
671                         } else {
672                                 return false;
673                         }
674                 },
675
676                 teardown: function( namespaces ) {
677                         jQuery.event.remove( this, ".specialSubmit" );
678                 }
679         };
680
681 }
682
683 // change delegation, happens here so we have bind.
684 if ( !jQuery.support.changeBubbles ) {
685
686         var formElems = /textarea|input|select/i,
687
688         changeFilters,
689
690         getVal = function( elem ) {
691                 var type = elem.type, val = elem.value;
692
693                 if ( type === "radio" || type === "checkbox" ) {
694                         val = elem.checked;
695
696                 } else if ( type === "select-multiple" ) {
697                         val = elem.selectedIndex > -1 ?
698                                 jQuery.map( elem.options, function( elem ) {
699                                         return elem.selected;
700                                 }).join("-") :
701                                 "";
702
703                 } else if ( elem.nodeName.toLowerCase() === "select" ) {
704                         val = elem.selectedIndex;
705                 }
706
707                 return val;
708         },
709
710         testChange = function testChange( e ) {
711                 var elem = e.target, data, val;
712
713                 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
714                         return;
715                 }
716
717                 data = jQuery.data( elem, "_change_data" );
718                 val = getVal(elem);
719
720                 // the current data will be also retrieved by beforeactivate
721                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
722                         jQuery.data( elem, "_change_data", val );
723                 }
724                 
725                 if ( data === undefined || val === data ) {
726                         return;
727                 }
728
729                 if ( data != null || val ) {
730                         e.type = "change";
731                         return jQuery.event.trigger( e, arguments[1], elem );
732                 }
733         };
734
735         jQuery.event.special.change = {
736                 filters: {
737                         focusout: testChange, 
738
739                         click: function( e ) {
740                                 var elem = e.target, type = elem.type;
741
742                                 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
743                                         return testChange.call( this, e );
744                                 }
745                         },
746
747                         // Change has to be called before submit
748                         // Keydown will be called before keypress, which is used in submit-event delegation
749                         keydown: function( e ) {
750                                 var elem = e.target, type = elem.type;
751
752                                 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
753                                         (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
754                                         type === "select-multiple" ) {
755                                         return testChange.call( this, e );
756                                 }
757                         },
758
759                         // Beforeactivate happens also before the previous element is blurred
760                         // with this event you can't trigger a change event, but you can store
761                         // information/focus[in] is not needed anymore
762                         beforeactivate: function( e ) {
763                                 var elem = e.target;
764                                 jQuery.data( elem, "_change_data", getVal(elem) );
765                         }
766                 },
767
768                 setup: function( data, namespaces ) {
769                         if ( this.type === "file" ) {
770                                 return false;
771                         }
772
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                         jQuery.event.remove( this, ".specialChange" );
782
783                         return formElems.test( this.nodeName );
784                 }
785         };
786
787         changeFilters = jQuery.event.special.change.filters;
788 }
789
790 function trigger( type, elem, args ) {
791         args[0].type = type;
792         return jQuery.event.handle.apply( elem, args );
793 }
794
795 // Create "bubbling" focus and blur events
796 if ( document.addEventListener ) {
797         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
798                 jQuery.event.special[ fix ] = {
799                         setup: function() {
800                                 this.addEventListener( orig, handler, true );
801                         }, 
802                         teardown: function() { 
803                                 this.removeEventListener( orig, handler, true );
804                         }
805                 };
806
807                 function handler( e ) { 
808                         e = jQuery.event.fix( e );
809                         e.type = fix;
810                         return jQuery.event.handle.call( this, e );
811                 }
812         });
813 }
814
815 jQuery.each(["bind", "one"], function( i, name ) {
816         jQuery.fn[ name ] = function( type, data, fn ) {
817                 // Handle object literals
818                 if ( typeof type === "object" ) {
819                         for ( var key in type ) {
820                                 this[ name ](key, data, type[key], fn);
821                         }
822                         return this;
823                 }
824                 
825                 if ( jQuery.isFunction( data ) ) {
826                         fn = data;
827                         data = undefined;
828                 }
829
830                 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
831                         jQuery( this ).unbind( event, handler );
832                         return fn.apply( this, arguments );
833                 }) : fn;
834
835                 if ( type === "unload" && name !== "one" ) {
836                         this.one( type, data, fn );
837
838                 } else {
839                         for ( var i = 0, l = this.length; i < l; i++ ) {
840                                 jQuery.event.add( this[i], type, handler, data );
841                         }
842                 }
843
844                 return this;
845         };
846 });
847
848 jQuery.fn.extend({
849         unbind: function( type, fn ) {
850                 // Handle object literals
851                 if ( typeof type === "object" && !type.preventDefault ) {
852                         for ( var key in type ) {
853                                 this.unbind(key, type[key]);
854                         }
855
856                 } else {
857                         for ( var i = 0, l = this.length; i < l; i++ ) {
858                                 jQuery.event.remove( this[i], type, fn );
859                         }
860                 }
861
862                 return this;
863         },
864         
865         delegate: function( selector, types, data, fn ) {
866                 return this.live( types, data, fn, selector );
867         },
868         
869         undelegate: function( selector, types, fn ) {
870                 if ( arguments.length === 0 ) {
871                                 return this.unbind( "live" );
872                 
873                 } else {
874                         return this.die( types, null, fn, selector );
875                 }
876         },
877         
878         trigger: function( type, data ) {
879                 return this.each(function() {
880                         jQuery.event.trigger( type, data, this );
881                 });
882         },
883
884         triggerHandler: function( type, data ) {
885                 if ( this[0] ) {
886                         var event = jQuery.Event( type );
887                         event.preventDefault();
888                         event.stopPropagation();
889                         jQuery.event.trigger( event, data, this[0] );
890                         return event.result;
891                 }
892         },
893
894         toggle: function( fn ) {
895                 // Save reference to arguments for access in closure
896                 var args = arguments, i = 1;
897
898                 // link all the functions, so any of them can unbind this click handler
899                 while ( i < args.length ) {
900                         jQuery.proxy( fn, args[ i++ ] );
901                 }
902
903                 return this.click( jQuery.proxy( fn, function( event ) {
904                         // Figure out which function to execute
905                         var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
906                         jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
907
908                         // Make sure that clicks stop
909                         event.preventDefault();
910
911                         // and execute the function
912                         return args[ lastToggle ].apply( this, arguments ) || false;
913                 }));
914         },
915
916         hover: function( fnOver, fnOut ) {
917                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
918         }
919 });
920
921 var liveMap = {
922         focus: "focusin",
923         blur: "focusout",
924         mouseenter: "mouseover",
925         mouseleave: "mouseout"
926 };
927
928 jQuery.each(["live", "die"], function( i, name ) {
929         jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
930                 var type, i = 0, match, namespaces, preType,
931                         selector = origSelector || this.selector,
932                         context = origSelector ? this : jQuery( this.context );
933
934                 if ( jQuery.isFunction( data ) ) {
935                         fn = data;
936                         data = undefined;
937                 }
938
939                 types = (types || "").split(" ");
940
941                 while ( (type = types[ i++ ]) != null ) {
942                         match = rnamespaces.exec( type );
943                         namespaces = "";
944
945                         if ( match )  {
946                                 namespaces = match[0];
947                                 type = type.replace( rnamespaces, "" );
948                         }
949
950                         if ( type === "hover" ) {
951                                 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
952                                 continue;
953                         }
954
955                         preType = type;
956
957                         if ( type === "focus" || type === "blur" ) {
958                                 types.push( liveMap[ type ] + namespaces );
959                                 type = type + namespaces;
960
961                         } else {
962                                 type = (liveMap[ type ] || type) + namespaces;
963                         }
964
965                         if ( name === "live" ) {
966                                 // bind live handler
967                                 context.each(function(){
968                                         jQuery.event.add( this, liveConvert( type, selector ),
969                                                 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
970                                 });
971
972                         } else {
973                                 // unbind live handler
974                                 context.unbind( liveConvert( type, selector ), fn );
975                         }
976                 }
977                 
978                 return this;
979         }
980 });
981
982 function liveHandler( event ) {
983         var stop, elems = [], selectors = [], args = arguments,
984                 related, match, handleObj, elem, j, i, l, data,
985                 events = jQuery.data( this, "events" );
986
987         // Make sure we avoid non-left-click bubbling in Firefox (#3861)
988         if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
989                 return;
990         }
991
992         event.liveFired = this;
993
994         var live = events.live.slice(0);
995
996         for ( j = 0; j < live.length; j++ ) {
997                 handleObj = live[j];
998
999                 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1000                         selectors.push( handleObj.selector );
1001
1002                 } else {
1003                         live.splice( j--, 1 );
1004                 }
1005         }
1006
1007         match = jQuery( event.target ).closest( selectors, event.currentTarget );
1008
1009         for ( i = 0, l = match.length; i < l; i++ ) {
1010                 for ( j = 0; j < live.length; j++ ) {
1011                         handleObj = live[j];
1012
1013                         if ( match[i].selector === handleObj.selector ) {
1014                                 elem = match[i].elem;
1015                                 related = null;
1016
1017                                 // Those two events require additional checking
1018                                 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1019                                         related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1020                                 }
1021
1022                                 if ( !related || related !== elem ) {
1023                                         elems.push({ elem: elem, handleObj: handleObj });
1024                                 }
1025                         }
1026                 }
1027         }
1028
1029         for ( i = 0, l = elems.length; i < l; i++ ) {
1030                 match = elems[i];
1031                 event.currentTarget = match.elem;
1032                 event.data = match.handleObj.data;
1033                 event.handleObj = match.handleObj;
1034
1035                 if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {
1036                         stop = false;
1037                         break;
1038                 }
1039         }
1040
1041         return stop;
1042 }
1043
1044 function liveConvert( type, selector ) {
1045         return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
1046 }
1047
1048 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1049         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1050         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1051
1052         // Handle event binding
1053         jQuery.fn[ name ] = function( fn ) {
1054                 return fn ? this.bind( name, fn ) : this.trigger( name );
1055         };
1056
1057         if ( jQuery.attrFn ) {
1058                 jQuery.attrFn[ name ] = true;
1059         }
1060 });
1061
1062 // Prevent memory leaks in IE
1063 // Window isn't included so as not to unbind existing unload events
1064 // More info:
1065 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1066 if ( window.attachEvent && !window.addEventListener ) {
1067         window.attachEvent("onunload", function() {
1068                 for ( var id in jQuery.cache ) {
1069                         if ( jQuery.cache[ id ].handle ) {
1070                                 // Try/Catch is to handle iframes being unloaded, see #4280
1071                                 try {
1072                                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
1073                                 } catch(e) {}
1074                         }
1075                 }
1076         });
1077 }