Skip to content

Commit 42ea746

Browse files
committed
CSS: Don't cache unrecognized CSS property names
This prevents jQuery from caching a prefixed property name if provided directly by the user, e.g. the following code: elem.css( "msTransform", "translate(5px, 2px)" ); should not prevent one from from later setting the transition directly: elem.css( "transform", "translate(5px, 2px)" ); on a browser not understanding the unprefixed version which is the case for Safari 8 & transform. (cherry-picked from d471842) Fixes gh-2015 Closes gh-2298
1 parent 37c3d08 commit 42ea746

File tree

2 files changed

+87
-9
lines changed

2 files changed

+87
-9
lines changed

src/css.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,32 +39,30 @@ var
3939
fontWeight: "400"
4040
},
4141

42-
cssPrefixes = [ "Webkit", "Moz", "ms" ];
42+
cssPrefixes = [ "Webkit", "Moz", "ms" ],
43+
emptyStyle = document.createElement( "div" ).style;
4344

4445
// BuildExclude
4546
curCSS = curCSS.curCSS;
4647

4748
// return a css property mapped to a potentially vendor prefixed property
48-
function vendorPropName( style, name ) {
49+
function vendorPropName( name ) {
4950

5051
// shortcut for names that are not vendor prefixed
51-
if ( name in style ) {
52+
if ( name in emptyStyle ) {
5253
return name;
5354
}
5455

5556
// check for vendor prefixed names
5657
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
57-
origName = name,
5858
i = cssPrefixes.length;
5959

6060
while ( i-- ) {
6161
name = cssPrefixes[ i ] + capName;
62-
if ( name in style ) {
62+
if ( name in emptyStyle ) {
6363
return name;
6464
}
6565
}
66-
67-
return origName;
6866
}
6967

7068
function setPositiveNumber( elem, value, subtract ) {
@@ -209,7 +207,7 @@ jQuery.extend({
209207
style = elem.style;
210208

211209
name = jQuery.cssProps[ origName ] ||
212-
( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
210+
( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
213211

214212
// gets hook for the prefixed version
215213
// followed by the unprefixed version
@@ -273,7 +271,7 @@ jQuery.extend({
273271

274272
// Make sure that we're working with the right name
275273
name = jQuery.cssProps[ origName ] ||
276-
( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
274+
( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
277275

278276
// gets hook for the prefixed version
279277
// followed by the unprefixed version

test/unit/css.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,4 +1187,84 @@ test( "get upper case alpha opacity in IE8", 1, function() {
11871187
fixture.removeChild( div );
11881188
});
11891189

1190+
1191+
( function() {
1192+
var vendorPrefixes = [ "Webkit", "Moz", "ms" ];
1193+
1194+
function resetCssPropsFor( name ) {
1195+
delete jQuery.cssProps[ name ];
1196+
jQuery.each( vendorPrefixes, function( index, prefix ) {
1197+
delete jQuery.cssProps[ prefix + name[ 0 ].toUpperCase() + name.slice( 1 ) ];
1198+
} );
1199+
}
1200+
1201+
test( "Don't default to a cached previously used wrong prefixed name (gh-2015)", function() {
1202+
// Note: this test needs a property we know is only supported in a prefixed version
1203+
// by at least one of our main supported browsers. This may get out of date so let's
1204+
// use -(webkit|moz)-appearance as well as those two are not on a standards track.
1205+
var appearanceName, transformName, elem, elemStyle,
1206+
transformVal = "translate(5px, 2px)",
1207+
emptyStyle = document.createElement( "div" ).style;
1208+
1209+
if ( "appearance" in emptyStyle ) {
1210+
appearanceName = "appearance";
1211+
} else {
1212+
jQuery.each( vendorPrefixes, function( index, prefix ) {
1213+
var prefixedProp = prefix + "Appearance";
1214+
if ( prefixedProp in emptyStyle ) {
1215+
appearanceName = prefixedProp;
1216+
}
1217+
} );
1218+
}
1219+
1220+
if ( "transform" in emptyStyle ) {
1221+
transformName = "transform";
1222+
} else {
1223+
jQuery.each( vendorPrefixes, function( index, prefix ) {
1224+
var prefixedProp = prefix + "Transform";
1225+
if ( prefixedProp in emptyStyle ) {
1226+
transformName = prefixedProp;
1227+
}
1228+
} );
1229+
}
1230+
1231+
expect( !!appearanceName + !!transformName + 1 );
1232+
1233+
resetCssPropsFor( "appearance" );
1234+
resetCssPropsFor( "transform" );
1235+
1236+
elem = jQuery( "<div/>" )
1237+
.css( {
1238+
msAppearance: "none",
1239+
appearance: "none",
1240+
1241+
// Only the ms prefix is used to make sure we haven't e.g. set
1242+
// webkitTransform ourselves in the test.
1243+
msTransform: transformVal,
1244+
transform: transformVal
1245+
} );
1246+
elemStyle = elem[ 0 ].style;
1247+
1248+
if ( appearanceName ) {
1249+
equal( elemStyle[ appearanceName ], "none", "setting properly-prefixed appearance" );
1250+
}
1251+
if ( transformName ) {
1252+
equal( elemStyle[ transformName ], transformVal, "setting properly-prefixed transform" );
1253+
}
1254+
equal( elemStyle[ "undefined" ], undefined, "Nothing writes to node.style.undefined" );
1255+
} );
1256+
1257+
test( "Don't detect fake set properties on a node when caching the prefixed version", function() {
1258+
expect( 1 );
1259+
1260+
var elem = jQuery( "<div/>" ),
1261+
style = elem[ 0 ].style;
1262+
style.MozFakeProperty = "old value";
1263+
elem.css( "fakeProperty", "new value" );
1264+
1265+
equal( style.MozFakeProperty, "old value", "Fake prefixed property is not cached" );
1266+
} );
1267+
1268+
} )();
1269+
11901270
}

0 commit comments

Comments
 (0)