Fixed two bugs with togglling.
[jquery.git] / fx / fx.js
1 jQuery.fn.extend({
2
3         // overwrite the old show method
4         //_show: jQuery.fn.show,
5         
6         /**
7          * Show all matched elements using a graceful animation.
8          * The height, width, and opacity of each of the matched elements 
9          * are changed dynamically according to the specified speed.
10          *
11          * @example $("p").show("slow");
12          *
13          * @name show
14          * @type jQuery
15          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
16          */
17          
18         /**
19          * Show all matched elements using a graceful animation and firing a callback
20          * function after completion.
21          * The height, width, and opacity of each of the matched elements 
22          * are changed dynamically according to the specified speed.
23          *
24          * @example $("p").show("slow",function(){
25          *   alert("Animation Done.");
26          * });
27          *
28          * @name show
29          * @type jQuery
30          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
31          * @param Function callback A function to be executed whenever the animation completes.
32          */
33         show: function(speed,callback){
34                 return speed ? this.animate({
35                         height: "show", width: "show", opacity: "show"
36                 }, speed, callback) : this._show();
37         },
38         
39         // Overwrite the old hide method
40         //_hide: jQuery.fn.hide,
41         
42         /**
43          * Hide all matched elements using a graceful animation.
44          * The height, width, and opacity of each of the matched elements 
45          * are changed dynamically according to the specified speed.
46          *
47          * @example $("p").hide("slow");
48          *
49          * @name hide
50          * @type jQuery
51          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
52          */
53          
54         /**
55          * Hide all matched elements using a graceful animation and firing a callback
56          * function after completion.
57          * The height, width, and opacity of each of the matched elements 
58          * are changed dynamically according to the specified speed.
59          *
60          * @example $("p").hide("slow",function(){
61          *   alert("Animation Done.");
62          * });
63          *
64          * @name hide
65          * @type jQuery
66          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
67          * @param Function callback A function to be executed whenever the animation completes.
68          */
69         hide: function(speed,callback){
70                 return speed ? this.animate({
71                         height: "hide", width: "hide", opacity: "hide"
72                 }, speed, callback) : this._hide();
73         },
74         
75         /**
76          * Reveal all matched elements by adjusting their height.
77          * Only the height is adjusted for this animation, causing all matched
78          * elements to be revealed in a "sliding" manner.
79          *
80          * @example $("p").slideDown("slow");
81          *
82          * @name slideDown
83          * @type jQuery
84          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
85          */
86          
87         /**
88          * Reveal all matched elements by adjusting their height and firing a callback
89          * function after completion.
90          * Only the height is adjusted for this animation, causing all matched
91          * elements to be revealed in a "sliding" manner.
92          *
93          * @example $("p").slideDown("slow",function(){
94          *   alert("Animation Done.");
95          * });
96          *
97          * @name slideDown
98          * @type jQuery
99          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
100          * @param Function callback A function to be executed whenever the animation completes.
101          */
102         slideDown: function(speed,callback){
103                 return this.animate({height: "show"}, speed, callback);
104         },
105         
106         /**
107          * Hide all matched elements by adjusting their height.
108          * Only the height is adjusted for this animation, causing all matched
109          * elements to be hidden in a "sliding" manner.
110          *
111          * @example $("p").slideUp("slow");
112          *
113          * @name slideUp
114          * @type jQuery
115          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
116          */
117          
118         /**
119          * Hide all matched elements by adjusting their height and firing a callback
120          * function after completion.
121          * Only the height is adjusted for this animation, causing all matched
122          * elements to be hidden in a "sliding" manner.
123          *
124          * @example $("p").slideUp("slow",function(){
125          *   alert("Animation Done.");
126          * });
127          *
128          * @name slideUp
129          * @type jQuery
130          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
131          * @param Function callback A function to be executed whenever the animation completes.
132          */
133         slideUp: function(speed,callback){
134                 return this.animate({height: "hide"}, speed, callback);
135         },
136         
137         /**
138          * Fade in all matched elements by adjusting their opacity.
139          * Only the opacity is adjusted for this animation, meaning that
140          * all of the matched elements should already have some form of height
141          * and width associated with them.
142          *
143          * @example $("p").fadeIn("slow");
144          *
145          * @name fadeIn
146          * @type jQuery
147          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
148          */
149          
150         /**
151          * Fade in all matched elements by adjusting their opacity and firing a 
152          * callback function after completion.
153          * Only the opacity is adjusted for this animation, meaning that
154          * all of the matched elements should already have some form of height
155          * and width associated with them.
156          *
157          * @example $("p").fadeIn("slow",function(){
158          *   alert("Animation Done.");
159          * });
160          *
161          * @name fadeIn
162          * @type jQuery
163          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
164          * @param Function callback A function to be executed whenever the animation completes.
165          */
166         fadeIn: function(speed,callback){
167                 return this.animate({opacity: "show"}, speed, callback);
168         },
169         
170         /**
171          * Fade out all matched elements by adjusting their opacity.
172          * Only the opacity is adjusted for this animation, meaning that
173          * all of the matched elements should already have some form of height
174          * and width associated with them.
175          *
176          * @example $("p").fadeOut("slow");
177          *
178          * @name fadeOut
179          * @type jQuery
180          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
181          */
182          
183         /**
184          * Fade out all matched elements by adjusting their opacity and firing a 
185          * callback function after completion.
186          * Only the opacity is adjusted for this animation, meaning that
187          * all of the matched elements should already have some form of height
188          * and width associated with them.
189          *
190          * @example $("p").fadeOut("slow",function(){
191          *   alert("Animation Done.");
192          * });
193          *
194          * @name fadeOut
195          * @type jQuery
196          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
197          * @param Function callback A function to be executed whenever the animation completes.
198          */
199         fadeOut: function(speed,callback){
200                 return this.animate({opacity: "hide"}, speed, callback);
201         },
202         
203         /**
204          * Fade the opacity of all matched elements to a specified opacity.
205          * Only the opacity is adjusted for this animation, meaning that
206          * all of the matched elements should already have some form of height
207          * and width associated with them.
208          *
209          * @example $("p").fadeTo("slow", 0.5);
210          *
211          * @name fadeTo
212          * @type jQuery
213          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
214          * @param Number opacity The opacity to fade to (a number from 0 to 1).
215          */
216          
217         /**
218          * Fade the opacity of all matched elements to a specified opacity and 
219          * firing a callback function after completion.
220          * Only the opacity is adjusted for this animation, meaning that
221          * all of the matched elements should already have some form of height
222          * and width associated with them.
223          *
224          * @example $("p").fadeTo("slow", 0.5, function(){
225          *   alert("Animation Done.");
226          * });
227          *
228          * @name fadeTo
229          * @type jQuery
230          * @param Object speed A string representing one of the three predefined speeds ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
231          * @param Number opacity The opacity to fade to (a number from 0 to 1).
232          * @param Function callback A function to be executed whenever the animation completes.
233          */
234         fadeTo: function(speed,to,callback){
235                 return this.animate({opacity: to}, speed, callback);
236         },
237         
238         /**
239          * @private
240          */
241         animate: function(prop,speed,callback) {
242                 return this.queue(function(){
243                         var i = 0;
244                         for ( var p in prop ) {
245                                 var e = new jQuery.fx( this, jQuery.speed(speed,callback,i++), p );
246                                 if ( prop[p].constructor == Number )
247                                         e.custom( e.cur(), prop[p] );
248                                 else
249                                         e[ prop[p] ]( prop );
250                         }
251                 });
252         },
253         
254         /**
255          *
256          * @private
257          */
258         queue: function(type,fn){
259                 if ( !fn ) {
260                         fn = type;
261                         type = "fx";
262                 }
263         
264                 return this.each(function(){
265                         if ( !this.queue )
266                                 this.queue = {};
267         
268                         if ( !this.queue[type] )
269                                 this.queue[type] = [];
270         
271                         this.queue[type].push( fn );
272                 
273                         if ( this.queue[type].length == 1 )
274                                 fn.apply(this);
275                 });
276         }
277
278 });
279
280 jQuery.extend({
281
282         setAuto: function(e,p) {
283                 if ( e.notAuto ) return;
284
285                 if ( p == "height" && e.scrollHeight != parseInt(jQuery.curCSS(e,p)) ) return;
286                 if ( p == "width" && e.scrollWidth != parseInt(jQuery.curCSS(e,p)) ) return;
287
288                 // Remember the original height
289                 var a = e.style[p];
290
291                 // Figure out the size of the height right now
292                 var o = jQuery.curCSS(e,p,1);
293
294                 if ( p == "height" && e.scrollHeight != o ||
295                         p == "width" && e.scrollWidth != o ) return;
296
297                 // Set the height to auto
298                 e.style[p] = e.currentStyle ? "" : "auto";
299
300                 // See what the size of "auto" is
301                 var n = jQuery.curCSS(e,p,1);
302
303                 // Revert back to the original size
304                 if ( o != n && n != "auto" ) {
305                         e.style[p] = a;
306                         e.notAuto = true;
307                 }
308         },
309         
310         speed: function(s,o,i) {
311                 o = o || {};
312                 
313                 if ( o.constructor == Function )
314                         o = { complete: o };
315                 
316                 var ss = { slow: 600, fast: 200 };
317                 o.duration = (s && s.constructor == Number ? s : ss[s]) || 400;
318         
319                 // Queueing
320                 o.oldComplete = o.complete;
321                 o.complete = function(){
322                         jQuery.dequeue(this, "fx");
323                         if ( o.oldComplete && o.oldComplete.constructor == Function )
324                                 o.oldComplete.apply( this );
325                 };
326                 
327                 if ( i > 0 )
328                         o.complete = null;
329         
330                 return o;
331         },
332         
333         queue: {},
334         
335         dequeue: function(elem,type){
336                 type = type || "fx";
337         
338                 if ( elem.queue && elem.queue[type] ) {
339                         // Remove self
340                         elem.queue[type].shift();
341         
342                         // Get next function
343                         var f = elem.queue[type][0];
344                 
345                         if ( f ) f.apply( elem );
346                 }
347         },
348
349         /*
350          * I originally wrote fx() as a clone of moo.fx and in the process
351          * of making it small in size the code became illegible to sane
352          * people. You've been warned.
353          */
354         
355         fx: function( elem, options, prop ){
356         
357                 var z = this;
358         
359                 // The users options
360                 z.o = {
361                         duration: options.duration || 400,
362                         complete: options.complete
363                 };
364         
365                 // The element
366                 z.el = elem;
367         
368                 // The styles
369                 var y = z.el.style;
370         
371                 // Simple function for setting a style value
372                 z.a = function(){
373                         if ( prop == "opacity" ) {
374                                 if (z.now == 1) z.now = 0.9999;
375                                 if (window.ActiveXObject)
376                                         y.filter = "alpha(opacity=" + z.now*100 + ")";
377                                 else
378                                         y.opacity = z.now;
379
380                         // My hate for IE will never die
381                         } else if ( parseInt(z.now) )
382                                 y[prop] = parseInt(z.now) + "px";
383                         y.display = "block";
384                 };
385         
386                 // Figure out the maximum number to run to
387                 z.max = function(){
388                         return parseFloat( jQuery.css(z.el,prop) );
389                 };
390         
391                 // Get the current size
392                 z.cur = function(){
393                         return parseFloat( jQuery.curCSS(z.el, prop) ) || z.max();
394                 };
395         
396                 // Start an animation from one number to another
397                 z.custom = function(from,to){
398                         z.startTime = (new Date()).getTime();
399                         z.now = from;
400                         z.a();
401         
402                         z.timer = setInterval(function(){
403                                 z.step(from, to);
404                         }, 13);
405                 };
406         
407                 // Simple 'show' function
408                 z.show = function( p ){
409                         if ( !z.el.orig ) z.el.orig = {};
410
411                         // Remember where we started, so that we can go back to it later
412                         z.el.orig[prop] = this.cur();
413
414                         z.custom( 0, z.el.orig[prop] );
415
416                         // Stupid IE, look what you made me do
417                         if ( prop != "opacity" )
418                                 y[prop] = "1px";
419                 };
420         
421                 // Simple 'hide' function
422                 z.hide = function(){
423                         if ( !z.el.orig ) z.el.orig = {};
424
425                         // Remember where we started, so that we can go back to it later
426                         z.el.orig[prop] = this.cur();
427
428                         z.o.hide = true;
429
430                         // Begin the animation
431                         z.custom(z.cur(),0);
432                 };
433         
434                 // IE has trouble with opacity if it does not have layout
435                 if ( jQuery.browser.msie && !z.el.currentStyle.hasLayout )
436                         y.zoom = "1";
437         
438                 // Remember  the overflow of the element
439                 if ( !z.el.oldOverlay )
440                         z.el.oldOverflow = jQuery.css( z.el, "overflow" );
441         
442                 // Make sure that nothing sneaks out
443                 //if ( z.el.oldOverlay == "visible" )
444                 y.overflow = "hidden";
445         
446                 // Each step of an animation
447                 z.step = function(firstNum, lastNum){
448                         var t = (new Date()).getTime();
449         
450                         if (t > z.o.duration + z.startTime) {
451                                 // Stop the timer
452                                 clearInterval(z.timer);
453                                 z.timer = null;
454
455                                 z.now = lastNum;
456                                 z.a();
457
458                                 // Hide the element if the "hide" operation was done
459                                 if ( z.o.hide ) y.display = 'none';
460         
461                                 // Reset the overflow
462                                 y.overflow = z.el.oldOverflow;
463
464                                 // If a callback was provided, execute it
465                                 if( z.o.complete && z.o.complete.constructor == Function )
466                                         // Execute the complete function
467                                         z.o.complete.apply( z.el );
468
469                                 // Reset the property, if the item has been hidden
470                                 if ( z.o.hide )
471                                         y[ prop ] = z.el.orig[ prop ].constructor == Number && prop != "opacity" ?
472                                                 z.el.orig[prop] + "px" : z.el.orig[prop];
473
474                                 // set its height and/or width to auto
475                                 jQuery.setAuto( z.el, prop );
476                         } else {
477                                 // Figure out where in the animation we are and set the number
478                                 var p = (t - this.startTime) / z.o.duration;
479                                 z.now = ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum;
480         
481                                 // Perform the next step of the animation
482                                 z.a();
483                         }
484                 };
485         
486         }
487
488 });