Fixes #245 - incorrect handling of backslash IE hack.
authorJakub Pawlowicz <jakub@goalsmashers.com>
Tue, 25 Feb 2014 20:25:17 +0000 (20:25 +0000)
committerJakub Pawlowicz <jakub@goalsmashers.com>
Tue, 25 Feb 2014 21:09:00 +0000 (21:09 +0000)
Backslash hack '\9' (which is accepted in IE[678]) should be handled correctly
if ie8 or ie7 compatibility is requested.

History.md
lib/clean.js
lib/properties/optimizer.js
lib/selectors/optimizer.js
test/unit-test.js

index 93078ba..5b44865 100644 (file)
@@ -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)
 ==================
 
index 24b84c3..3f53203 100644 (file)
@@ -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();
     });
   }
index 527acc7..2b5698d 100644 (file)
@@ -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);
         }
index 0b6e6ce..ce50cc5 100644 (file)
@@ -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)
index c238eb3..d48a723 100644 (file)
@@ -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}',