Fixes #508 - removing duplicate media queries.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 13 Apr 2015 20:31:09 +0000 (21:31 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 13 Apr 2015 20:32:03 +0000 (21:32 +0100)
It's same as with duplicated properties - they can be removed
no matter what.

History.md
lib/selectors/optimizers/advanced.js
lib/stringifier/one-time.js
test/media-queries-test.js

index 7c0fffa..6a06dc8 100644 (file)
@@ -15,6 +15,7 @@
 * Fixed issue [#490](https://github.com/jakubpawlowicz/clean-css/issues/490) - vendor prefixed multivalue `background`.
 * Fixed issue [#500](https://github.com/jakubpawlowicz/clean-css/issues/500) - merging duplicate adjacent properties.
 * Fixed issue [#507](https://github.com/jakubpawlowicz/clean-css/issues/507) - merging longhands into many shorthands.
+* Fixed issue [#508](https://github.com/jakubpawlowicz/clean-css/issues/508) - removing duplicate media queries.
 
 [3.1.9 / 2015-04-04](https://github.com/jakubpawlowicz/clean-css/compare/v3.1.8...v3.1.9)
 ==================
index 1df8946..fb3d0f5 100644 (file)
@@ -4,6 +4,7 @@ var CleanUp = require('./clean-up');
 var extractProperties = require('../extractor');
 var canReorder = require('../reorderable').canReorder;
 var canReorderSingle = require('../reorderable').canReorderSingle;
+var stringifyAll = require('../../stringifier/one-time').all;
 var stringifyBody = require('../../stringifier/one-time').body;
 var stringifySelectors = require('../../stringifier/one-time').selectors;
 
@@ -617,6 +618,24 @@ AdvancedOptimizer.prototype.restructure = function (tokens) {
   }
 };
 
+AdvancedOptimizer.prototype.removeDuplicateMediaQueries = function (tokens) {
+  var candidates = {};
+
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+    if (token[0] != 'block')
+      continue;
+
+    var key = token[1][0] + '%' + stringifyAll(token[2]);
+    var candidate = candidates[key];
+
+    if (candidate)
+      candidate[2] = [];
+
+    candidates[key] = token;
+  }
+};
+
 AdvancedOptimizer.prototype.mergeMediaQueries = function (tokens) {
   var candidates = {};
   var reduced = [];
@@ -724,6 +743,7 @@ AdvancedOptimizer.prototype.optimize = function (tokens) {
     }
 
     if (self.options.mediaMerging) {
+      self.removeDuplicateMediaQueries(tokens);
       var reduced = self.mergeMediaQueries(tokens);
       for (var i = reduced.length - 1; i >= 0; i--) {
         _optimize(reduced[i][2]);
index f70551d..4a65c7f 100644 (file)
@@ -11,6 +11,12 @@ function context() {
   };
 }
 
+function all(tokens) {
+  var fakeContext = context();
+  helpers.all(tokens, fakeContext);
+  return fakeContext.output.join('');
+}
+
 function body(tokens) {
   var fakeContext = context();
   helpers.body(tokens, fakeContext);
@@ -36,6 +42,7 @@ function value(tokens, position) {
 }
 
 module.exports = {
+  all: all,
   body: body,
   property: property,
   selectors: selectors,
index 7886e38..3a54c9a 100644 (file)
@@ -109,6 +109,22 @@ vows.describe('media queries')
       'get merged': function(minified) {
         assert.equal(minified.styles, '@media (min-width:1024px){.one{color:red}}@media screen{a{color:red}div{display:block}}');
       }
+    },
+    'duplicated but non-mergeable': {
+      'topic': function () {
+        return new CleanCSS().minify('@media screen{a{color:red}}.one{color:#000}@media screen{a{color:red}}');
+      },
+      'get merged': function(minified) {
+        assert.equal(minified.styles, '.one{color:#000}@media screen{a{color:red}}');
+      }
+    },
+    'many duplicated but non-mergeable': {
+      'topic': function () {
+        return new CleanCSS().minify('@media print{a{color:#fff}}@media screen{a{color:red}}.one{color:#000}@media screen{a{color:red}}@media print{a{display:block}}@media print{a{color:#fff}}');
+      },
+      'get merged': function(minified) {
+        assert.equal(minified.styles, '.one{color:#000}@media screen{a{color:red}}@media print{a{display:block;color:#fff}}');
+      }
     }
   })
   .addBatch({