From 13237b49488bd781e9b9100732b07d049cb228e9 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Tue, 25 Feb 2014 20:25:17 +0000 Subject: [PATCH] Fixes #245 - incorrect handling of backslash IE hack. Backslash hack '\9' (which is accepted in IE[678]) should be handled correctly if ie8 or ie7 compatibility is requested. --- History.md | 5 +++++ lib/clean.js | 3 ++- lib/properties/optimizer.js | 19 ++++++++++++++--- lib/selectors/optimizer.js | 2 +- test/unit-test.js | 41 +++++++++++++++++++++++++++++++++++-- 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/History.md b/History.md index 93078bad..5b448658 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,11 @@ * Adds a better non-adjacent optimizer compatible with the upcoming new property optimizer. +[2.1.2 / 2014-xx-xx (UNRELEASED)](https://github.com/GoalSmashers/clean-css/compare/v2.1.1...v2.1.2) +================== + +* Fixed issue [#245](https://github.com/GoalSmashers/clean-css/issues/245) - incorrect handling of backslash IE hack. + [2.1.1 / 2014-02-18](https://github.com/GoalSmashers/clean-css/compare/v2.1.0...v2.1.1) ================== diff --git a/lib/clean.js b/lib/clean.js index 24b84c3c..3f53203e 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -342,7 +342,8 @@ var minify = function(data, callback) { data = new SelectorsOptimizer(data, context, { keepBreaks: options.keepBreaks, lineBreak: lineBreak, - selectorsMergeMode: mergeMode + selectorsMergeMode: mergeMode, + compatibility: options.compatibility }).process(); }); } diff --git a/lib/properties/optimizer.js b/lib/properties/optimizer.js index 527acc76..2b5698d5 100644 --- a/lib/properties/optimizer.js +++ b/lib/properties/optimizer.js @@ -1,4 +1,4 @@ -module.exports = function Optimizer() { +module.exports = function Optimizer(compatibility) { var overridable = { 'animation-delay': ['animation'], 'animation-direction': ['animation'], @@ -96,6 +96,8 @@ module.exports = function Optimizer() { '-webkit-transition-timing-function': ['-webkit-transition'] }; + var IE_BACKSLASH_HACK = '\\9'; + var overrides = {}; for (var granular in overridable) { for (var i = 0; i < overridable[granular].length; i++) { @@ -113,7 +115,7 @@ module.exports = function Optimizer() { var tokens = body.split(';'); var keyValues = []; - if (tokens.length < 2) + if (tokens.length === 0 || (tokens.length == 1 && tokens[0].indexOf(IE_BACKSLASH_HACK) == -1)) return; for (var i = 0, l = tokens.length; i < l; i++) { @@ -125,7 +127,8 @@ module.exports = function Optimizer() { keyValues.push([ token.substring(0, firstColon), token.substring(firstColon + 1), - token.indexOf('!important') > -1 + token.indexOf('!important') > -1, + token.indexOf(IE_BACKSLASH_HACK, firstColon + 1) > 0 ]); } @@ -164,11 +167,15 @@ module.exports = function Optimizer() { var token = tokens[i]; var property = token[0]; var isImportant = token[2]; + var isIEHack = token[3]; var _property = (property == '-ms-filter' || property == 'filter') ? (lastProperty == 'background' || lastProperty == 'background-image' ? lastProperty : property) : property; var toOverridePosition = 0; + if (!compatibility && isIEHack) + continue; + // comment is necessary - we assume that if two properties are one after another // then it is intentional way of redefining property which may not be widely supported // e.g. a{display:inline-block;display:-moz-inline-box} @@ -180,9 +187,15 @@ module.exports = function Optimizer() { if (toOverridePosition == -1) break; + var lastToken = merged[toOverridePosition]; + var wasIEHack = lastToken[3]; + if (merged[toOverridePosition][2] && !isImportant) continue tokensLoop; + if (compatibility && !wasIEHack && isIEHack) + break; + merged.splice(toOverridePosition, 1); properties.splice(toOverridePosition, 1); } diff --git a/lib/selectors/optimizer.js b/lib/selectors/optimizer.js index 0b6e6cef..ce50cc56 100644 --- a/lib/selectors/optimizer.js +++ b/lib/selectors/optimizer.js @@ -10,7 +10,7 @@ module.exports = function Optimizer(data, context, options) { var minificationsMade = []; - var propertyOptimizer = new PropertyOptimizer(); + var propertyOptimizer = new PropertyOptimizer(options.compatibility); var cleanUpSelector = function(selectors) { if (selectors.indexOf(',') == -1) diff --git a/test/unit-test.js b/test/unit-test.js index c238eb35..d48a7237 100644 --- a/test/unit-test.js +++ b/test/unit-test.js @@ -365,8 +365,8 @@ vows.describe('clean-units').addBatch({ ], 'border\'s none to none': 'a{border:none}p{border-top:none}', 'background:transparent to zero': [ - 'a{background:transparent}p{background transparent url(logo.png)}', - 'a{background:0 0}p{background transparent url(logo.png)}' + 'a{background:transparent}p{background:transparent url(logo.png)}', + 'a{background:0 0}p{background:transparent url(logo.png)}' ], 'outline:none to outline:0': [ 'a{outline:none}', @@ -897,6 +897,43 @@ path")}', "a{font:12px/16px Helvetica-Regular,Arial-Bold}" ] }), + 'IE hacks': cssContext({ + 'star': 'a{*color:#fff}', + 'unserscore': 'a{_color:#fff}', + 'backslash': 'a{color:#fff\\9}', + 'overriding by a star': 'a{color:red;display:block;*color:#fff}', + 'overriding by a unserscore': 'a{color:red;display:block;_color:#fff}', + 'overriding by a backslash': 'a{color:red;display:block;color:#fff\\9}', + 'overriding !important by a star': 'a{color:red!important;display:block;*color:#fff}', + 'overriding !important by a unserscore': 'a{color:red!important;display:block;_color:#fff}', + 'overriding !important by a backslash': [ + 'a{color:red!important;display:block;color:#fff\\9}', + 'a{color:red!important;display:block}', + ], + 'overriding a star': [ + 'a{*color:red;display:block;*color:#fff}', + 'a{display:block;*color:#fff}' + ], + 'overriding a unserscore': [ + 'a{_color:red;display:block;_color:#fff}', + 'a{display:block;_color:#fff}' + ], + 'overriding a backslash': [ + 'a{color:red\\9;display:block;color:#fff\\9}', + 'a{display:block;color:#fff\\9}' + ], + 'overriding a star by a non-ajacent selector': 'a{color:red}.one{display:block}a{*color:#fff}', + 'overriding a unserscore by a non-ajacent selector': 'a{color:red}.one{display:block}a{_color:#fff}', + 'overriding a backslash by a non-ajacent selector': 'a{color:red}.one{display:block}a{color:#fff\\9}' + }, { compatibility: 'ie8' }), + 'IE hacks without IE compatibility': cssContext({ + 'star': 'a{*color:#fff}', // See #246 + 'unserscore': 'a{_color:#fff}', // See #246 + 'backslash': [ + 'a{color:#fff\\9}', + '' + ] + }), 'animations': cssContext({ 'shorten': [ '@keyframes test\n{ from\n { width:100px; }\n to { width:200px; }\n}', -- 2.34.1