Update $.fn.animate to change display mode only when necessary (inline, non-floated...
[jquery.git] / src / effects.js
index d1d873d..3257ac3 100644 (file)
@@ -13,45 +13,41 @@ var elemdisplay = {},
                [ "opacity" ]
        ];
 
-jQuery.fn.extend({
-       show: function( speed, easing, callback ) {
-               if ( speed || speed === 0) {
-                       return this.animate( genFx("show", 3), speed, easing, callback);
-
-               } else {
-                       for ( var i = 0, l = this.length; i < l; i++ ) {
-                               var old = jQuery.data(this[i], "olddisplay");
-
-                               this[i].style.display = old || "";
-
-                               if ( jQuery.css( this[i], "display" ) === "none" ) {
-                                       var nodeName = this[i].nodeName, display;
+function defaultDisplay(nodeName) {
+       if ( !elemdisplay[ nodeName ] ) {
+               var elem = jQuery("<" + nodeName + ">").appendTo("body"),
+                       display = elem.css("display");
 
-                                       if ( elemdisplay[ nodeName ] ) {
-                                               display = elemdisplay[ nodeName ];
+               elem.remove();
 
-                                       } else {
-                                               var elem = jQuery("<" + nodeName + ">").appendTo("body");
-
-                                               display = elem.css("display");
-
-                                               if ( display === "none" ) {
-                                                       display = "block";
-                                               }
+               if ( display === "none" || display === "" ) {
+                       display = "block";
+               }
 
-                                               elem.remove();
+               elemdisplay[ nodeName ] = display;
+       }
 
-                                               elemdisplay[ nodeName ] = display;
-                                       }
+       return elemdisplay[ nodeName ];
+}
 
-                                       jQuery.data(this[i], "olddisplay", display);
+jQuery.fn.extend({
+       show: function( speed, easing, callback ) {
+               if ( speed || speed === 0 ) {
+                       return this.animate( genFx("show", 3), speed, easing, callback);
+               } else {
+                       for ( var i = 0, j = this.length; i < j; i++ ) {
+                               // Set elements which have been overridden with display: none
+                               // in a stylesheet to whatever the default browser style is
+                               // for such an element
+                               if ( jQuery.css( this[i], "display" ) === "none" && this[i].style.display !== "none" ) {
+                                       jQuery.data(this[i], "olddisplay", defaultDisplay(this[i].nodeName));
                                }
                        }
 
                        // Set the display of the elements in a second loop
                        // to avoid the constant reflow
-                       for ( var j = 0, k = this.length; j < k; j++ ) {
-                               this[j].style.display = jQuery.data(this[j], "olddisplay") || "";
+                       for ( i = 0, j = this.length; i < j; i++ ) {
+                               this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
                        }
 
                        return this;
@@ -115,6 +111,9 @@ jQuery.fn.extend({
                }
 
                return this[ optall.queue === false ? "each" : "queue" ](function() {
+                       // XXX ‘this’ does not always have a nodeName when running the
+                       // test suite
+
                        var opt = jQuery.extend({}, optall), p,
                                hidden = this.nodeType === 1 && jQuery(this).is(":hidden"),
                                self = this;
@@ -132,12 +131,32 @@ jQuery.fn.extend({
                                        return opt.complete.call(this);
                                }
 
-                               if ( ( p === "height" || p === "width" ) && this.style ) {
-                                       // Store display property
-                                       opt.display = this.style.display;
-
+                               if ( ( p === "height" || p === "width" ) ) {
                                        // Make sure that nothing sneaks out
                                        opt.overflow = this.style.overflow;
+
+                                       // Set display property to inline-block for height/width
+                                       // animations on inline elements that are having width/height
+                                       // animated
+                                       if ( jQuery.curCSS( this, "display" ) === "inline" &&
+                                       jQuery.curCSS( this, "float" ) === "none" ) {
+                                               if ( !jQuery.support.inlineBlockNeedsLayout ) {
+                                                       this.style.display = "inline-block";
+                                               } else {
+                                                       var display = defaultDisplay(this.nodeName);
+
+                                                       // inline-level elements accept inline-block;
+                                                       // block-level elements need to be inline with layout
+                                                       if ( display === "inline" ) {
+                                                               this.style.display = "inline-block";
+                                                       }
+                                                       else {
+                                                               this.style.display = "inline";
+                                                               jQuery.data( this, "oldzoom", this.style.zoom );
+                                                               this.style.zoom = 1;
+                                                       }
+                                               }
+                                       }
                                }
 
                                if ( jQuery.isArray( prop[p] ) ) {
@@ -248,7 +267,7 @@ jQuery.each({
 
 jQuery.extend({
        speed: function( speed, easing, fn ) {
-               var opt = speed && typeof speed === "object" ? speed : {
+               var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
                        complete: fn || !fn && easing ||
                                jQuery.isFunction( speed ) && speed,
                        duration: speed,
@@ -256,7 +275,7 @@ jQuery.extend({
                };
 
                opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
-                       jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
+                       opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
 
                // Queueing
                opt.old = opt.complete;
@@ -303,11 +322,6 @@ jQuery.fx.prototype = {
                }
 
                (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
-
-               // Set display property to block for height/width animations
-               if ( ( this.prop === "height" || this.prop === "width" ) && this.elem.style ) {
-                       this.elem.style.display = "block";
-               }
        },
 
        // Get the current size
@@ -384,17 +398,9 @@ jQuery.fx.prototype = {
                        }
 
                        if ( done ) {
-                               if ( this.options.display != null ) {
-                                       // Reset the overflow
+                               // Reset the overflow
+                               if ( this.options.overflow != null ) {
                                        this.elem.style.overflow = this.options.overflow;
-
-                                       // Reset the display
-                                       var old = jQuery.data(this.elem, "olddisplay");
-                                       this.elem.style.display = old ? old : this.options.display;
-
-                                       if ( jQuery.css( this.elem, "display" ) === "none" ) {
-                                               this.elem.style.display = "block";
-                                       }
                                }
 
                                // Hide the element if the "hide" operation was done