Improves property overriding & redefining algorithm.
authorGoalSmashers <jakub@goalsmashers.com>
Sat, 2 Nov 2013 20:12:50 +0000 (21:12 +0100)
committerGoalSmashers <jakub@goalsmashers.com>
Sun, 3 Nov 2013 08:49:23 +0000 (09:49 +0100)
* Handles redefining overridden properties.
* Treats -ms-filter/filter as a background / background-image property.

lib/properties/optimizer.js
lib/selectors/optimizer.js
test/data/big-min.css
test/unit-test.js

index 10e67de..6106f37 100644 (file)
@@ -156,40 +156,50 @@ module.exports = function Optimizer() {
       return allowAdjacent.indexOf(position) > -1;
     };
 
+    tokensLoop:
     for (var i = 0, l = tokens.length; i < l; i++) {
       var token = tokens[i];
       var property = token[0];
       var isImportant = token[2];
-      var alreadyOnPosition = properties.indexOf(property);
-
-      if (alreadyOnPosition > -1 && merged[alreadyOnPosition][2] && !isImportant)
-        continue;
+      var _property = (property == '-ms-filter' || property == 'filter') ?
+        (lastProperty == 'background' || lastProperty == 'background-image' ? lastProperty : property) :
+        property;
+      var toOverridePosition = 0;
 
       // 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}
-      // however if `allowAdjacent` is set then the rule does not apply
-      // (e.g merging two adjacent selectors)
-      if (alreadyOnPosition > -1 && (lastProperty != property || mergeablePosition(i))) {
-        merged.splice(alreadyOnPosition, 1);
-        properties.splice(alreadyOnPosition, 1);
+      // however if `mergeablePosition` yields true then the rule does not apply
+      // (e.g merging two adjacent selectors: `a{display:block}a{display:block}`)
+      if (_property != lastProperty || mergeablePosition(i)) {
+        while (true) {
+          toOverridePosition = properties.indexOf(_property, toOverridePosition);
+          if (toOverridePosition == -1)
+            break;
+
+          if (merged[toOverridePosition][2] && !isImportant)
+            continue tokensLoop;
+
+          merged.splice(toOverridePosition, 1);
+          properties.splice(toOverridePosition, 1);
+        }
       }
 
       merged.push(token);
-      properties.push(property);
+      properties.push(_property);
 
       // certain properties (see values of `overridable`) should trigger removal of
       // more granular properties (see keys of `overridable`)
-      if (rescanTrigger[property])
-        removeOverridenBy(property, isImportant);
+      if (rescanTrigger[_property])
+        removeOverridenBy(_property, isImportant);
 
       // add rescan triggers - if certain property appears later in the list a rescan needs
       // to be triggered, e.g 'border-top' triggers a rescan after 'border-top-width' and
       // 'border-top-color' as they can be removed
-      for (var j = 0, list = overridable[property] || [], m = list.length; j < m; j++)
+      for (var j = 0, list = overridable[_property] || [], m = list.length; j < m; j++)
         rescanTrigger[list[j]] = true;
 
-      lastProperty = property;
+      lastProperty = _property;
     }
 
     return merged;
index b2be39e..2d406d7 100644 (file)
@@ -65,7 +65,8 @@ module.exports = function Optimizer(data, options) {
         continue;
 
       if (token.selector == lastToken.selector) {
-        lastToken.body = propertyOptimizer.process(lastToken.body + ';' + token.body, true);
+        var joinAt = [lastToken.body.split(';').length];
+        lastToken.body = propertyOptimizer.process(lastToken.body + ';' + token.body, joinAt);
         forRemoval.push(i);
       } else if (token.body == lastToken.body && !isSpecial(token.selector) && !isSpecial(lastToken.selector)) {
         lastToken.selector = cleanUpSelector(lastToken.selector + ',' + token.selector);
index 61b680b..70d40ef 100644 (file)
@@ -745,7 +745,7 @@ img[height="97"]+.ico29x29{bottom:6%;left:3.5%}
 .portfolio_appel_revolutionnaire .elt.shown .portfolio_data_container{-ms-filter:"alpha(Opacity=80)";opacity:.8}
 .portfolio_appel_revolutionnaire .portfolio_data_container .credits{opacity:.5;padding-left:4px}
 .portfolio_appel_revolutionnaire .carrousel .elt{width:644px;height:322px}
-.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant{position:absolute;top:0;left:0;width:165px;height:322px;-ms-filter:"alpha(Opacity=60)";background:rgba(0,0,0,.6)}
+.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant{position:absolute;top:0;left:0;width:165px;height:322px;background:#000;-ms-filter:"alpha(Opacity=60)";background:rgba(0,0,0,.6)}
 .portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent:hover,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant:hover{cursor:pointer}
 .portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .precedent span,.portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant span{display:block;margin:111px 0 0;text-indent:0;font-size:72px;width:40px;height:100px;line-height:95px;text-align:center;background:#fff;background:-moz-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:-webkit-gradient(linear,left center,right center,color-stop(0%,#eee),color-stop(50%,#fff),color-stop(100%,#fff));background:-webkit-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:-o-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:-ms-linear-gradient(left,#eee 0,#fff 50%,#fff 100%);background:linear-gradient(left,#eee 0,#fff 50%,#fff 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);border:solid #ddd;border-width:0 0 0 1px;box-shadow:0 0 1px 1px #000;-ms-filter:"alpha(Opacity=20)";opacity:.2;-webkit-transition:opacity 1s;-moz-transition:opacity 1s;-o-transition:opacity 1s;transition:opacity 1s}
 .portfolio_appel_revolutionnaire.conteneur_carrousel .navigation .suivant span{border-width:0 1px 0 0;margin:111px 0 0 124px;background:-moz-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:-webkit-gradient(linear,left center,right center,color-stop(0%,#fff),color-stop(55%,#fff),color-stop(100%,#eee));background:-webkit-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:-o-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:-ms-linear-gradient(left,#fff 0,#fff 55%,#eee 100%);background:linear-gradient(left,#fff 0,#fff 55%,#eee 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}
index 96131ce..e97de43 100644 (file)
@@ -1152,7 +1152,19 @@ title']{display:block}",
     'of many properties in one declaration': [
       'a{display:inline-block;color:red;font-weight:bolder;font-weight:700;display:block!important;color:#fff}',
       'a{font-weight:bolder;font-weight:700;display:block!important;color:#fff}'
-    ]
+    ],
+    'both redefined and overridden': [
+      'p{display:block;display:-moz-inline-box;color:red;display:table-cell}',
+      'p{color:red;display:table-cell}'
+    ],
+    'background redefined with merging': [
+      '.one{display:block}.one{background:#fff;background:-webkit-gradient();background:-moz-linear-gradient();filter:progid:DXImageTransform}',
+      '.one{display:block;background:#fff;background:-webkit-gradient();background:-moz-linear-gradient();filter:progid:DXImageTransform}'
+    ],
+    'filter treated as background': 'p{background:-moz-linear-gradient();background:-webkit-linear-gradient();filter:"progid:DXImageTransform";background:linear-gradient()}',
+    'filter treated as background-image': 'p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();filter:"progid:DXImageTransform";background-image:linear-gradient()}',
+    '-ms-filter treated as background': 'p{background:-moz-linear-gradient();background:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background:linear-gradient()}',
+    '-ms-filter treated as background-image': 'p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background-image:linear-gradient()}'
   }),
   'same selectors': cssContext({
     'of two non-adjacent selectors': '.one{color:red}.two{color:#00f}.one{font-weight:700}',