]> source.dussan.org Git - jquery.git/commitdiff
CSS: Don't cache unrecognized CSS property names
authorMichał Gołębiowski <m.goleb@gmail.com>
Mon, 11 May 2015 21:23:09 +0000 (23:23 +0200)
committerMichał Gołębiowski <m.goleb@gmail.com>
Mon, 1 Jun 2015 12:05:05 +0000 (14:05 +0200)
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.

Fixes gh-2015
Closes gh-2298

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

index 7b011668ef6f171ad8338f926c862451c332e263..566f5a0fd6b034028e44ac916baebfabd09d7954 100644 (file)
@@ -3,6 +3,7 @@ define([
        "./var/pnum",
        "./core/access",
        "./css/var/rmargin",
+       "./var/document",
        "./var/rcssNum",
        "./css/var/rnumnonpx",
        "./css/var/cssExpand",
@@ -18,8 +19,8 @@ define([
        "./core/init",
        "./core/ready",
        "./selector" // contains
-], function( jQuery, pnum, access, rmargin, rcssNum, rnumnonpx, cssExpand, isHidden,
-       getStyles, swap, curCSS, adjustCSS, addGetHookIf, support, showHide ) {
+], function( jQuery, pnum, access, rmargin, document, rcssNum, rnumnonpx, cssExpand,
+       isHidden, getStyles, swap, curCSS, adjustCSS, addGetHookIf, support, showHide ) {
 
 var
        // Swappable if display is none or starts with table
@@ -34,29 +35,27 @@ var
                fontWeight: "400"
        },
 
-       cssPrefixes = [ "Webkit", "Moz", "ms" ];
+       cssPrefixes = [ "Webkit", "Moz", "ms" ],
+       emptyStyle = document.createElement( "div" ).style;
 
 // Return a css property mapped to a potentially vendor prefixed property
-function vendorPropName( style, name ) {
+function vendorPropName( name ) {
 
        // Shortcut for names that are not vendor prefixed
-       if ( name in style ) {
+       if ( name in emptyStyle ) {
                return name;
        }
 
        // Check for vendor prefixed names
        var capName = name[0].toUpperCase() + name.slice(1),
-               origName = name,
                i = cssPrefixes.length;
 
        while ( i-- ) {
                name = cssPrefixes[ i ] + capName;
-               if ( name in style ) {
+               if ( name in emptyStyle ) {
                        return name;
                }
        }
-
-       return origName;
 }
 
 function setPositiveNumber( elem, value, subtract ) {
@@ -203,7 +202,7 @@ jQuery.extend({
                        style = elem.style;
 
                name = jQuery.cssProps[ origName ] ||
-                       ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+                       ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
 
                // Gets hook for the prefixed version, then unprefixed version
                hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
@@ -261,7 +260,7 @@ jQuery.extend({
 
                // Make sure that we're working with the right name
                name = jQuery.cssProps[ origName ] ||
-                       ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+                       ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
 
                // Try prefixed name followed by the unprefixed name
                hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
index 4d0e11b3b812c4f333065d63a9ce96717a2f1a14..22a3c7636585b63a12d8e09124014a8c467c91a8 100644 (file)
@@ -1116,4 +1116,84 @@ test( "Do not throw on frame elements from css method (#15098)", 1, function() {
                ok( false, "It did throw" );
        }
 });
+
+( function() {
+       var vendorPrefixes = [ "Webkit", "Moz", "ms" ];
+
+       function resetCssPropsFor( name ) {
+               delete jQuery.cssProps[ name ];
+               jQuery.each( vendorPrefixes, function( index, prefix ) {
+                       delete jQuery.cssProps[ prefix + name[ 0 ].toUpperCase() + name.slice( 1 ) ];
+               } );
+       }
+
+       test( "Don't default to a cached previously used wrong prefixed name (gh-2015)", function() {
+               // Note: this test needs a property we know is only supported in a prefixed version
+               // by at least one of our main supported browsers. This may get out of date so let's
+               // use -(webkit|moz)-appearance as well as those two are not on a standards track.
+               var appearanceName, transformName, elem, elemStyle,
+                       transformVal = "translate(5px, 2px)",
+                       emptyStyle = document.createElement( "div" ).style;
+
+               if ( "appearance" in emptyStyle ) {
+                       appearanceName = "appearance";
+               } else {
+                       jQuery.each( vendorPrefixes, function( index, prefix ) {
+                               var prefixedProp = prefix + "Appearance";
+                               if ( prefixedProp in emptyStyle ) {
+                                       appearanceName = prefixedProp;
+                               }
+                       } );
+               }
+
+               if ( "transform" in emptyStyle ) {
+                       transformName = "transform";
+               } else {
+                       jQuery.each( vendorPrefixes, function( index, prefix ) {
+                               var prefixedProp = prefix + "Transform";
+                               if ( prefixedProp in emptyStyle ) {
+                                       transformName = prefixedProp;
+                               }
+                       } );
+               }
+
+               expect( !!appearanceName + !!transformName + 1 );
+
+               resetCssPropsFor( "appearance" );
+               resetCssPropsFor( "transform" );
+
+               elem = jQuery( "<div/>" )
+                       .css( {
+                               msAppearance: "none",
+                               appearance: "none",
+
+                               // Only the ms prefix is used to make sure we haven't e.g. set
+                               // webkitTransform ourselves in the test.
+                               msTransform: transformVal,
+                               transform: transformVal
+                       } );
+               elemStyle = elem[ 0 ].style;
+
+               if ( appearanceName ) {
+                       equal( elemStyle[ appearanceName ], "none", "setting properly-prefixed appearance" );
+               }
+               if ( transformName ) {
+                       equal( elemStyle[ transformName ], transformVal, "setting properly-prefixed transform" );
+               }
+               equal( elemStyle.undefined, undefined, "Nothing writes to node.style.undefined" );
+       } );
+
+       test( "Don't detect fake set properties on a node when caching the prefixed version", function() {
+               expect( 1 );
+
+               var elem = jQuery( "<div/>" ),
+                       style = elem[ 0 ].style;
+               style.MozFakeProperty = "old value";
+               elem.css( "fakeProperty", "new value" );
+
+               equal( style.MozFakeProperty, "old value", "Fake prefixed property is not cached" );
+       } );
+
+} )();
+
 }