I've cleaned up and documented the events plugin, it's close to being ready for 1.0.
authorJohn Resig <jeresig@gmail.com>
Mon, 19 Jun 2006 00:12:14 +0000 (00:12 +0000)
committerJohn Resig <jeresig@gmail.com>
Mon, 19 Jun 2006 00:12:14 +0000 (00:12 +0000)
event/event.js

index fcd590a..bd1bb27 100644 (file)
-(function(){
-       var e = ["blur","focus","contextmenu","load","resize","scroll","unload",
-               "click","dblclick","mousedown","mouseup","mouseenter","mouseleave",
-               "mousemove","mouseover","mouseout","change","reset","select","submit",
-               "keydown","keypress","keyup","abort","error","ready"];
+// We're overriding the old toggle function, so
+// remember it for later
+$.fn._toggle = $.fn.toggle;
 
-       for ( var i = 0; i < e.length; i++ ) {
-               (function(){
-                       var o = e[i];
-                       $.fn[o] = function(f){ return this.bind(o, f); };
-                       $.fn["un"+o] = function(f){ return this.unbind(o, f); };
-                       $.fn["do"+o] = function(){ return this.trigger(o); };
-                       $.fn["one"+o] = function(f){ return this.bind(o, function(e){
-                               if ( this[o+f] !== null ) { return true; }
-                               this[o+f]++;
-                               return $.apply(this,f,[e]);
-                       }); };
+/**
+ * Toggle between two function calls every other click.
+ */
+$.fn.toggle = function(a,b) {
+       // If two functions are passed in, we're
+       // toggling on a click
+       return a && b ? this.click(function(e){
+               // Figure out which function to execute
+               this.last = this.last == a ? b : a;
                
-                       // Deprecated
-                       //$.fn["on"+o] = function(f){ return this.bind(o, f); };
-               })();
-       }
-})();
-
-$.fn.hover = function(f,g) {
-       // Check if mouse(over|out) are still within the same parent element
-       return this.each(function(){
-               var obj = this;
-               $.event.add(this, "mouseover", function(e) {
-                       var p = ( e.fromElement !== null ? e.fromElement : e.relatedTarget );
-                       while ( p && p != obj ) { p = p.parentNode; }
-                       if ( p == obj ) { return false; }
-                       return $.apply(obj,f,[e]);
-               });
-               $.event.add(this, "mouseout", function(e) {
-                       var p = ( e.toElement !== null ? e.toElement : e.relatedTarget );
-                       while ( p && p != obj ) { p = p.parentNode; }
-                       if ( p == obj ) { return false; }
-                       return $.apply(obj,g,[e]);
-               });
-       });
+               // Make sure that clicks don't pass through
+               e.preventDefault();
+               
+               // and execute the function
+               return $.apply( this, this.last, [e] ) || false;
+       }) :
+       
+       // Otherwise, execute the old toggle function
+       this._toggle();
 };
 
-$.$$isReady = false;
-$.$$ready = [];
-
-// Handle when the DOM is ready
-$.ready = function() {
-       if ( !$.$$isReady ) {
-               $.$$isReady = true;
-               if ( $.$$ready ) {
-                       for ( var i = 0; i < $.$$ready.length; i++ ) {
-                               $.apply( document, $.$$ready[i] );
-                       }
-                       $.$$ready = [];
-               }
+/**
+ * Toggle between two function calls on mouse over/out.
+ */
+$.fn.hover = function(f,g) {
+       
+       // A private function for haandling mouse 'hovering'
+       function handleHover(e) {
+               // Check if mouse(over|out) are still within the same parent element
+               var p = e.fromElement || e.toElement || e.relatedTarget;
+               while ( p && p != this ) p = p.parentNode;
+               
+               // If we actually just moused on to a sub-element, ignore it
+               if ( p == this ) return false;
+               
+               // Execute the right function
+               return $.apply(this,e.type == 'mouseover' ? f : g,[e]);
        }
+       
+       // Bind the function to the two event listeners
+       return this.mouseover(handleHover).mouseout(handleHover);
 };
 
-// If Mozilla is used
-if ( $.browser == "mozilla" || $.browser == "opera" ) {
-       // Use the handy event callback
-       document.addEventListener( "DOMContentLoaded", $.ready, null );
-
-// 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 ( $.browser == "msie" ) {
-
-       // Only works if you document.write() it
-       document.write('<scr' + 'ipt id=__ie_init defer=true ' + 
-               'src=javascript:void(0)><\/script>');
-
-       // Use the defer script hack
-       var script = document.getElementById('__ie_init');
-       script.onreadystatechange = function() {
-               if ( this.readyState == 'complete' ) {
-                       $.ready();
-               }
-       };
-
-       // Clear from memory
-       script = null;
-
-// If Safari  is used
-} else if ( $.browser == "safari" ) {
-       $.$$timer = setInterval(function(){
-       if ( document.readyState == "loaded" || 
-                       document.readyState == "complete" ) {
-
-                       clearInterval( $.$$timer );
-                       $.$$timer = null;
-
-                       $.ready();
-               }
-       }, 10);
-}
-
-// A fallback, that will always work, just in case
-$.event.add( window, "load", $.ready );
-
 /**
  * Bind a function to fire when the DOM is ready.
  */
 $.fn.ready = function(f) {
-       if ( $.$$isReady ) {
+       // If the DOM is already ready
+       if ( $.isReady )
+               // Execute the function immediately
                $.apply( document, f );
-       } else {
-               if ( ! $.$$ready ) {
-                       $.$$ready = [];
-               }
-
-               $.$$ready.push( f );
+               
+       // Otherwise, remember the function for later
+       else {
+               // Add the function to the wait list
+               $.readyList.push( f );
        }
 
        return this;
 };
 
-$.fn.toggle = function(a,b) {
-       return a && b ? this.click(function(e){
-               this.$$last = this.$$last == a ? b : a;
-               e.preventDefault();
-               return $.apply( this, this.$$last, [e] ) || false;
-       }) : this._toggle();
-};
+(function(){
+       /*
+        * Bind a number of event-handling functions, dynamically
+        */
+       var e = ["blur","focus","contextmenu","load","resize","scroll","unload",
+               "click","dblclick","mousedown","mouseup","mouseenter","mouseleave",
+               "mousemove","mouseover","mouseout","change","reset","select","submit",
+               "keydown","keypress","keyup","abort","error","ready"];
+
+       // Go through all the event names, but make sure that
+       // it is enclosed properly
+       for ( var i = 0; i < e.length; i++ ) {(function(){
+                       
+               var o = e[i];
+               
+               // Handle event binding
+               $.fn[o] = function(f){ return this.bind(o, f); };
+               
+               // Handle event unbinding
+               $.fn["un"+o] = function(f){ return this.unbind(o, f); };
+               
+               // Handle event triggering
+               $.fn["do"+o] = function(){ return this.trigger(o); };
+               
+               // Finally, handle events that only fire once
+               $.fn["one"+o] = function(f){
+                       // Attach the event listener
+                       return this.bind(o, function(e){
+                               // TODO: Remove the event listener, instead of this hack
+                               
+                               // If this function has already been executed, stop
+                               if ( this[o+f] !== null )
+                                       return true;
+                               
+                               // Otherwise, mark as having been executed
+                               this[o+f]++;
+                               
+                               // And execute the bound function
+                               return $.apply(this,f,[e]);
+                       });
+               };
+                       
+       })();}
+               
+       /*
+        * 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 hasn't already loaded
+               if ( !$.isReady ) {
+                       // Remember that the DOM is ready
+                       $.isReady = true;
+                       
+                       // If there are functions bound, to execute
+                       if ( $.readyList ) {
+                               // Execute all of them
+                               for ( var i = 0; i < $.readyList.length; i++ )
+                                       $.apply( document, $.readyList[i] );
+                               
+                               // Reset the list of functions
+                               $.readyList = null;
+                       }
+               }
+       };
+       
+       // If Mozilla is used
+       if ( $.browser == "mozilla" || $.browser == "opera" ) {
+               // Use the handy event callback
+               $.event.add( document, "DOMContentLoaded", $.ready );
+       
+       // 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 ( $.browser == "msie" ) {
+       
+               // Only works if you document.write() it
+               document.write('<scr' + 'ipt id=__ie_init defer=true ' + 
+                       'src=javascript:void(0)><\/script>');
+       
+               // Use the defer script hack
+               var script = document.getElementById('__ie_init');
+               script.onreadystatechange = function() {
+                       if ( this.readyState == 'complete' )
+                               $.ready();
+               };
+       
+               // Clear from memory
+               script = null;
+       
+       // If Safari  is used
+       } else if ( $.browser == "safari" ) {
+               // Continually check to see if the document.readyState is valid
+               $.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( $.safariTimer );
+                               $.safariTimer = null;
+       
+                               // and execute any waiting functions
+                               $.ready();
+                       }
+               }, 10);
+       }
+       
+       // A fallback to window.onload, that will always work
+       $.event.add( window, "load", $.ready );
+       
+})();