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