Added support for the new .andSelf() method. This method combines the previous two...
[jquery.git] / src / fx / fx.js
1 jQuery.fn.extend({
2         show: function(speed,callback){
3                 return speed ?
4                         this.animate({
5                                 height: "show", width: "show", opacity: "show"
6                         }, speed, callback) :
7                         
8                         this.filter(":hidden").each(function(){
9                                 this.style.display = this.oldblock ? this.oldblock : "";
10                                 if ( jQuery.css(this,"display") == "none" )
11                                         this.style.display = "block";
12                         }).end();
13         },
14         
15         hide: function(speed,callback){
16                 return speed ?
17                         this.animate({
18                                 height: "hide", width: "hide", opacity: "hide"
19                         }, speed, callback) :
20                         
21                         this.filter(":visible").each(function(){
22                                 this.oldblock = this.oldblock || jQuery.css(this,"display");
23                                 if ( this.oldblock == "none" )
24                                         this.oldblock = "block";
25                                 this.style.display = "none";
26                         }).end();
27         },
28
29         // Save the old toggle function
30         _toggle: jQuery.fn.toggle,
31         
32         toggle: function( fn, fn2 ){
33                 return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
34                         this._toggle( fn, fn2 ) :
35                         fn ?
36                                 this.animate({
37                                         height: "toggle", width: "toggle", opacity: "toggle"
38                                 }, fn, fn2) :
39                                 this.each(function(){
40                                         jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
41                                 });
42         },
43         
44         slideDown: function(speed,callback){
45                 return this.animate({height: "show"}, speed, callback);
46         },
47         
48         slideUp: function(speed,callback){
49                 return this.animate({height: "hide"}, speed, callback);
50         },
51
52         slideToggle: function(speed, callback){
53                 return this.animate({height: "toggle"}, speed, callback);
54         },
55         
56         fadeIn: function(speed, callback){
57                 return this.animate({opacity: "show"}, speed, callback);
58         },
59         
60         fadeOut: function(speed, callback){
61                 return this.animate({opacity: "hide"}, speed, callback);
62         },
63         
64         fadeTo: function(speed,to,callback){
65                 return this.animate({opacity: to}, speed, callback);
66         },
67         
68         animate: function( prop, speed, easing, callback ) {
69                 return this.queue(function(){
70                         var hidden = jQuery(this).is(":hidden"),
71                                 opt = jQuery.speed(speed, easing, callback),
72                                 self = this;
73                         
74                         for ( var p in prop ) {
75                                 if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
76                                         return jQuery.isFunction(opt.complete) && opt.complete.apply(this);
77
78                                 if ( p == "height" || p == "width" ) {
79                                         // Store display property
80                                         opt.display = jQuery.css(this, "display");
81
82                                         // Make sure that nothing sneaks out
83                                         opt.overflow = this.style.overflow;
84                                 }
85                         }
86
87                         if ( opt.overflow != null )
88                                 this.style.overflow = "hidden";
89
90                         this.curAnim = jQuery.extend({}, prop);
91                         
92                         jQuery.each( prop, function(name, val){
93                                 var e = new jQuery.fx( self, opt, name );
94                                 if ( val.constructor == Number )
95                                         e.custom( e.cur() || 0, val );
96                                 else
97                                         e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
98                         });
99
100                         // For JS strict compliance
101                         return true;
102                 });
103         },
104         
105         queue: function(type,fn){
106                 if ( !fn ) {
107                         fn = type;
108                         type = "fx";
109                 }
110         
111                 return this.each(function(){
112                         if ( !this.queue )
113                                 this.queue = {};
114         
115                         if ( !this.queue[type] )
116                                 this.queue[type] = [];
117         
118                         this.queue[type].push( fn );
119                 
120                         if ( this.queue[type].length == 1 )
121                                 fn.apply(this);
122                 });
123         },
124
125         stop: function(){
126                 var timers = jQuery.timers;
127
128                 return this.each(function(){
129                         for ( var i = 0; i < timers.length; i++ )
130                                 if ( timers[i].elem == this )
131                                         timers.splice(i--, 1);
132                 });
133         }
134
135 });
136
137 jQuery.extend({
138         
139         speed: function(speed, easing, fn) {
140                 var opt = speed && speed.constructor == Object ? speed : {
141                         complete: fn || !fn && easing || 
142                                 jQuery.isFunction( speed ) && speed,
143                         duration: speed,
144                         easing: fn && easing || easing && easing.constructor != Function && easing
145                 };
146
147                 opt.duration = (opt.duration && opt.duration.constructor == Number ? 
148                         opt.duration : 
149                         { slow: 600, fast: 200 }[opt.duration]) || 400;
150         
151                 // Queueing
152                 opt.old = opt.complete;
153                 opt.complete = function(){
154                         jQuery.dequeue(this, "fx");
155                         if ( jQuery.isFunction( opt.old ) )
156                                 opt.old.apply( this );
157                 };
158         
159                 return opt;
160         },
161         
162         easing: {
163                 linear: function( p, n, firstNum, diff ) {
164                         return firstNum + diff * p;
165                 },
166                 swing: function( p, n, firstNum, diff ) {
167                         return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
168                 }
169         },
170         
171         queue: {},
172         
173         dequeue: function(elem,type){
174                 type = type || "fx";
175         
176                 if ( elem.queue && elem.queue[type] ) {
177                         // Remove self
178                         elem.queue[type].shift();
179         
180                         // Get next function
181                         var f = elem.queue[type][0];
182                 
183                         if ( f ) f.apply( elem );
184                 }
185         },
186
187         timers: [],
188
189         fx: function( elem, options, prop ){
190
191                 var z = this, y = elem.style,
192                         isprop = elem[prop] != null && y[prop] == null;
193                 
194                 // Simple function for setting a style value
195                 z.a = function(){
196                         if ( options.step )
197                                 options.step.apply( elem, [ z.now ] );
198
199                         if ( prop == "opacity" )
200                                 jQuery.attr(y, "opacity", z.now); // Let attr handle opacity
201                         else {
202                                 if ( isprop )
203                                         elem[prop] = parseInt(z.now);
204                                 else
205                                         y[prop] = parseInt(z.now) + "px";
206
207                                 // Set display property to block for height/width animations
208                                 if ( prop == "height" || prop == "width" )
209                                         y.display = "block";
210                         }
211                 };
212
213                 // Figure out the maximum number to run to
214                 z.max = function(){
215                         return parseFloat( jQuery.css(elem,prop) );
216                 };
217
218                 // Get the current size
219                 z.cur = function(){
220                         if ( isprop ) return elem[prop];
221                         var r = parseFloat( jQuery.curCSS(elem, prop) );
222                         return r && r > -10000 ? r : z.max();
223                 };
224
225                 // Start an animation from one number to another
226                 z.custom = function(from,to){
227                         z.startTime = (new Date()).getTime();
228                         z.now = from;
229                         z.a();
230
231                         function t(){
232                                 return z.step(from, to);
233                         }
234
235                         t.elem = elem;
236
237                         jQuery.timers.push(t);
238
239                         if ( jQuery.timers.length == 1 ) {
240                                 var timer = setInterval(function(){
241                                         var timers = jQuery.timers;
242                                         
243                                         for ( var i = 0; i < timers.length; i++ )
244                                                 if ( !timers[i]() )
245                                                         timers.splice(i--, 1);
246
247                                         if ( !timers.length )
248                                                 clearInterval( timer );
249                                 }, 13);
250                         }
251                 };
252
253                 // Simple 'show' function
254                 z.show = function(){
255                         if ( !elem.orig ) elem.orig = {};
256
257                         // Remember where we started, so that we can go back to it later
258                         elem.orig[prop] = jQuery.attr( elem.style, prop );
259
260                         options.show = true;
261
262                         // Begin the animation
263                         z.custom(0, this.cur());
264
265                         // Make sure that we start at a small width/height to avoid any
266                         // flash of content
267                         if ( prop != "opacity" )
268                                 y[prop] = "1px";
269                         
270                         // Start by showing the element
271                         jQuery(elem).show();
272                 };
273
274                 // Simple 'hide' function
275                 z.hide = function(){
276                         if ( !elem.orig ) elem.orig = {};
277
278                         // Remember where we started, so that we can go back to it later
279                         elem.orig[prop] = jQuery.attr( elem.style, prop );
280
281                         options.hide = true;
282
283                         // Begin the animation
284                         z.custom(this.cur(), 0);
285                 };
286
287                 // Each step of an animation
288                 z.step = function(firstNum, lastNum){
289                         var t = (new Date()).getTime();
290
291                         if (t > options.duration + z.startTime) {
292                                 z.now = lastNum;
293                                 z.a();
294
295                                 if (elem.curAnim) elem.curAnim[ prop ] = true;
296
297                                 var done = true;
298                                 for ( var i in elem.curAnim )
299                                         if ( elem.curAnim[i] !== true )
300                                                 done = false;
301
302                                 if ( done ) {
303                                         if ( options.display != null ) {
304                                                 // Reset the overflow
305                                                 y.overflow = options.overflow;
306                                         
307                                                 // Reset the display
308                                                 y.display = options.display;
309                                                 if ( jQuery.css(elem, "display") == "none" )
310                                                         y.display = "block";
311                                         }
312
313                                         // Hide the element if the "hide" operation was done
314                                         if ( options.hide )
315                                                 y.display = "none";
316
317                                         // Reset the properties, if the item has been hidden or shown
318                                         if ( options.hide || options.show )
319                                                 for ( var p in elem.curAnim )
320                                                         jQuery.attr(y, p, elem.orig[p]);
321                                 }
322
323                                 // If a callback was provided, execute it
324                                 if ( done && jQuery.isFunction( options.complete ) )
325                                         // Execute the complete function
326                                         options.complete.apply( elem );
327
328                                 return false;
329                         } else {
330                                 var n = t - this.startTime;
331                                 // Figure out where in the animation we are and set the number
332                                 var p = n / options.duration;
333                                 
334                                 // Perform the easing function, defaults to swing
335                                 z.now = jQuery.easing[options.easing || (jQuery.easing.swing ? "swing" : "linear")](p, n, firstNum, (lastNum-firstNum), options.duration);
336
337                                 // Perform the next step of the animation
338                                 z.a();
339                         }
340
341                         return true;
342                 };
343         
344         }
345 });