]> source.dussan.org Git - jquery.git/commitdiff
Fix #13855: line-height animations. Close gh-1265.
authorRichard Gibson <richard.gibson@gmail.com>
Thu, 9 May 2013 02:56:51 +0000 (22:56 -0400)
committerRichard Gibson <richard.gibson@gmail.com>
Tue, 14 May 2013 00:33:28 +0000 (20:33 -0400)
(cherry picked from commit 3971c2ebb2e6729fe80bac4ee7b91bc02f26486f)

src/css.js
src/effects.js
test/unit/effects.js

index 892debf545ad816bfa2433c55cfeae9e7a1288fb..d9bc15fc146ff0e3033f73173c97bec7518b4eba 100644 (file)
@@ -161,7 +161,7 @@ jQuery.extend({
                }
        },
 
-       // Exclude the following css properties to add px
+       // Don't automatically add "px" to these possibly-unitless properties
        cssNumber: {
                "columnCount": true,
                "fillOpacity": true,
index 485c34a507915bf16557fca5eea8f4eb46bbc3e4..982365128751cff28c6cac62e325cec53205aa2b 100644 (file)
@@ -5,44 +5,51 @@ var fxNow, timerId,
        animationPrefilters = [ defaultPrefilter ],
        tweeners = {
                "*": [function( prop, value ) {
-                       var end, unit,
-                               tween = this.createTween( prop, value ),
-                               parts = rfxnum.exec( value ),
+                       var tween = this.createTween( prop, value ),
                                target = tween.cur(),
-                               start = +target || 0,
+                               parts = rfxnum.exec( value ),
+                               unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+                               // Starting value computation is required for potential unit mismatches
+                               start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+                                       rfxnum.exec( jQuery.css( tween.elem, prop ) ),
                                scale = 1,
                                maxIterations = 20;
 
-                       if ( parts ) {
-                               end = +parts[2];
-                               unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
-
-                               // We need to compute starting value
-                               if ( unit !== "px" && start ) {
-                                       // Iteratively approximate from a nonzero starting point
-                                       // Prefer the current property, because this process will be trivial if it uses the same units
-                                       // Fallback to end or a simple constant
-                                       start = jQuery.css( tween.elem, prop, true ) || end || 1;
-
-                                       do {
-                                               // If previous iteration zeroed out, double until we get *something*
-                                               // Use a string for doubling factor so we don't accidentally see scale as unchanged below
-                                               scale = scale || ".5";
-
-                                               // Adjust and apply
-                                               start = start / scale;
-                                               jQuery.style( tween.elem, prop, start + unit );
-
-                                       // Update scale, tolerating zero or NaN from tween.cur()
-                                       // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
-                                       } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
-                               }
+                       if ( start && start[ 3 ] !== unit ) {
+                               // Trust units reported by jQuery.css
+                               unit = unit || start[ 3 ];
+
+                               // Make sure we update the tween properties later on
+                               parts = parts || [];
+
+                               // Iteratively approximate from a nonzero starting point
+                               start = +target || 1;
 
+                               do {
+                                       // If previous iteration zeroed out, double until we get *something*
+                                       // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+                                       scale = scale || ".5";
+
+                                       // Adjust and apply
+                                       start = start / scale;
+                                       jQuery.style( tween.elem, prop, start + unit );
+
+                               // Update scale, tolerating zero or NaN from tween.cur()
+                               // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+                               } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+                       }
+
+                       // Update tween properties
+                       if ( parts ) {
                                tween.unit = unit;
-                               tween.start = start;
+                               tween.start = +start || +target || 0;
                                // If a +=/-= token was provided, we're doing a relative animation
-                               tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
+                               tween.end = parts[ 1 ] ?
+                                       start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+                                       +parts[ 2 ];
                        }
+
                        return tween;
                }]
        };
@@ -55,19 +62,18 @@ function createFxNow() {
        return ( fxNow = jQuery.now() );
 }
 
-function createTweens( animation, props ) {
-       jQuery.each( props, function( prop, value ) {
-               var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
-                       index = 0,
-                       length = collection.length;
-               for ( ; index < length; index++ ) {
-                       if ( collection[ index ].call( animation, prop, value ) ) {
+function createTween( value, prop, animation ) {
+       var tween,
+               collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+               index = 0,
+               length = collection.length;
+       for ( ; index < length; index++ ) {
+               if ( (tween = collection[ index ].call( animation, prop, value )) ) {
 
-                               // we're done with this property
-                               return;
-                       }
+                       // we're done with this property
+                       return tween;
                }
-       });
+       }
 }
 
 function Animation( elem, properties, options ) {
@@ -153,7 +159,7 @@ function Animation( elem, properties, options ) {
                }
        }
 
-       createTweens( animation, props );
+       jQuery.map( props, createTween, animation );
 
        if ( jQuery.isFunction( animation.opts.start ) ) {
                animation.opts.start.call( elem, animation );
@@ -243,14 +249,12 @@ jQuery.Animation = jQuery.extend( Animation, {
 
 function defaultPrefilter( elem, props, opts ) {
        /* jshint validthis: true */
-       var prop, index, length,
-               value, dataShow, toggle,
-               tween, hooks, oldfire,
+       var prop, value, toggle, tween, hooks, oldfire,
                anim = this,
-               style = elem.style,
                orig = {},
-               handled = [],
-               hidden = elem.nodeType && isHidden( elem );
+               style = elem.style,
+               hidden = elem.nodeType && isHidden( elem ),
+               dataShow = jQuery._data( elem, "fxshow" );
 
        // handle queue: false promises
        if ( !opts.queue ) {
@@ -315,23 +319,25 @@ function defaultPrefilter( elem, props, opts ) {
 
 
        // show/hide pass
-       for ( index in props ) {
-               value = props[ index ];
+       for ( prop in props ) {
+               value = props[ prop ];
                if ( rfxtypes.exec( value ) ) {
-                       delete props[ index ];
+                       delete props[ prop ];
                        toggle = toggle || value === "toggle";
                        if ( value === ( hidden ? "hide" : "show" ) ) {
                                continue;
                        }
-                       handled.push( index );
+                       orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
                }
        }
 
-       length = handled.length;
-       if ( length ) {
-               dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
-               if ( "hidden" in dataShow ) {
-                       hidden = dataShow.hidden;
+       if ( !jQuery.isEmptyObject( orig ) ) {
+               if ( dataShow ) {
+                       if ( "hidden" in dataShow ) {
+                               hidden = dataShow.hidden;
+                       }
+               } else {
+                       dataShow = jQuery._data( elem, "fxshow", {} );
                }
 
                // store state if its toggle - enables .stop().toggle() to "reverse"
@@ -352,10 +358,8 @@ function defaultPrefilter( elem, props, opts ) {
                                jQuery.style( elem, prop, orig[ prop ] );
                        }
                });
-               for ( index = 0 ; index < length ; index++ ) {
-                       prop = handled[ index ];
-                       tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
-                       orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
+               for ( prop in orig ) {
+                       tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
 
                        if ( !( prop in dataShow ) ) {
                                dataShow[ prop ] = tween.start;
index f276ac3bab6df18f329dba41ec5a3b58d5c1e993..a23ff2cca386ed5a43a1d5f5853a82acdb1425e4 100644 (file)
@@ -1405,6 +1405,44 @@ test("Do not append px to 'fill-opacity' #9548", 1, function() {
        });
 });
 
+test("line-height animates correctly (#13855)", function() {
+       expect( 12 );
+       stop();
+
+       var
+               animated = jQuery(
+                       "<p style='line-height: 4;'>unitless</p>" +
+                       "<p style='line-height: 50px;'>px</p>" +
+                       "<p style='line-height: 420%;'>percent</p>" +
+                       "<p style='line-height: 2.5em;'>em</p>"
+               ).appendTo("#qunit-fixture"),
+               initialHeight = jQuery.map( animated, function( el ) {
+                       return jQuery( el ).height();
+               });
+
+       animated.animate( { "line-height": "hide" }, 1500 );
+       setTimeout(function() {
+               animated.each(function( i ) {
+                       var label = jQuery.text( this ),
+                               initial = initialHeight[ i ],
+                               height = jQuery( this ).height();
+                       ok( height < initial, "hide " + label + ": upper bound" );
+                       ok( height > initial / 2, "hide " + label + ": lower bound" );
+               });
+               animated.stop( true, true ).hide().animate( { "line-height": "show" }, 1500 );
+               setTimeout(function() {
+                       animated.each(function( i ) {
+                               var label = jQuery.text( this ),
+                                       initial = initialHeight[ i ],
+                                       height = jQuery( this ).height();
+                               ok( height < initial / 2, "show " + label + ": upper bound" );
+                       });
+                       animated.stop( true, true );
+                       start();
+               }, 400 );
+       }, 400 );
+});
+
 // Start 1.8 Animation tests
 asyncTest( "jQuery.Animation( object, props, opts )", 4, function() {
        var animation,