From 42156d9d0f97af2ec387e830a81ddd14c6e04caa Mon Sep 17 00:00:00 2001 From: Ian Obermiller Date: Wed, 22 Apr 2015 01:20:40 -0700 Subject: [PATCH 1/6] Simple prefixing based on css-vendor --- modules/prefix.js | 113 ++++++++++++++++++++++++++++++++++++++ modules/resolve-styles.js | 6 +- 2 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 modules/prefix.js diff --git a/modules/prefix.js b/modules/prefix.js new file mode 100644 index 00000000..bc95ca22 --- /dev/null +++ b/modules/prefix.js @@ -0,0 +1,113 @@ +/** + * Based on https://github.com/jsstyles/css-vendor, but without any dash-case + * shenanigans. + */ + +var camelCase = require('lodash/string/camelCase'); +var kebabCase = require('lodash/string/kebabCase'); + +var domStyle = document.createElement('p').style; +var prefixedPropertyCache = {}; +var prefixedValueCache = {}; +var vendorPrefix = ''; + +['Webkit', 'Moz', 'ms', 'O'].some(function(prefix) { + if ((prefix + 'Transform') in domStyle) { + vendorPrefix = prefix; + return true; + } + return false; +}); + +function _getPrefixedProperty(property) { + if (prefixedPropertyCache[property]) { + return prefixedPropertyCache[property]; + } + + if (property in domStyle) { + // unprefixed + return prefixedPropertyCache[property] = property; + } + + var newProperty = + vendorPrefix + property[0].toUpperCase() + property.slice(1); + if (newProperty in domStyle) { + // prefixed + return prefixedPropertyCache[property] = newProperty; + } + + // unsupported + return prefixedPropertyCache[property] = false; +} + +function _getPrefixedValue(property, value) { + // don't test numbers or numbers with units (e.g. 10em) + if (typeof value !== 'string' || !isNaN(parseInt(value, 10))) { + return value; + } + + var cacheKey = property + value; + + if (prefixedValueCache[cacheKey]) { + return prefixedValueCache[cacheKey]; + } + + // Clear style first + domStyle[property] = ''; + + // Test value as it is. + domStyle[property] = value; + + // Value is supported as it is. Note that we just make sure it is not an empty + // string. Browsers will sometimes rewrite values, but still accept them. They + // will set the value to an empty string if not supported. + // E.g. for border, "solid 1px black" becomes "1px solid black" + // but "foobar" becomes "", since it is not supported. + if (domStyle[property]) { + prefixedValueCache[cacheKey] = value; + return value; + } + + // Test value with vendor prefix. + value = vendorPrefix + value; + domStyle[property] = value; + + // Value is supported with vendor prefix. + if (domStyle[property]) { + prefixedValueCache[cacheKey] = value; + return value; + } + + return prefixedValueCache[cacheKey] = false; +} + +/** + * Returns a new style object with vendor prefixes added to property names + * and values. + */ +function prefix(style) { + var newStyle = {}; + Object.keys(style).forEach(function(property) { + var value = style[property]; + + var newProperty = _getPrefixedProperty(property); + if (newProperty === false) { + // Ignore unsupported properties + console.warn('Unsupported CSS property ' + property); + return; + } + + var newValue = _getPrefixedValue(newProperty, value); + if (newValue === false) { + // Ignore unsupported values + console.warn( + 'Unsupported CSS value ' + value + ' for property ' + property + ); + } + + newStyle[newProperty] = newValue; + }); + return newStyle; +} + +module.exports = prefix; diff --git a/modules/resolve-styles.js b/modules/resolve-styles.js index c53293d7..cfa22ece 100644 --- a/modules/resolve-styles.js +++ b/modules/resolve-styles.js @@ -2,6 +2,7 @@ var MouseUpListener = require('./mouse-up-listener'); var getState = require('./get-state'); +var prefix = require('./prefix'); var React = require('react/addons'); var clone = require('lodash/lang/clone'); @@ -136,7 +137,8 @@ var resolveStyles = function (component, renderedElement, existingKeyMap) { !Object.keys(style).some(_isSpecialKey) ) { if (style) { - newProps.style = style; + // Still perform vendor prefixing, though. + newProps.style = prefix(style); return React.cloneElement(renderedElement, newProps, newChildren); } else if (newChildren) { return React.cloneElement(renderedElement, {}, newChildren); @@ -229,7 +231,7 @@ var resolveStyles = function (component, renderedElement, existingKeyMap) { ); } - newProps.style = newStyle; + newProps.style = prefix(newStyle); return React.cloneElement(renderedElement, newProps, newChildren); }; From c290eff1b6811fdd62ddd2f9bdf7caee5e4e5b7b Mon Sep 17 00:00:00 2001 From: Ian Obermiller Date: Wed, 22 Apr 2015 01:29:27 -0700 Subject: [PATCH 2/6] Use css-style prefixes for values --- modules/prefix.js | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/modules/prefix.js b/modules/prefix.js index bc95ca22..f9a2d904 100644 --- a/modules/prefix.js +++ b/modules/prefix.js @@ -6,18 +6,28 @@ var camelCase = require('lodash/string/camelCase'); var kebabCase = require('lodash/string/kebabCase'); +var jsCssMap = { + Webkit: '-webkit-', + Moz: '-moz-', + // IE did it wrong again ... + ms: '-ms-', + O: '-o-' +}; +var testProp = 'Transform'; + var domStyle = document.createElement('p').style; var prefixedPropertyCache = {}; var prefixedValueCache = {}; -var vendorPrefix = ''; - -['Webkit', 'Moz', 'ms', 'O'].some(function(prefix) { - if ((prefix + 'Transform') in domStyle) { - vendorPrefix = prefix; - return true; +var propertyVendorPrefix = ''; +var valueVendorPrefix = ''; + +for (var js in jsCssMap) { + if ((js + testProp) in domStyle) { + propertyVendorPrefix = js; + valueVendorPrefix = jsCssMap[js]; + break } - return false; -}); +} function _getPrefixedProperty(property) { if (prefixedPropertyCache[property]) { @@ -30,7 +40,7 @@ function _getPrefixedProperty(property) { } var newProperty = - vendorPrefix + property[0].toUpperCase() + property.slice(1); + propertyVendorPrefix + property[0].toUpperCase() + property.slice(1); if (newProperty in domStyle) { // prefixed return prefixedPropertyCache[property] = newProperty; @@ -69,7 +79,7 @@ function _getPrefixedValue(property, value) { } // Test value with vendor prefix. - value = vendorPrefix + value; + value = valueVendorPrefix + value; domStyle[property] = value; // Value is supported with vendor prefix. From b939fc4ae179183c33f75d4dc54cf1b8299145c7 Mon Sep 17 00:00:00 2001 From: Ian Obermiller Date: Thu, 23 Apr 2015 03:15:24 -0700 Subject: [PATCH 3/6] Support optional css-style prefixes --- modules/prefix.js | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/modules/prefix.js b/modules/prefix.js index f9a2d904..75503b23 100644 --- a/modules/prefix.js +++ b/modules/prefix.js @@ -18,32 +18,40 @@ var testProp = 'Transform'; var domStyle = document.createElement('p').style; var prefixedPropertyCache = {}; var prefixedValueCache = {}; -var propertyVendorPrefix = ''; -var valueVendorPrefix = ''; +var jsVendorPrefix = ''; +var cssVendorPrefix = ''; for (var js in jsCssMap) { if ((js + testProp) in domStyle) { - propertyVendorPrefix = js; - valueVendorPrefix = jsCssMap[js]; + jsVendorPrefix = js; + cssVendorPrefix = jsCssMap[js]; break } } function _getPrefixedProperty(property) { - if (prefixedPropertyCache[property]) { + if (prefixedPropertyCache.hasOwnProperty(property)) { return prefixedPropertyCache[property]; } if (property in domStyle) { // unprefixed - return prefixedPropertyCache[property] = property; + prefixedPropertyCache[property] = { + css: kebabCase(property), + js: property + }; + return prefixedPropertyCache[property]; } var newProperty = - propertyVendorPrefix + property[0].toUpperCase() + property.slice(1); + jsVendorPrefix + property[0].toUpperCase() + property.slice(1); if (newProperty in domStyle) { // prefixed - return prefixedPropertyCache[property] = newProperty; + prefixedPropertyCache[property] = { + css: cssVendorPrefix + kebabCase(property), + js: newProperty + }; + return prefixedPropertyCache[property]; } // unsupported @@ -58,7 +66,7 @@ function _getPrefixedValue(property, value) { var cacheKey = property + value; - if (prefixedValueCache[cacheKey]) { + if (prefixedValueCache.hasOwnProperty(cacheKey)) { return prefixedValueCache[cacheKey]; } @@ -79,7 +87,7 @@ function _getPrefixedValue(property, value) { } // Test value with vendor prefix. - value = valueVendorPrefix + value; + value = cssVendorPrefix + value; domStyle[property] = value; // Value is supported with vendor prefix. @@ -95,7 +103,8 @@ function _getPrefixedValue(property, value) { * Returns a new style object with vendor prefixes added to property names * and values. */ -function prefix(style) { +function prefix(style, mode /* 'css' or 'js' */) { + mode = mode || 'js'; var newStyle = {}; Object.keys(style).forEach(function(property) { var value = style[property]; @@ -107,7 +116,7 @@ function prefix(style) { return; } - var newValue = _getPrefixedValue(newProperty, value); + var newValue = _getPrefixedValue(newProperty.js, value); if (newValue === false) { // Ignore unsupported values console.warn( @@ -115,7 +124,7 @@ function prefix(style) { ); } - newStyle[newProperty] = newValue; + newStyle[newProperty[mode]] = newValue; }); return newStyle; } From 0e65ccf694f8a763f9fddd67e1654a48192bdb4e Mon Sep 17 00:00:00 2001 From: Ian Obermiller Date: Thu, 23 Apr 2015 03:51:52 -0700 Subject: [PATCH 4/6] Fix lint --- modules/prefix.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/modules/prefix.js b/modules/prefix.js index 75503b23..fb5cd048 100644 --- a/modules/prefix.js +++ b/modules/prefix.js @@ -3,7 +3,8 @@ * shenanigans. */ -var camelCase = require('lodash/string/camelCase'); +'use strict'; + var kebabCase = require('lodash/string/kebabCase'); var jsCssMap = { @@ -25,11 +26,11 @@ for (var js in jsCssMap) { if ((js + testProp) in domStyle) { jsVendorPrefix = js; cssVendorPrefix = jsCssMap[js]; - break + break; } } -function _getPrefixedProperty(property) { +var _getPrefixedProperty = function (property) { if (prefixedPropertyCache.hasOwnProperty(property)) { return prefixedPropertyCache[property]; } @@ -56,9 +57,9 @@ function _getPrefixedProperty(property) { // unsupported return prefixedPropertyCache[property] = false; -} +}; -function _getPrefixedValue(property, value) { +var _getPrefixedValue = function (property, value) { // don't test numbers or numbers with units (e.g. 10em) if (typeof value !== 'string' || !isNaN(parseInt(value, 10))) { return value; @@ -97,16 +98,15 @@ function _getPrefixedValue(property, value) { } return prefixedValueCache[cacheKey] = false; -} +}; -/** - * Returns a new style object with vendor prefixes added to property names - * and values. - */ -function prefix(style, mode /* 'css' or 'js' */) { +// Returns a new style object with vendor prefixes added to property names +// and values. +/*eslint-disable no-console */ +var prefix = function (style, mode /* 'css' or 'js' */) { mode = mode || 'js'; var newStyle = {}; - Object.keys(style).forEach(function(property) { + Object.keys(style).forEach(function (property) { var value = style[property]; var newProperty = _getPrefixedProperty(property); @@ -127,6 +127,7 @@ function prefix(style, mode /* 'css' or 'js' */) { newStyle[newProperty[mode]] = newValue; }); return newStyle; -} +}; +/*eslint-enable no-console */ module.exports = prefix; From bcb899b8f5118e937aa6ad050c37afba72bcc697 Mon Sep 17 00:00:00 2001 From: Ian Obermiller Date: Fri, 24 Apr 2015 21:14:39 -0700 Subject: [PATCH 5/6] Fix tests by including a simple mock for prefix --- modules/__mocks__/prefix.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 modules/__mocks__/prefix.js diff --git a/modules/__mocks__/prefix.js b/modules/__mocks__/prefix.js new file mode 100644 index 00000000..73e6817b --- /dev/null +++ b/modules/__mocks__/prefix.js @@ -0,0 +1,7 @@ +'use strict'; + +var prefixMock = function(style, mode) { + return style; +}; + +module.exports = prefixMock; From 33eaa1e7882fb5fa66fd6d5c5fd865818fe28ebb Mon Sep 17 00:00:00 2001 From: Ian Obermiller Date: Fri, 1 May 2015 06:27:17 -0700 Subject: [PATCH 6/6] Fix lint in prefix mock. --- modules/__mocks__/prefix.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/__mocks__/prefix.js b/modules/__mocks__/prefix.js index 73e6817b..9571c5c0 100644 --- a/modules/__mocks__/prefix.js +++ b/modules/__mocks__/prefix.js @@ -1,6 +1,6 @@ 'use strict'; -var prefixMock = function(style, mode) { +var prefixMock = function (style) { return style; };