jquery event: adding some whitespaces to the last change.
[jquery.git] / src / event.js
index f2e5fc6..4c710c1 100644 (file)
@@ -7,11 +7,14 @@ jQuery.event = {
 
        // Bind an event to an element
        // Original by Dean Edwards
-       add: function(element, type, handler, data) {
+       add: function(elem, types, handler, data) {
+               if ( elem.nodeType == 3 || elem.nodeType == 8 )
+                       return;
+
                // For whatever reason, IE has trouble passing the window object
                // around, causing it to be cloned in the process
-               if ( jQuery.browser.msie && element.setInterval != undefined )
-                       element = window;
+               if ( jQuery.browser.msie && elem.setInterval != undefined )
+                       elem = window;
 
                // Make sure that the function being executed has a unique ID
                if ( !handler.guid )
@@ -19,7 +22,7 @@ jQuery.event = {
                        
                // if data is passed, bind to handler 
                if( data != undefined ) { 
-                       // Create temporary function pointer to original handler 
+                       // Create temporary function pointer to original handler 
                        var fn = handler; 
 
                        // Create unique handler function, wrapped around original handler 
@@ -35,149 +38,197 @@ jQuery.event = {
                        handler.guid = fn.guid;
                }
 
-               // Namespaced event handlers
-               var parts = type.split(".");
-               type = parts[0];
-               handler.type = parts[1];
-
                // Init the element's event structure
-               var events = jQuery.data(element, "events") || jQuery.data(element, "events", {});
-               
-               var handle = jQuery.data(element, "handle", function(){
-                       // returned undefined or false
-                       var val;
-
-                       // Handle the second event of a trigger and when
-                       // an event is called after a page has unloaded
-                       if ( typeof jQuery == "undefined" || jQuery.event.triggered )
-                               return val;
-                       
-                       val = jQuery.event.handle.apply(element, arguments);
+               var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+                       handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+                               // Handle the second event of a trigger and when
+                               // an event is called after a page has unloaded
+                               if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
+                                       return jQuery.event.handle.apply(arguments.callee.elem, arguments);
+                       });
+               // Add elem as a property of the handle function
+               // This is to prevent a memory leak with non-native
+               // event in IE.
+               handle.elem = elem;
                        
-                       return val;
-               });
-
-               // Get the current list of functions bound to this event
-               var handlers = events[type];
-
-               // Init the event handler queue
-               if (!handlers) {
-                       handlers = events[type] = {};   
-                       
-                       // And bind the global event handler to the element
-                       if (element.addEventListener)
-                               element.addEventListener(type, handle, false);
-                       else
-                               element.attachEvent("on" + type, handle);
-               }
+                       // Handle multiple events seperated by a space
+                       // jQuery(...).bind("mouseover mouseout", fn);
+                       jQuery.each(types.split(/\s+/), function(index, type) {
+                               // Namespaced event handlers
+                               var parts = type.split(".");
+                               type = parts[0];
+                               handler.type = parts[1];
+
+                               // Get the current list of functions bound to this event
+                               var handlers = events[type];
+
+                               // Init the event handler queue
+                               if (!handlers) {
+                                       handlers = events[type] = {};
+               
+                                       // Check for a special event handler
+                                       // Only use addEventListener/attachEvent if the special
+                                       // events handler returns false
+                                       if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
+                                               // Bind the global event handler to the element
+                                               if (elem.addEventListener)
+                                                       elem.addEventListener(type, handle, false);
+                                               else if (elem.attachEvent)
+                                                       elem.attachEvent("on" + type, handle);
+                                       }
+                               }
 
-               // Add the function to the element's handler list
-               handlers[handler.guid] = handler;
+                               // Add the function to the element's handler list
+                               handlers[handler.guid] = handler;
 
-               // Keep track of which events have been used, for global triggering
-               this.global[type] = true;
+                               // Keep track of which events have been used, for global triggering
+                               jQuery.event.global[type] = true;
+                       });
+               
+               // Nullify elem to prevent memory leaks in IE
+               elem = null;
        },
 
        guid: 1,
        global: {},
 
        // Detach an event or set of events from an element
-       remove: function(element, type, handler) {
-               var events = jQuery.data(element, "events"), ret, index;
+       remove: function(elem, types, handler) {
+               // don't do events on text and comment nodes
+               if ( elem.nodeType == 3 || elem.nodeType == 8 )
+                       return;
 
-               // Namespaced event handlers
-               if ( typeof type == "string" ) {
-                       var parts = type.split(".");
-                       type = parts[0];
-               }
+               var events = jQuery.data(elem, "events"), ret, index;
 
                if ( events ) {
-                       // type is actually an event object here
-                       if ( type && type.type ) {
-                               handler = type.handler;
-                               type = type.type;
-                       }
-                       
-                       if ( !type ) {
-                               for ( type in events )
-                                       this.remove( element, type );
-
-                       } else if ( events[type] ) {
-                               // remove the given handler for the given type
-                               if ( handler )
-                                       delete events[type][handler.guid];
-                               
-                               // remove all handlers for the given type
-                               else
-                                       for ( handler in events[type] )
-                                               // Handle the removal of namespaced events
-                                               if ( !parts[1] || events[type][handler].type == parts[1] )
-                                                       delete events[type][handler];
-
-                               // remove generic event handler if no more handlers exist
-                               for ( ret in events[type] ) break;
-                               if ( !ret ) {
-                                       if (element.removeEventListener)
-                                               element.removeEventListener(type, jQuery.data(element, "handle"), false);
-                                       else
-                                               element.detachEvent("on" + type, jQuery.data(element, "handle"));
-                                       ret = null;
-                                       delete events[type];
+                       // Unbind all events for the element
+                       if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
+                               for ( var type in events )
+                                       this.remove( elem, type + (types || "") );
+                       else {
+                               // types is actually an event object here
+                               if ( types.type ) {
+                                       handler = types.handler;
+                                       types = types.type;
                                }
+                               
+                               // Handle multiple events seperated by a space
+                               // jQuery(...).unbind("mouseover mouseout", fn);
+                               jQuery.each(types.split(/\s+/), function(index, type){
+                                       // Namespaced event handlers
+                                       var parts = type.split(".");
+                                       type = parts[0];
+                                       
+                                       if ( events[type] ) {
+                                               // remove the given handler for the given type
+                                               if ( handler )
+                                                       delete events[type][handler.guid];
+                       
+                                               // remove all handlers for the given type
+                                               else
+                                                       for ( handler in events[type] )
+                                                               // Handle the removal of namespaced events
+                                                               if ( !parts[1] || events[type][handler].type == parts[1] )
+                                                                       delete events[type][handler];
+
+                                               // remove generic event handler if no more handlers exist
+                                               for ( ret in events[type] ) break;
+                                               if ( !ret ) {
+                                                       if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
+                                                               if (elem.removeEventListener)
+                                                                       elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+                                                               else if (elem.detachEvent)
+                                                                       elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+                                                       }
+                                                       ret = null;
+                                                       delete events[type];
+                                               }
+                                       }
+                               });
                        }
 
                        // Remove the expando if it's no longer used
                        for ( ret in events ) break;
                        if ( !ret ) {
-                               jQuery.removeData( element, "events" );
-                               jQuery.removeData( element, "handle" );
+                               var handle = jQuery.data( elem, "handle" );
+                               if ( handle ) handle.elem = null;
+                               jQuery.removeData( elem, "events" );
+                               jQuery.removeData( elem, "handle" );
                        }
                }
        },
 
-       trigger: function(type, data, element, donative, extra) {
+       trigger: function(type, data, elem, donative, extra) {
                // Clone the incoming data, if any
-               data = jQuery.makeArray(data || []);
+               data = jQuery.makeArray(data);
+
+               if ( type.indexOf("!") >= 0 ) {
+                       type = type.slice(0, -1);
+                       var exclusive = true;
+               }
 
                // Handle a global trigger
-               if ( !element ) {
+               if ( !elem ) {
                        // Only trigger if we've ever bound an event for it
                        if ( this.global[type] )
                                jQuery("*").add([window, document]).trigger(type, data);
 
                // Handle triggering a single element
                } else {
-                       var val, ret, fn = jQuery.isFunction( element[ type ] || null ),
+                       // don't do events on text and comment nodes
+                       if ( elem.nodeType == 3 || elem.nodeType == 8 )
+                               return undefined;
+
+                       var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
                                // Check to see if we need to provide a fake event, or not
-                               evt = !data[0] || !data[0].preventDefault;
+                               event = !data[0] || !data[0].preventDefault;
                        
                        // Pass along a fake event
-                       if ( evt )
-                               data.unshift( this.fix({ type: type, target: element }) );
+                       if ( event ) {
+                               data.unshift({ 
+                                       type: type, 
+                                       target: elem, 
+                                       preventDefault: function(){}, 
+                                       stopPropagation: function(){}, 
+                                       timeStamp: +new Date
+                               });
+                               data[0][expando] = true; // no need to fix fake event
+                       }
 
                        // Enforce the right trigger type
                        data[0].type = type;
+                       if ( exclusive )
+                               data[0].exclusive = true;
 
-                       // Trigger the event
-                       if ( jQuery.isFunction( jQuery.data(element, "handle") ) )
-                               val = jQuery.data(element, "handle").apply( element, data );
+                       // Trigger the event, it is assumed that "handle" is a function
+                       var handle = jQuery.data(elem, "handle"); 
+                       if ( handle ) 
+                               val = handle.apply( elem, data );
 
-                       // Handle triggering native .onfoo handlers
-                       if ( !fn && element["on"+type] && element["on"+type].apply( element, data ) === false )
+                       // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+                       if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
                                val = false;
 
                        // Extra functions don't get the custom event object
-                       if ( evt )
+                       if ( event )
                                data.shift();
 
                        // Handle triggering of extra function
-                       if ( extra && extra.apply( element, data ) === false )
-                               val = false;
+                       if ( extra && jQuery.isFunction( extra ) ) {
+                               // call the extra function and tack the current return value on the end for possible inspection
+                               ret = extra.apply( elem, val == null ? data : data.concat( val ) );
+                               // if anything is returned, give it precedence and have it overwrite the previous value
+                               if (ret !== undefined)
+                                       val = ret;
+                       }
 
                        // Trigger the native events (except for clicks on links)
-                       if ( fn && donative !== false && val !== false && !(jQuery.nodeName(element, 'a') && type == "click") ) {
+                       if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
                                this.triggered = true;
-                               element[ type ]();
+                               try {
+                                       elem[ type ]();
+                               // prevent IE from throwing an error for some hidden elements
+                               } catch (e) {}
                        }
 
                        this.triggered = false;
@@ -188,51 +239,57 @@ jQuery.event = {
 
        handle: function(event) {
                // returned undefined or false
-               var val;
+               var val, ret, namespace, all, handlers;
 
-               // Empty object is for triggered events with no data
-               event = jQuery.event.fix( event || window.event || {} ); 
+               event = arguments[0] = jQuery.event.fix( event || window.event );
 
                // Namespaced event handlers
-               var parts = event.type.split(".");
-               event.type = parts[0];
+               namespace = event.type.split(".");
+               event.type = namespace[0];
+               namespace = namespace[1];
+               all = !namespace && !event.exclusive; //cache this now, all = true means, any handler
 
-               var c = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
-               args.unshift( event );
+               handlers = ( jQuery.data(this, "events") || {} )[event.type];
 
-               for ( var j in c ) {
-                       // Pass in a reference to the handler function itself
-                       // So that we can later remove it
-                       args[0].handler = c[j];
-                       args[0].data = c[j].data;
+               for ( var j in handlers ) {
+                       var handler = handlers[j];
 
                        // Filter the functions by class
-                       if ( !parts[1] || c[j].type == parts[1] ) {
-                               var tmp = c[j].apply( this, args );
+                       if ( all || handler.type == namespace ) {
+                               // Pass in a reference to the handler function itself
+                               // So that we can later remove it
+                               event.handler = handler;
+                               event.data = handler.data;
+                               
+                               ret = handler.apply( this, arguments );
 
                                if ( val !== false )
-                                       val = tmp;
+                                       val = ret;
 
-                               if ( tmp === false ) {
+                               if ( ret === false ) {
                                        event.preventDefault();
                                        event.stopPropagation();
                                }
                        }
                }
 
-               // Clean up added properties in IE to prevent memory leak
-               if (jQuery.browser.msie)
-                       event.target = event.preventDefault = event.stopPropagation =
-                               event.handler = event.data = null;
-
                return val;
        },
 
        fix: function(event) {
+               if ( event[expando] == true ) 
+                       return event;
+               
                // store a copy of the original event object 
-               // and clone to set read-only properties
+               // and "clone" to set read-only properties
                var originalEvent = event;
-               event = jQuery.extend({}, originalEvent);
+               event = { originalEvent: originalEvent };
+               var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
+               for ( var i=props.length; i; i-- )
+                       event[ props[i] ] = originalEvent[ props[i] ];
+               
+               // Mark it as fixed
+               event[expando] = true;
                
                // add preventDefault and stopPropagation since 
                // they will not work on the clone
@@ -251,13 +308,16 @@ jQuery.event = {
                        originalEvent.cancelBubble = true;
                };
                
+               // Fix timeStamp
+               event.timeStamp = event.timeStamp || +new Date;
+               
                // Fix target property, if necessary
-               if ( !event.target && event.srcElement )
-                       event.target = event.srcElement;
+               if ( !event.target )
+                       event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
                                
                // check if target is a textnode (safari)
-               if (jQuery.browser.safari && event.target.nodeType == 3)
-                       event.target = originalEvent.target.parentNode;
+               if ( event.target.nodeType == 3 )
+                       event.target = event.target.parentNode;
 
                // Add relatedTarget, if necessary
                if ( !event.relatedTarget && event.fromElement )
@@ -265,13 +325,13 @@ jQuery.event = {
 
                // Calculate pageX/Y if missing and clientX/Y available
                if ( event.pageX == null && event.clientX != null ) {
-                       var e = document.documentElement, b = document.body;
-                       event.pageX = event.clientX + (e && e.scrollLeft || b.scrollLeft || 0);
-                       event.pageY = event.clientY + (e && e.scrollTop || b.scrollTop || 0);
+                       var doc = document.documentElement, body = document.body;
+                       event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+                       event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
                }
                        
                // Add which for key events
-               if ( !event.which && (event.charCode || event.keyCode) )
+               if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
                        event.which = event.charCode || event.keyCode;
                
                // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
@@ -284,6 +344,62 @@ jQuery.event = {
                        event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
                        
                return event;
+       },
+       
+       special: {
+               ready: {
+                       setup: function() {
+                               // Make sure the ready event is setup
+                               bindReady();
+                               return;
+                       },
+                       
+                       teardown: function() { return; }
+               },
+               
+               mouseenter: {
+                       setup: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
+                               return true;
+                       },
+               
+                       teardown: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
+                               return true;
+                       },
+                       
+                       handler: function(event) {
+                               // If we actually just moused on to a sub-element, ignore it
+                               if ( withinElement(event, this) ) return true;
+                               // Execute the right handlers by setting the event type to mouseenter
+                               arguments[0].type = "mouseenter";
+                               return jQuery.event.handle.apply(this, arguments);
+                       }
+               },
+       
+               mouseleave: {
+                       setup: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
+                               return true;
+                       },
+               
+                       teardown: function() {
+                               if ( jQuery.browser.msie ) return false;
+                               jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
+                               return true;
+                       },
+                       
+                       handler: function(event) {
+                               // If we actually just moused on to a sub-element, ignore it
+                               if ( withinElement(event, this) ) return true;
+                               // Execute the right handlers by setting the event type to mouseleave
+                               arguments[0].type = "mouseleave";
+                               return jQuery.event.handle.apply(this, arguments);
+                       }
+               }
        }
 };
 
@@ -318,70 +434,50 @@ jQuery.fn.extend({
        triggerHandler: function( type, data, fn ) {
                if ( this[0] )
                        return jQuery.event.trigger( type, data, this[0], false, fn );
+               return undefined;
        },
 
        toggle: function() {
                // Save reference to arguments for access in closure
-               var a = arguments;
+               var args = arguments;
 
-               return this.click(function(e) {
+               return this.click(function(event) {
                        // Figure out which function to execute
-                       this.lastToggle = 0 == this.lastToggle ? 1 : 0;
+                       this.lastToggle = ( this.lastToggle || 0 ) % args.length;
                        
                        // Make sure that clicks stop
-                       e.preventDefault();
+                       event.preventDefault();
                        
                        // and execute the function
-                       return a[this.lastToggle].apply( this, [e] ) || false;
+                       return args[ this.lastToggle++ ].apply( this, arguments ) || false;
                });
        },
 
-       hover: function(f,g) {
-               
-               // A private function for handling mouse 'hovering'
-               function handleHover(e) {
-                       // Check if mouse(over|out) are still within the same parent element
-                       var p = e.relatedTarget;
-       
-                       // Traverse up the tree
-                       while ( p && p != this ) try { p = p.parentNode; } catch(e) { p = this; };
-                       
-                       // If we actually just moused on to a sub-element, ignore it
-                       if ( p == this ) return false;
-                       
-                       // Execute the right function
-                       return (e.type == "mouseover" ? f : g).apply(this, [e]);
-               }
-               
-               // Bind the function to the two event listeners
-               return this.mouseover(handleHover).mouseout(handleHover);
+       hover: function(fnOver, fnOut) {
+               return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
        },
        
-       ready: function(f) {
+       ready: function(fn) {
                // Attach the listeners
                bindReady();
 
                // If the DOM is already ready
                if ( jQuery.isReady )
                        // Execute the function immediately
-                       f.apply( document, [jQuery] );
+                       fn.call( document, jQuery );
                        
                // Otherwise, remember the function for later
                else
                        // Add the function to the wait list
-                       jQuery.readyList.push( function() { return f.apply(this, [jQuery]); } );
+                       jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
        
                return this;
        }
 });
 
 jQuery.extend({
-       /*
-        * All the code that makes DOM Ready work nicely.
-        */
        isReady: false,
        readyList: [],
-       
        // Handle when the DOM is ready
        ready: function() {
                // Make sure that the DOM is not already loaded
@@ -399,77 +495,99 @@ jQuery.extend({
                                // Reset the list of functions
                                jQuery.readyList = null;
                        }
-                       // Remove event listener to avoid memory leak
-                       if ( jQuery.browser.mozilla || jQuery.browser.opera )
-                               document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
-                       
-                       // Remove script element used by IE hack
-                       if( !window.frames.length ) // don't remove if frames are present (#1187)
-                               jQuery(window).load(function(){ jQuery("#__ie_init").remove(); });
+               
+                       // Trigger any bound ready events
+                       jQuery(document).triggerHandler("ready");
                }
        }
 });
 
-
-jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
-       "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + 
-       "submit,keydown,keypress,keyup,error").split(","), function(i,o){
-       
-       // Handle event binding
-       jQuery.fn[o] = function(f){
-               return f ? this.bind(o, f) : this.trigger(o);
-       };
-});
-
 var readyBound = false;
 
 function bindReady(){
        if ( readyBound ) return;
        readyBound = true;
 
-       // If Mozilla is used
-       if ( jQuery.browser.mozilla || jQuery.browser.opera )
+       // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
+       if ( document.addEventListener && !jQuery.browser.opera)
                // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
        
-       // If IE is used, use the excellent hack by Matthias Miller
-       // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited
-       else if ( jQuery.browser.msie ) {
-       
-               // Only works if you document.write() it
-               document.write("<scr" + "ipt id=__ie_init defer=true " + 
-                       "src=//:><\/script>");
-       
-               // Use the defer script hack
-               var script = document.getElementById("__ie_init");
-               
-               // script does not exist if jQuery is loaded dynamically
-               if ( script ) 
-                       script.onreadystatechange = function() {
-                               if ( this.readyState != "complete" ) return;
-                               jQuery.ready();
-                       };
-       
-               // Clear from memory
-               script = null;
-       
-       // If Safari  is used
-       } else if ( jQuery.browser.safari )
-               // Continually check to see if the document.readyState is valid
-               jQuery.safariTimer = setInterval(function(){
-                       // loaded and complete are both valid states
-                       if ( document.readyState == "loaded" || 
-                               document.readyState == "complete" ) {
-       
-                               // If either one are found, remove the timer
-                               clearInterval( jQuery.safariTimer );
-                               jQuery.safariTimer = null;
-       
-                               // and execute any waiting functions
-                               jQuery.ready();
+       // If IE is used and is not in a frame
+       // Continually check to see if the document is ready
+       if ( jQuery.browser.msie && window == top ) (function(){
+               if (jQuery.isReady) return;
+               try {
+                       // If IE is used, use the trick by Diego Perini
+                       // http://javascript.nwbox.com/IEContentLoaded/
+                       document.documentElement.doScroll("left");
+               } catch( error ) {
+                       setTimeout( arguments.callee, 0 );
+                       return;
+               }
+               // and execute any waiting functions
+               jQuery.ready();
+       })();
+
+       if ( jQuery.browser.opera )
+               document.addEventListener( "DOMContentLoaded", function () {
+                       if (jQuery.isReady) return;
+                       for (var i = 0; i < document.styleSheets.length; i++)
+                               if (document.styleSheets[i].disabled) {
+                                       setTimeout( arguments.callee, 0 );
+                                       return;
+                               }
+                       // and execute any waiting functions
+                       jQuery.ready();
+               }, false);
+
+       if ( jQuery.browser.safari ) {
+               var numStyles;
+               (function(){
+                       if (jQuery.isReady) return;
+                       if ( document.readyState != "loaded" && document.readyState != "complete" ) {
+                               setTimeout( arguments.callee, 0 );
+                               return;
+                       }
+                       if ( numStyles === undefined )
+                               numStyles = jQuery("style, link[rel=stylesheet]").length;
+                       if ( document.styleSheets.length != numStyles ) {
+                               setTimeout( arguments.callee, 0 );
+                               return;
                        }
-               }, 10); 
+                       // and execute any waiting functions
+                       jQuery.ready();
+               })();
+       }
 
        // A fallback to window.onload, that will always work
        jQuery.event.add( window, "load", jQuery.ready );
 }
+
+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
+       "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + 
+       "submit,keydown,keypress,keyup,error").split(","), function(i, name){
+       
+       // Handle event binding
+       jQuery.fn[name] = function(fn){
+               return fn ? this.bind(name, fn) : this.trigger(name);
+       };
+});
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event, elem) {
+       // Check if mouse(over|out) are still within the same parent element
+       var parent = event.relatedTarget;
+       // Traverse up the tree
+       while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
+       // Return true if we actually just moused on to a sub-element
+       return parent == elem;
+};
+
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery(window).bind("unload", function() {
+       jQuery("*").add(document).unbind();
+});