Fix #8498. Add cssHooks[prop].expand for use by animate().

This commit is contained in:
Mike Sherov 2011-12-08 20:01:23 -05:00 committed by Dave Methvin
parent 7f6a991313
commit 8f5f1b2e6c
4 changed files with 127 additions and 21 deletions

View File

@ -10,8 +10,10 @@ var ralpha = /alpha\([^)]*\)/i,
rmargin = /^margin/,
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssWidth = [ "Left", "Right" ],
cssHeight = [ "Top", "Bottom" ],
// order is important!
cssExpand = [ "Top", "Right", "Bottom", "Left" ],
curCSS,
getComputedStyle,
@ -169,10 +171,10 @@ jQuery.each(["height", "width"], function( i, name ) {
get: function( elem, computed, extra ) {
if ( computed ) {
if ( elem.offsetWidth !== 0 ) {
return getWH( elem, name, extra );
return getWidthOrHeight( elem, name, extra );
} else {
return jQuery.swap( elem, cssShow, function() {
return getWH( elem, name, extra );
return getWidthOrHeight( elem, name, extra );
});
}
}
@ -326,24 +328,23 @@ if ( document.documentElement.currentStyle ) {
curCSS = getComputedStyle || currentStyle;
function getWH( elem, name, extra ) {
function getWidthOrHeight( elem, name, extra ) {
// Start with offset property
var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
which = name === "width" ? cssWidth : cssHeight,
i = 0,
len = which.length;
i = name === "width" ? 1 : 0,
len = 4;
if ( val > 0 ) {
if ( extra !== "border" ) {
for ( ; i < len; i++ ) {
for ( ; i < len; i += 2 ) {
if ( !extra ) {
val -= parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
}
if ( extra === "margin" ) {
val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
} else {
val -= parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
}
}
}
@ -354,20 +355,20 @@ function getWH( elem, name, extra ) {
// Fall back to computed then uncomputed css if necessary
val = curCSS( elem, name, name );
if ( val < 0 || val == null ) {
val = elem.style[ name ] || 0;
val = elem.style[ name ];
}
// Normalize "", auto, and prepare for extra
val = parseFloat( val ) || 0;
// Add padding, border, margin
if ( extra ) {
for ( ; i < len; i++ ) {
val += parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
for ( ; i < len; i += 2 ) {
val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
if ( extra !== "padding" ) {
val += parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
}
if ( extra === "margin" ) {
val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
}
}
}
@ -388,4 +389,29 @@ if ( jQuery.expr && jQuery.expr.filters ) {
};
}
// These hooks are used by animate to expand properties
jQuery.each({
margin: "",
padding: "",
border: "Width"
}, function( prefix, suffix ) {
jQuery.cssHooks[ prefix + suffix ] = {
expand: function( value ) {
var i,
// assumes a single number if not a string
parts = typeof value === "string" ? value.split(" ") : [ value ],
expanded = {};
for ( i = 0; i < 4; i++ ) {
expanded[ prefix + cssExpand[ i ] + suffix ] =
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
}
return expanded;
}
};
});
})( jQuery );

21
src/effects.js vendored
View File

@ -142,24 +142,37 @@ jQuery.fn.extend({
var opt = jQuery.extend( {}, optall ),
isElement = this.nodeType === 1,
hidden = isElement && jQuery(this).is(":hidden"),
name, val, p, e,
name, val, p, e, hooks, replace,
parts, start, end, unit,
method;
// will store per property easing and be used to determine when an animation is complete
opt.animatedProperties = {};
// first pass over propertys to expand / normalize
for ( p in prop ) {
// property name normalization
name = jQuery.camelCase( p );
if ( p !== name ) {
prop[ name ] = prop[ p ];
delete prop[ p ];
}
if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
replace = hooks.expand( prop[ name ] );
delete prop[ name ];
// not quite $.extend, this wont overwrite keys already present.
// also - reusing 'p' from above because we have the correct "name"
for ( p in replace ) {
if ( ! ( p in prop ) ) {
prop[ p ] = replace[ p ];
}
}
}
}
for ( name in prop ) {
val = prop[ name ];
// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
if ( jQuery.isArray( val ) ) {
opt.animatedProperties[ name ] = val[ 1 ];

View File

@ -549,4 +549,44 @@ test("outerWidth(true) and css('margin') returning % instead of px in Webkit, se
el = jQuery( "<div/>" ).css({ width: "50%", marginRight: "50%" }).appendTo( container );
equal( el.outerWidth(true), 400, "outerWidth(true) and css('margin') returning % instead of px in Webkit, see #10639" );
});
test( "cssHooks - expand", function() {
expect( 15 );
var result,
properties = {
margin: [ "marginTop", "marginRight", "marginBottom", "marginLeft" ],
borderWidth: [ "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth"],
padding: [ "paddingTop", "paddingRight", "paddingBottom", "paddingLeft" ]
};
jQuery.each( properties, function( property, keys ) {
var hook = jQuery.cssHooks[ property ],
expected = {};
jQuery.each( keys, function( _, key ) {
expected[ key ] = 10;
});
result = hook.expand( 10 );
deepEqual( result, expected, property + " expands properly with a number" );
jQuery.each( keys, function( _, key ) {
expected[ key ] = "10px";
});
result = hook.expand( "10px" );
deepEqual( result, expected, property + " expands properly with '10px'" );
expected[ keys[1] ] = expected[ keys[3] ] = "20px";
result = hook.expand( "10px 20px" );
deepEqual( result, expected, property + " expands properly with '10px 20px'" );
expected[ keys[2] ] = "30px";
result = hook.expand( "10px 20px 30px" );
deepEqual( result, expected, property + " expands properly with '10px 20px 30px'" );
expected[ keys[3] ] = "40px";
result = hook.expand( "10px 20px 30px 40px" );
deepEqual( result, expected, property + " expands properly with '10px 20px 30px 40px'" );
});
});

27
test/unit/effects.js vendored
View File

@ -1271,3 +1271,30 @@ asyncTest( "callbacks that throw exceptions will be removed (#5684)", function()
start();
}, 1);
});
test("animate will scale margin properties individually", function() {
expect( 2 );
stop();
var foo = jQuery( "#foo" ).css({
margin: 0,
marginLeft: 100
});
ok( foo.css( "marginLeft" ) !== foo.css( "marginRight" ), "Sanity Check" );
foo.animate({
margin: 200
}).stop();
ok( foo.css( "marginLeft") !== foo.css( "marginRight" ), "The margin properties are different");
// clean up for next test
foo.css({
marginLeft: '',
marginRight: '',
marginTop: '',
marginBottom: ''
});
start();
});