Added my one fun thing for the night: jQuery.each, inspired by Dean Edwards' work.
[jquery.git] / fx / fx.js
1 jQuery.fn.extend({
2
3         // overwrite the old show method
4         _show: jQuery.fn.show,
5         
6         /**
7          * The effects module overloads the show method to now allow 
8          * for a speed to the show operation. What actually happens is 
9          * that the height, width, and opacity to the matched elements 
10          * are changed dynamically. The only three current speeds are 
11          * "slow", "normal", and "fast". For example:
12          *   $("p").show("slow");
13          * Note: You should not run the show method on things 
14          * that are already shown. This can be circumvented by doing this:
15          *   $("p:hidden").show("slow");
16          */
17         show: function(speed,callback){
18                 return speed ? this.animate({
19                         height: "show", width: "show", opacity: "show"
20                 }, speed, callback) : this._show();
21         },
22         
23         // Overwrite the old hide method
24         _hide: jQuery.fn.hide,
25         
26         /**
27          * The hide function behaves very similary to the show function, 
28          * but is just the opposite.
29          *   $("p:visible").hide("slow");
30          */
31         hide: function(speed,callback){
32                 return speed ? this.animate({
33                         height: "hide", width: "hide", opacity: "hide"
34                 }, speed, callback) : this._hide();
35         },
36         
37         /**
38          * This function increases the height and opacity for all matched 
39          * elements. This is very similar to 'show', but does not change 
40          * the width - creating a neat sliding effect.
41          *   $("p:hidden").slideDown("slow");
42          */
43         slideDown: function(speed,callback){
44                 return this.animate({height: "show"}, speed, callback);
45         },
46         
47         /**
48          * Just like slideDown, only it hides all matched elements.
49          *   $("p:visible").slideUp("slow");
50          */
51         slideUp: function(speed,callback){
52                 return this.animate({height: "hide"}, speed, callback);
53         },
54         
55         /**
56          * Adjusts the opacity of all matched elements from a hidden, 
57          * to a fully visible, state.
58          *   $("p:hidden").fadeIn("slow");
59          */
60         fadeIn: function(speed,callback){
61                 return this.animate({opacity: "show"}, speed, callback);
62         },
63         
64         /**
65          * Same as fadeIn, but transitions from a visible, to a hidden state.
66          *   $("p:visible").fadeOut("slow");
67          */
68         fadeOut: function(speed,callback){
69                 return this.animate({opacity: "hide"}, speed, callback);
70         },
71         
72         /**
73          * ...
74          */
75         fadeTo: function(speed,to,callback){
76                 return this.animate({opacity: to}, speed, callback);
77         },
78         
79         /**
80          *
81          */
82         animate: function(prop,speed,callback) {
83                 return this.queue(function(){
84                         var i = 0;
85                         for ( var p in prop ) {
86                                 var e = new jQuery.fx( this, jQuery.speed(speed,callback,i++), p );
87                                 if ( prop[p].constructor == Number )
88                                         e.custom( e.cur(), prop[p] );
89                                 else
90                                         e[ prop[p] ]( prop );
91                         }
92                 });
93         },
94         
95         /**
96          *
97          * @private
98          */
99         queue: function(type,fn){
100                 if ( !fn ) {
101                         fn = type;
102                         type = "fx";
103                 }
104         
105                 return this.each(function(){
106                         if ( !this.queue )
107                                 this.queue = {};
108         
109                         if ( !this.queue[type] )
110                                 this.queue[type] = [];
111         
112                         this.queue[type].push( fn );
113                 
114                         if ( this.queue[type].length == 1 )
115                                 fn.apply(this);
116                 });
117         }
118
119 });
120
121 jQuery.extend({
122
123         setAuto: function(e,p) {
124                 if ( e.notAuto ) return;
125
126                 if ( p == "height" && e.scrollHeight != parseInt(jQuery.curCSS(e,p)) ) return;
127                 if ( p == "width" && e.scrollWidth != parseInt(jQuery.curCSS(e,p)) ) return;
128
129                 // Remember the original height
130                 var a = e.style[p];
131
132                 // Figure out the size of the height right now
133                 var o = jQuery.curCSS(e,p,1);
134
135                 if ( p == "height" && e.scrollHeight != o ||
136                         p == "width" && e.scrollWidth != o ) return;
137
138                 // Set the height to auto
139                 e.style[p] = e.currentStyle ? "" : "auto";
140
141                 // See what the size of "auto" is
142                 var n = jQuery.curCSS(e,p,1);
143
144                 // Revert back to the original size
145                 if ( o != n && n != "auto" ) {
146                         e.style[p] = a;
147                         e.notAuto = true;
148                 }
149         },
150         
151         speed: function(s,o,i) {
152                 o = o || {};
153                 
154                 if ( o.constructor == Function )
155                         o = { complete: o };
156                 
157                 var ss = { slow: 600, fast: 200 };
158                 o.duration = (s && s.constructor == Number ? s : ss[s]) || 400;
159         
160                 // Queueing
161                 o.oldComplete = o.complete;
162                 o.complete = function(){
163                         jQuery.dequeue(this, "fx");
164                         if ( o.oldComplete && o.oldComplete.constructor == Function )
165                                 o.oldComplete.apply( this );
166                 };
167                 
168                 if ( i > 0 )
169                         o.complete = null;
170         
171                 return o;
172         },
173         
174         queue: {},
175         
176         dequeue: function(elem,type){
177                 type = type || "fx";
178         
179                 if ( elem.queue && elem.queue[type] ) {
180                         // Remove self
181                         elem.queue[type].shift();
182         
183                         // Get next function
184                         var f = elem.queue[type][0];
185                 
186                         if ( f ) f.apply( elem );
187                 }
188         },
189
190         /*
191          * I originally wrote fx() as a clone of moo.fx and in the process
192          * of making it small in size the code became illegible to sane
193          * people. You've been warned.
194          */
195         
196         fx: function( elem, options, prop ){
197         
198                 var z = this;
199         
200                 // The users options
201                 z.o = {
202                         duration: options.duration || 400,
203                         complete: options.complete
204                 };
205         
206                 // The element
207                 z.el = elem;
208         
209                 // The styles
210                 var y = z.el.style;
211         
212                 // Simple function for setting a style value
213                 z.a = function(){
214                         if ( prop == "opacity" ) {
215                                 if (z.now == 1) z.now = 0.9999;
216                                 if (window.ActiveXObject)
217                                         y.filter = "alpha(opacity=" + z.now*100 + ")";
218                                 else
219                                         y.opacity = z.now;
220
221                         // My hate for IE will never die
222                         } else if ( parseInt(z.now) )
223                                 y[prop] = parseInt(z.now) + "px";
224                         y.display = "block";
225                 };
226         
227                 // Figure out the maximum number to run to
228                 z.max = function(){
229                         return parseFloat( jQuery.css(z.el,prop) );
230                 };
231         
232                 // Get the current size
233                 z.cur = function(){
234                         return parseFloat( jQuery.curCSS(z.el, prop) ) || z.max();
235                 };
236         
237                 // Start an animation from one number to another
238                 z.custom = function(from,to){
239                         z.startTime = (new Date()).getTime();
240                         z.now = from;
241                         z.a();
242         
243                         z.timer = setInterval(function(){
244                                 z.step(from, to);
245                         }, 13);
246                 };
247         
248                 // Simple 'show' function
249                 z.show = function( p ){
250                         if ( !z.el.orig ) z.el.orig = {};
251
252                         // Remember where we started, so that we can go back to it later
253                         z.el.orig[prop] = this.cur();
254
255                         z.custom( 0, z.el.orig[prop] );
256
257                         // Stupid IE, look what you made me do
258                         if ( prop != "opacity" )
259                                 y[prop] = "1px";
260                 };
261         
262                 // Simple 'hide' function
263                 z.hide = function(){
264                         if ( !z.el.orig ) z.el.orig = {};
265
266                         // Remember where we started, so that we can go back to it later
267                         z.el.orig[prop] = this.cur();
268
269                         z.o.hide = true;
270
271                         // Begin the animation
272                         z.custom(z.cur(),0);
273                 };
274         
275                 // IE has trouble with opacity if it does not have layout
276                 if ( jQuery.browser.msie && !z.el.currentStyle.hasLayout )
277                         y.zoom = "1";
278         
279                 // Remember  the overflow of the element
280                 if ( !z.el.oldOverlay )
281                         z.el.oldOverflow = jQuery.css( z.el, "overflow" );
282         
283                 // Make sure that nothing sneaks out
284                 if ( z.el.oldOverlay == "visible" )
285                         y.overflow = "hidden";
286         
287                 // Each step of an animation
288                 z.step = function(firstNum, lastNum){
289                         var t = (new Date()).getTime();
290         
291                         if (t > z.o.duration + z.startTime) {
292                                 // Stop the timer
293                                 clearInterval(z.timer);
294                                 z.timer = null;
295
296                                 z.now = lastNum;
297                                 z.a();
298
299                                 // Hide the element if the "hide" operation was done
300                                 if ( z.o.hide ) y.display = 'none';
301         
302                                 // Reset the overflow
303                                 y.overflow = z.el.oldOverflow;
304
305                                 // If a callback was provided, execute it
306                                 if( z.o.complete && z.o.complete.constructor == Function )
307                                         // Execute the complete function
308                                         z.o.complete.apply( z.el );
309
310                                 // Reset the property, if the item has been hidden
311                                 if ( z.o.hide )
312                                         y[ prop ] = z.el.orig[ prop ].constructor == Number && prop != "opacity" ?
313                                                 z.el.orig[prop] + "px" : z.el.orig[prop];
314
315                                 // set its height and/or width to auto
316                                 jQuery.setAuto( z.el, prop );
317                         } else {
318                                 // Figure out where in the animation we are and set the number
319                                 var p = (t - this.startTime) / z.o.duration;
320                                 z.now = ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum;
321         
322                                 // Perform the next step of the animation
323                                 z.a();
324                         }
325                 };
326         
327         }
328
329 });