Skip to content

Commit 8f5f1b2

Browse files
mikesherovdmethvin
authored andcommitted
Fix #8498. Add cssHooks[prop].expand for use by animate().
1 parent 7f6a991 commit 8f5f1b2

File tree

4 files changed

+127
-21
lines changed

4 files changed

+127
-21
lines changed

src/css.js

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ var ralpha = /alpha\([^)]*\)/i,
1010
rmargin = /^margin/,
1111

1212
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
13-
cssWidth = [ "Left", "Right" ],
14-
cssHeight = [ "Top", "Bottom" ],
13+
14+
// order is important!
15+
cssExpand = [ "Top", "Right", "Bottom", "Left" ],
16+
1517
curCSS,
1618

1719
getComputedStyle,
@@ -169,10 +171,10 @@ jQuery.each(["height", "width"], function( i, name ) {
169171
get: function( elem, computed, extra ) {
170172
if ( computed ) {
171173
if ( elem.offsetWidth !== 0 ) {
172-
return getWH( elem, name, extra );
174+
return getWidthOrHeight( elem, name, extra );
173175
} else {
174176
return jQuery.swap( elem, cssShow, function() {
175-
return getWH( elem, name, extra );
177+
return getWidthOrHeight( elem, name, extra );
176178
});
177179
}
178180
}
@@ -326,24 +328,23 @@ if ( document.documentElement.currentStyle ) {
326328

327329
curCSS = getComputedStyle || currentStyle;
328330

329-
function getWH( elem, name, extra ) {
331+
function getWidthOrHeight( elem, name, extra ) {
330332

331333
// Start with offset property
332334
var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
333-
which = name === "width" ? cssWidth : cssHeight,
334-
i = 0,
335-
len = which.length;
335+
i = name === "width" ? 1 : 0,
336+
len = 4;
336337

337338
if ( val > 0 ) {
338339
if ( extra !== "border" ) {
339-
for ( ; i < len; i++ ) {
340+
for ( ; i < len; i += 2 ) {
340341
if ( !extra ) {
341-
val -= parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
342+
val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
342343
}
343344
if ( extra === "margin" ) {
344-
val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
345+
val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
345346
} else {
346-
val -= parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
347+
val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
347348
}
348349
}
349350
}
@@ -354,20 +355,20 @@ function getWH( elem, name, extra ) {
354355
// Fall back to computed then uncomputed css if necessary
355356
val = curCSS( elem, name, name );
356357
if ( val < 0 || val == null ) {
357-
val = elem.style[ name ] || 0;
358+
val = elem.style[ name ];
358359
}
359360
// Normalize "", auto, and prepare for extra
360361
val = parseFloat( val ) || 0;
361362

362363
// Add padding, border, margin
363364
if ( extra ) {
364-
for ( ; i < len; i++ ) {
365-
val += parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
365+
for ( ; i < len; i += 2 ) {
366+
val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
366367
if ( extra !== "padding" ) {
367-
val += parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
368+
val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
368369
}
369370
if ( extra === "margin" ) {
370-
val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
371+
val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
371372
}
372373
}
373374
}
@@ -388,4 +389,29 @@ if ( jQuery.expr && jQuery.expr.filters ) {
388389
};
389390
}
390391

392+
// These hooks are used by animate to expand properties
393+
jQuery.each({
394+
margin: "",
395+
padding: "",
396+
border: "Width"
397+
}, function( prefix, suffix ) {
398+
399+
jQuery.cssHooks[ prefix + suffix ] = {
400+
expand: function( value ) {
401+
var i,
402+
403+
// assumes a single number if not a string
404+
parts = typeof value === "string" ? value.split(" ") : [ value ],
405+
expanded = {};
406+
407+
for ( i = 0; i < 4; i++ ) {
408+
expanded[ prefix + cssExpand[ i ] + suffix ] =
409+
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
410+
}
411+
412+
return expanded;
413+
}
414+
};
415+
});
416+
391417
})( jQuery );

src/effects.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,24 +142,37 @@ jQuery.fn.extend({
142142
var opt = jQuery.extend( {}, optall ),
143143
isElement = this.nodeType === 1,
144144
hidden = isElement && jQuery(this).is(":hidden"),
145-
name, val, p, e,
145+
name, val, p, e, hooks, replace,
146146
parts, start, end, unit,
147147
method;
148148

149149
// will store per property easing and be used to determine when an animation is complete
150150
opt.animatedProperties = {};
151151

152+
// first pass over propertys to expand / normalize
152153
for ( p in prop ) {
153-
154-
// property name normalization
155154
name = jQuery.camelCase( p );
156155
if ( p !== name ) {
157156
prop[ name ] = prop[ p ];
158157
delete prop[ p ];
159158
}
159+
160+
if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
161+
replace = hooks.expand( prop[ name ] );
162+
delete prop[ name ];
163+
164+
// not quite $.extend, this wont overwrite keys already present.
165+
// also - reusing 'p' from above because we have the correct "name"
166+
for ( p in replace ) {
167+
if ( ! ( p in prop ) ) {
168+
prop[ p ] = replace[ p ];
169+
}
170+
}
171+
}
172+
}
160173

174+
for ( name in prop ) {
161175
val = prop[ name ];
162-
163176
// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
164177
if ( jQuery.isArray( val ) ) {
165178
opt.animatedProperties[ name ] = val[ 1 ];

test/unit/css.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,4 +549,44 @@ test("outerWidth(true) and css('margin') returning % instead of px in Webkit, se
549549
el = jQuery( "<div/>" ).css({ width: "50%", marginRight: "50%" }).appendTo( container );
550550

551551
equal( el.outerWidth(true), 400, "outerWidth(true) and css('margin') returning % instead of px in Webkit, see #10639" );
552+
});
553+
554+
test( "cssHooks - expand", function() {
555+
expect( 15 );
556+
var result,
557+
properties = {
558+
margin: [ "marginTop", "marginRight", "marginBottom", "marginLeft" ],
559+
borderWidth: [ "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth"],
560+
padding: [ "paddingTop", "paddingRight", "paddingBottom", "paddingLeft" ]
561+
};
562+
563+
jQuery.each( properties, function( property, keys ) {
564+
var hook = jQuery.cssHooks[ property ],
565+
expected = {};
566+
jQuery.each( keys, function( _, key ) {
567+
expected[ key ] = 10;
568+
});
569+
result = hook.expand( 10 );
570+
deepEqual( result, expected, property + " expands properly with a number" );
571+
572+
jQuery.each( keys, function( _, key ) {
573+
expected[ key ] = "10px";
574+
});
575+
result = hook.expand( "10px" );
576+
deepEqual( result, expected, property + " expands properly with '10px'" );
577+
578+
expected[ keys[1] ] = expected[ keys[3] ] = "20px";
579+
result = hook.expand( "10px 20px" );
580+
deepEqual( result, expected, property + " expands properly with '10px 20px'" );
581+
582+
expected[ keys[2] ] = "30px";
583+
result = hook.expand( "10px 20px 30px" );
584+
deepEqual( result, expected, property + " expands properly with '10px 20px 30px'" );
585+
586+
expected[ keys[3] ] = "40px";
587+
result = hook.expand( "10px 20px 30px 40px" );
588+
deepEqual( result, expected, property + " expands properly with '10px 20px 30px 40px'" );
589+
590+
});
591+
552592
});

test/unit/effects.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,3 +1271,30 @@ asyncTest( "callbacks that throw exceptions will be removed (#5684)", function()
12711271
start();
12721272
}, 1);
12731273
});
1274+
1275+
test("animate will scale margin properties individually", function() {
1276+
expect( 2 );
1277+
stop();
1278+
1279+
var foo = jQuery( "#foo" ).css({
1280+
margin: 0,
1281+
marginLeft: 100
1282+
});
1283+
1284+
ok( foo.css( "marginLeft" ) !== foo.css( "marginRight" ), "Sanity Check" );
1285+
1286+
foo.animate({
1287+
margin: 200
1288+
}).stop();
1289+
1290+
ok( foo.css( "marginLeft") !== foo.css( "marginRight" ), "The margin properties are different");
1291+
1292+
// clean up for next test
1293+
foo.css({
1294+
marginLeft: '',
1295+
marginRight: '',
1296+
marginTop: '',
1297+
marginBottom: ''
1298+
});
1299+
start();
1300+
});

0 commit comments

Comments
 (0)