Reworks same-selector merging to run both ways.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 25 Feb 2015 20:35:31 +0000 (20:35 +0000)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 25 Feb 2015 22:04:54 +0000 (22:04 +0000)
This way it can optimize more use cases as content may not be
movable one way but it could be other way, e.g.:

```css
a{color:red}
p{display:block}
a{display:inline-block}
```

In this case the third selector can't be moved and merged with the
first one, but it can be done the other way around.

lib/selectors/optimizers/advanced.js
test/fixtures/big-min.css
test/integration-test.js
test/selectors/optimizer-test.js

index 92078fb..ec275bf 100644 (file)
@@ -367,24 +367,42 @@ AdvancedOptimizer.prototype.mergeNonAdjacentBySelector = function (tokens) {
 
     selectorIterator:
     for (var j = positions.length - 1; j > 0; j--) {
-      var targetPosition = positions[j - 1];
-      var targetToken = tokens[targetPosition];
-      var movedPosition = positions[j];
-      var movedToken = tokens[movedPosition];
-      var movedProperties = allProperties(movedToken);
-
-      for (var k = movedPosition - 1; k > targetPosition; k--) {
-        var traversedProperties = allProperties(tokens[k]);
+      var positionOne = positions[j - 1];
+      var tokenOne = tokens[positionOne];
+      var positionTwo = positions[j];
+      var tokenTwo = tokens[positionTwo];
+
+      directionIterator:
+      for (var direction = 1; direction >= -1; direction -= 2) {
+        var topToBottom = direction == 1;
+        var from = topToBottom ? positionOne + 1 : positionTwo - 1;
+        var to = topToBottom ? positionTwo : positionOne;
+        var delta = topToBottom ? 1 : -1;
+        var moved = topToBottom ? tokenOne : tokenTwo;
+        var target = topToBottom ? tokenTwo : tokenOne;
+        var movedProperties = allProperties(moved);
+
+        while (from != to) {
+          var traversedProperties = allProperties(tokens[from]);
+          from += delta;
+
+          // traversed then moved as we move selectors towards the start
+          var reorderable = topToBottom ?
+            canReorder(movedProperties, traversedProperties) :
+            canReorder(traversedProperties, movedProperties);
+
+          if (!reorderable && !topToBottom)
+            continue selectorIterator;
+          if (!reorderable && topToBottom)
+            continue directionIterator;
+        }
 
-        // traversed then moved as we move selectors towards the start
-        if (!canReorder(traversedProperties, movedProperties))
-          continue selectorIterator;
+        var joinAt = topToBottom ? [target.body.length] : [moved.body.length];
+        var joinedBodies = topToBottom ? moved.body.concat(target.body) : target.body.concat(moved.body);
+        var newBody = this.propertyOptimizer.process(target.value, joinedBodies, joinAt, true);
+        changeBodyOf(target, newBody);
+        changeBodyOf(moved, { tokenized: [], list: [] });
       }
-
-      var joinAt = [movedToken.body.length];
-      var newBody = this.propertyOptimizer.process(targetToken.value, targetToken.body.concat(movedToken.body), joinAt, true);
-      changeBodyOf(targetToken, newBody);
-      changeBodyOf(movedToken, { tokenized: [], list: [] });
     }
   }
 };
index 1331563..90daa90 100644 (file)
@@ -12,13 +12,11 @@ article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display
 audio,canvas,video{display:inline-block}
 [hidden],audio:not([controls]){display:none}
 .tt13_capital,.tt15_capital,.tt20,.tt24,.tt28,.tt32,.tt40{display:block}
-html{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
 button,html,input,select,textarea{font-family:sans-serif}
 body,figure,form{margin:0}
 a:focus{outline:dotted thin}
 a:active,a:hover{outline:0}
 h1,h2,h3,h4,h5,h6{margin:0;font-weight:700}
-p{-webkit-margin-before:0;-webkit-margin-after:0}
 abbr[title]{border-bottom:1px dotted}
 b,strong{font-weight:700}
 .tt13_capital,.tt15_capital,.tt20,.tt24,.tt26_capital,.tt28,.tt32,.tt40{font-weight:400}
@@ -189,7 +187,7 @@ table{border-spacing:0}
 .clear{overflow:hidden;width:0;height:0}
 .clearfix:after{clear:both;content:' ';display:block;font-size:0;line-height:0;width:0;height:0}
 * html .clearfix{height:1%}
-html{font-size:62.5%}
+html{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;font-size:62.5%}
 body{font-size:1.3rem;font-size:13px;line-height:140%;color:#16212c;background:#e9edf0}
 .global{width:1000px;margin:0 auto;padding:20px 0 10px;background:#fff}
 .lmd-header{position:relative;z-index:15}
@@ -202,7 +200,7 @@ a{color:#036}
 .bg_fonce a:focus,.bg_fonce a:hover{opacity:1}
 .obf{color:#036}
 .lien_interne,.lien_interne:hover{color:#000}
-p{margin:0}
+p{-webkit-margin-before:0;-webkit-margin-after:0;margin:0}
 article,figure,section{overflow:hidden}
 section article{margin:0 0 16px}
 .img_bord,article img,figure img{border:1px solid #eef1f5;vertical-align:bottom}
@@ -257,9 +255,8 @@ section article{margin:0 0 16px}
 .bord_lrb1_gris_clair{border-left:1px solid #eef1f5;border-right:1px solid #eef1f5;border-bottom:1px solid #eef1f5}
 .bord_top1_gris{border-top:1px solid #e9edf0;padding-top:10px}
 .bord_bot1_gris{border-bottom:1px solid #e9edf0;padding-bottom:10px}
-.bord_double_gris_blanc{line-height:25px;font-size:12px}
 .bord1_gris_clair{border:1px solid #eef1f5}
-.bord_double_gris_blanc{display:inline-block;border:solid #d2d6db;border-width:1px 0}
+.bord_double_gris_blanc{line-height:25px;font-size:12px;display:inline-block;border:solid #d2d6db;border-width:1px 0}
 .bord_double_gris_blanc span{display:inline-block;border:solid #fff;border-width:1px 0}
 .bloc_abo{border-top:3px solid #ffd500}
 img[width="642"],img[width="312"]{margin-bottom:6px}
@@ -310,7 +307,6 @@ button::-moz-focus-inner,input[type=submit]::-moz-focus-inner{padding:0;border:0
 .nl span{display:inline-block;width:20px;height:20px;margin:0 0 0 5px;line-height:20px;background:url(/medias/web/img/sprites/pictos20x20.png)no-repeat}
 .nl:hover span{background-position:right -20px}
 .bt_fermer,.bt_ouvrir,.bt_ouvrir:hover,.croix_blanche,.croix_grise,.fb13x13,.fb13x13_blanc,.fb13x13_gris,.google13x13,.google13x13_blanc,.ico_annee_en_france,.lien_externe span,.linkedin13x13,.linkedin13x13_blanc,.nb_commentaires .pic,.nb_reactions .pic,.nl_blanc,.tw13x13,.tw13x13_blanc,.tw13x13_gris,.tw_bird{background:url(/medias/web/img/sprites/icos_petites.png)no-repeat;display:inline-block;text-indent:-9999px;height:13px;width:13px;cursor:pointer}
-.tw_bird{cursor:default}
 .fb13x13,.fb13x13_blanc,.fb13x13_gris,.google13x13,.google13x13_blanc,.linkedin13x13,.linkedin13x13_blanc,.tw13x13,.tw13x13_blanc,.tw13x13_gris{margin:0 2px;vertical-align:middle}
 .fb13x13,.fb13x13_gris{background-position:0 -38px}
 .fb13x13_gris{background-position:0 -94px}
@@ -326,7 +322,7 @@ button::-moz-focus-inner,input[type=submit]::-moz-focus-inner{padding:0;border:0
 .linkedin13x13{background-position:0 -80px}
 .linkedin13x13_blanc{background-position:-14px -216px}
 .linkedin13x13:hover,.linkedin13x13_blanc:hover{background-position:-14px -80px}
-.tw_bird{width:15px;height:11px;vertical-align:middle;background-position:-14px -131px}
+.tw_bird{cursor:default;width:15px;height:11px;vertical-align:middle;background-position:-14px -131px}
 .nb_reactions,span.nb_reactions{font-size:10px;font-weight:700;font-family:arial,sans-serif;color:#a2a9ae;vertical-align:5%;white-space:nowrap}
 .nb_commentaires .pic,.nb_reactions .pic{vertical-align:text-bottom;margin:0 3px 0 0;width:12px;height:11px;background-position:-13px 0}
 .lien_externe{color:#5d666d;font-size:11px}
@@ -2163,10 +2159,9 @@ a.god:hover{background:#3c3c3c;color:#fff}
 #core-liberation .block-search-results .block-content .article .object-picture,#core-liberation .block-search-results .block-content .article .object-picture img{height:116px}
 #core-liberation .block-search-results .block-content .object-picture .np{position:relative}
 #core-liberation .block-search-results .block-content .object-picture .np .p1,#core-liberation .block-search-results .block-content .object-picture .np .p2{position:absolute;width:79px;height:102px;border-style:solid;border-width:7px 4px}
-#core-liberation .block-search-results .block-content .object-picture .np a.date{position:absolute;display:block;width:80px;top:10px;padding:2px 2px 3px 4px}
 #core-liberation .block-search-results .block-content .object-picture .np .p1{z-index:2000}
 #core-liberation .block-search-results .block-content .object-picture .np .p2{z-index:1000}
-#core-liberation .block-search-results .block-content .object-picture .np a.date{z-index:500}
+#core-liberation .block-search-results .block-content .object-picture .np a.date{position:absolute;display:block;width:80px;top:10px;padding:2px 2px 3px 4px;z-index:500}
 #core-liberation .block-https-inscription{width:418px;margin:0 auto 42px}
 #core-liberation .block-https-inscription .block-content h2{margin:5px 0 10px;text-align:center;font-size:16px;font-weight:700;font-family:Verdana,sans-serif}
 #core-liberation .block-https-inscription .block-content p{margin-bottom:15px;text-align:center;font-size:14px}
@@ -2552,7 +2547,6 @@ body.access-ess #page-paywall .content .arguments .arg{float:none;margin:auto}
 .site-liberation .block-call-items .tpl-search-results .object-picture .np a.date{position:absolute;display:block;width:80px;top:10px;padding:2px 2px 3px 4px}
 .site-liberation .block-call-items .tpl-search-results .object-picture .np .p1{z-index:2000}
 .site-liberation .block-call-items .tpl-search-results .object-picture .np .p2{z-index:1000}
-.site-liberation .block-call-items .tpl-search-results .object-picture .np a.date{z-index:500}
 .site-liberation .block-call-items .tpl-no-border{border-bottom:none}
 .site-liberation .block-call-items .tpl-visual-square-left .visual{display:block;float:left;margin:3px 14px 0 0;width:84px;height:84px}
 .site-liberation .block-call-items .tpl-visual-square-left .subtitle,.site-liberation .block-call-items .tpl-visual-square-left h3,.site-liberation .block-call-items .tpl-visual-square-left h4,.site-liberation .block-call-items .tpl-visual-square-left h5{margin-left:98px}
@@ -2723,7 +2717,7 @@ body.slideshow .ad-top .megaban{background:#333}
 .site-liberation .block-call-items .tpl-search-results h4,.site-liberation .block-call-items .tpl-search-results h4 a{color:#959595}
 .site-liberation .block-call-items .tpl-search-results .object-picture .np .p1,.site-liberation .block-call-items .tpl-search-results .object-picture .np .p2{background-color:#fff;border-color:#c8c8c8}
 #core-liberation .block-comments .block-content .comment_outer,#core-liberation .block-item-read-more{border-color:#ddd}
-.site-liberation .block-call-items .tpl-search-results .object-picture .np a.date{background-color:#c8c8c8}
+.site-liberation .block-call-items .tpl-search-results .object-picture .np a.date{z-index:500;background-color:#c8c8c8}
 #core-liberation .block-item .object-picture .legende{color:#838383}
 .site-liberation .block-item .object-content a:hover{color:#e20000}
 #core-liberation .block-item-locked{border-top-color:#c1b0bb;border-bottom-color:#c1b0bb;background:#fff;background:-moz-linear-gradient(top,#dbdad6 0,#fff 2%,#fff 98%,#e1e0de 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dbdad6),color-stop(2%,#fff),color-stop(98%,#fff),color-stop(100%,#e1e0de));background:-o-linear-gradient(top,#dbdad6 0,#fff 2%,#fff 98%,#e1e0de 100%)}
index 6d8299a..ed0f2be 100644 (file)
@@ -1737,7 +1737,7 @@ title']{display:block}",
     'when overriden with a browser specific selector': 'a{color:red}::-webkit-scrollbar,a{color:#fff}',
     'two same selectors over a block': [
       '.one{color:red}@media print{.two{display:block}}.one{display:none}',
-      '.one{color:red}@media print{.two{display:block}}.one{display:none}'
+      '@media print{.two{display:block}}.one{color:red;display:none}'
     ],
     'two same bodies over a block': [
       '.one{color:red}@media print{.two{display:block}}.three{color:red}',
@@ -1745,18 +1745,17 @@ title']{display:block}",
     ]
   }),
   'same non-adjacent selectors': cssContext({
-    'with different properties': 'a{color:red;display:block}.one{margin:5px}a{margin:2px}',
     'with one redefined property': [
       'a{color:red;display:block}.one{color:red}a{color:#fff;margin:2px}',
-      'a{display:block}.one{color:red}a{color:#fff;margin:2px}'
+      '.one{color:red}a{display:block;color:#fff;margin:2px}'
     ],
     'with intentionally redefined properties on joins': [
       'a{display:inline-block;display:-moz-inline-box;color:red}.one{margin:12px}a{color:#fff;margin:2px}',
-      'a{display:inline-block;display:-moz-inline-box}.one{margin:12px}a{color:#fff;margin:2px}'
+      '.one{margin:12px}a{display:inline-block;display:-moz-inline-box;color:#fff;margin:2px}'
     ],
     'with intentionally redefined properties on multiple joins': [
       'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{margin:10px}a{margin:0}',
-      '.one{font-size:12px}a{color:#fff}.two{margin:10px}a{margin:0}'
+      '.one{font-size:12px}.two{margin:10px}a{color:#fff;margin:0}'
     ],
     'with all redefined properties': [
       'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
@@ -1764,7 +1763,7 @@ title']{display:block}",
     ],
     'many with all redefined properties': [
       'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
-      'a{padding:10px}.zero{color:transparent}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
+      '.zero{color:transparent}.one{font-size:12px}a{padding:10px;color:#fff;display:inline-block;margin:2px}'
     ],
     'when overriden by an empty selector': [
       'a{padding:10px}.one{color:red}a{}',
@@ -1787,7 +1786,10 @@ title']{display:block}",
       '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}',
       '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}'
     ],
-    'when undefined is used as a value': '.one{text-shadow:undefined}p{font-size:14px}.one{font-size:12px}',
+    'when undefined is used as a value': [
+      '.one{text-shadow:undefined}p{font-size:14px}.one{font-size:12px}',
+      'p{font-size:14px}.one{text-shadow:undefined;font-size:12px}'
+    ],
     'when undefined is used as a value with reduction': [
       '.one{text-shadow:undefined}p{color:red}.one{font-size:12px;text-shadow:none}',
       'p{color:red}.one{font-size:12px;text-shadow:none}'
@@ -1797,14 +1799,17 @@ title']{display:block}",
       'a,::-moz-selection{color:red}p{display:block}a,::-moz-selection{color:#fff}',
       'p{display:block}::-moz-selection,a{color:#fff}'
     ],
-    'with full property comparison': '.one{height:7rem}.two{color:#fff}.one{line-height:7rem;color:red}',
+    'with full property comparison': [
+      '.one{height:7rem}.two{color:#fff}.one{line-height:7rem;color:red}',
+      '.two{color:#fff}.one{height:7rem;line-height:7rem;color:red}'
+    ],
     'with two intermediate, non-overriding selectors': [
       '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}',
       '.one{color:red;margin:0;font-size:12px}.two{color:#fff}'
     ],
     'with two intermediate, overriding more specific selectors': [
       '.one{color:red;margin:0}.two{font:12px serif}.one{font-size:12px}',
-      '.one{color:red;margin:0}.two{font:12px serif}.one{font-size:12px}'
+      '.two{font:12px serif}.one{color:red;margin:0;font-size:12px}'
     ],
     'with granular selectors from the same shorthand': [
       '.one{color:red;margin:0}.two{font-weight:700}.one{font-size:12px}',
index d735476..22b6e8b 100644 (file)
@@ -107,6 +107,10 @@ vows.describe(SelectorsOptimizer)
         '.one,.two,.three{color:red;display:block}div{margin:0}.four,.five,.six{color:red;display:block}',
         '.five,.four,.one,.six,.three,.two{color:red;display:block}div{margin:0}'
       ],
+      'down until changed': [
+        '.one{padding:0}.two{margin:0}.one{margin-bottom:3px}',
+        '.two{margin:0}.one{padding:0;margin-bottom:3px}'
+      ],
       'over shorthands': [
         'div{margin-top:0}.one{margin:0}.two{display:block;margin-top:0}',
         '.two,div{margin-top:0}.one{margin:0}.two{display:block}'
@@ -241,7 +245,7 @@ vows.describe(SelectorsOptimizer)
       ],
       'non-adjacent': [
         'a{color:red;display:block}.one{margin:12px}a{color:#fff;margin:2px}',
-        'a{display:block}.one{margin:12px}a{color:#fff;margin:2px}'
+        '.one{margin:12px}a{display:block;color:#fff;margin:2px}'
       ],
       'non-adjacent with multi selectors': [
         'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}',