Skip to content
Permalink
Browse files

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

  • Loading branch information...
mikesherov authored and dmethvin committed Dec 9, 2011
1 parent 7f6a991 commit 8f5f1b2e6c0f7b8b6d66bfc06c7b169a9443c2b8
Showing with 127 additions and 21 deletions.
  1. +43 −17 src/css.js
  2. +17 −4 src/effects.js
  3. +40 −0 test/unit/css.js
  4. +27 −0 test/unit/effects.js
@@ -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 );
@@ -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 ];
@@ -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'" );

});

});
@@ -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();
});

0 comments on commit 8f5f1b2

Please sign in to comment.
You can’t perform that action at this time.