Happy 100th commit, jQuery!
[jquery.git] / event / event.js
1 // We're overriding the old toggle function, so
2 // remember it for later
3 $.fn._toggle = $.fn.toggle;
4
5 /**
6  * Toggle between two function calls every other click.
7  */
8 $.fn.toggle = function(a,b) {
9         // If two functions are passed in, we're
10         // toggling on a click
11         return a && b ? this.click(function(e){
12                 // Figure out which function to execute
13                 this.last = this.last == a ? b : a;
14                 
15                 // Make sure that clicks don't pass through
16                 e.preventDefault();
17                 
18                 // and execute the function
19                 return $.apply( this, this.last, [e] ) || false;
20         }) :
21         
22         // Otherwise, execute the old toggle function
23         this._toggle();
24 };
25
26 /**
27  * Toggle between two function calls on mouse over/out.
28  */
29 $.fn.hover = function(f,g) {
30         
31         // A private function for haandling mouse 'hovering'
32         function handleHover(e) {
33                 // Check if mouse(over|out) are still within the same parent element
34                 var p = e.fromElement || e.toElement || e.relatedTarget;
35                 while ( p && p != this ) p = p.parentNode;
36                 
37                 // If we actually just moused on to a sub-element, ignore it
38                 if ( p == this ) return false;
39                 
40                 // Execute the right function
41                 return (e.type == "mouseover" ? f : g).apply(this,[e]);
42         }
43         
44         // Bind the function to the two event listeners
45         return this.mouseover(handleHover).mouseout(handleHover);
46 };
47
48 /**
49  * Bind a function to fire when the DOM is ready.
50  */
51 $.fn.ready = function(f) {
52         // If the DOM is already ready
53         if ( $.isReady )
54                 // Execute the function immediately
55                 $.apply( document, f );
56                 
57         // Otherwise, remember the function for later
58         else {
59                 // Add the function to the wait list
60                 $.readyList.push( f );
61         }
62
63         return this;
64 };
65
66 (function(){
67         /*
68          * Bind a number of event-handling functions, dynamically
69          */
70         var e = "blur,focus,contextmenu,load,resize,scroll,unload,click,dblclick," +
71                 "mousedown,mouseup,mouseenter,mouseleave,mousemove,mouseover,mouseout," +
72                 "change,reset,select,submit,keydown,keypress,keyup,abort,error,ready".split(",");
73
74         // Go through all the event names, but make sure that
75         // it is enclosed properly
76         for ( var i = 0; i < e.length; i++ ) {(function(){
77                         
78                 var o = e[i];
79                 
80                 // Handle event binding
81                 $.fn[o] = function(f){ return this.bind(o, f); };
82                 
83                 // Handle event unbinding
84                 $.fn["un"+o] = function(f){ return this.unbind(o, f); };
85                 
86                 // Handle event triggering
87                 $.fn["do"+o] = function(){ return this.trigger(o); };
88                 
89                 // Finally, handle events that only fire once
90                 $.fn["one"+o] = function(f){
91                         // Attach the event listener
92                         return this.bind(o, function(e){
93                                 // TODO: Remove the event listener, instead of this hack
94                                 
95                                 // If this function has already been executed, stop
96                                 if ( this[o+f] !== null )
97                                         return true;
98                                 
99                                 // Otherwise, mark as having been executed
100                                 this[o+f]++;
101                                 
102                                 // And execute the bound function
103                                 return $.apply(this,f,[e]);
104                         });
105                 };
106                         
107         })();}
108                 
109         /*
110          * All the code that makes DOM Ready work nicely.
111          */
112          
113         $.isReady = false;
114         $.readyList = [];
115         
116         // Handle when the DOM is ready
117         $.ready = function() {
118                 // Make sure that the DOM hasn't already loaded
119                 if ( !$.isReady ) {
120                         // Remember that the DOM is ready
121                         $.isReady = true;
122                         
123                         // If there are functions bound, to execute
124                         if ( $.readyList ) {
125                                 // Execute all of them
126                                 for ( var i = 0; i < $.readyList.length; i++ )
127                                         $.apply( document, $.readyList[i] );
128                                 
129                                 // Reset the list of functions
130                                 $.readyList = null;
131                         }
132                 }
133         };
134         
135         // If Mozilla is used
136         if ( $.browser == "mozilla" || $.browser == "opera" ) {
137                 // Use the handy event callback
138                 $.event.add( document, "DOMContentLoaded", $.ready );
139         
140         // If IE is used, use the excellent hack by Matthias Miller
141         // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited
142         } else if ( $.browser == "msie" ) {
143         
144                 // Only works if you document.write() it
145                 document.write("<scr" + "ipt id=__ie_init defer=true " + 
146                         "src=javascript:void(0)><\/script>");
147         
148                 // Use the defer script hack
149                 var script = document.getElementById("__ie_init");
150                 script.onreadystatechange = function() {
151                         if ( this.readyState == "complete" )
152                                 $.ready();
153                 };
154         
155                 // Clear from memory
156                 script = null;
157         
158         // If Safari  is used
159         } else if ( $.browser == "safari" ) {
160                 // Continually check to see if the document.readyState is valid
161                 $.safariTimer = setInterval(function(){
162                         // loaded and complete are both valid states
163                         if ( document.readyState == "loaded" || 
164                                 document.readyState == "complete" ) {
165         
166                                 // If either one are found, remove the timer
167                                 clearInterval( $.safariTimer );
168                                 $.safariTimer = null;
169         
170                                 // and execute any waiting functions
171                                 $.ready();
172                         }
173                 }, 10);
174         }
175         
176         // A fallback to window.onload, that will always work
177         $.event.add( window, "load", $.ready );
178         
179 })();