var optimizeProperties = require('../properties/optimizer');
-var extractProperties = require('./extractor');
-var canReorder = require('./reorderable').canReorder;
-
var removeDuplicates = require('./remove-duplicates');
var mergeAdjacent = require('./merge-adjacent');
var reduceNonAdjacent = require('./reduce-non-adjacent');
var mergeNonAdjacentByBody = require('./merge-non-adjacent-by-body');
var restructure = require('./restructure');
var removeDuplicateMediaQueries = require('./remove-duplicate-media-queries');
+var mergeMediaQueries = require('./merge-media-queries');
function AdvancedOptimizer(options, context) {
this.options = options;
this.validator = context.validator;
}
-AdvancedOptimizer.prototype.mergeMediaQueries = function (tokens) {
- var candidates = {};
- var reduced = [];
-
- for (var i = tokens.length - 1; i >= 0; i--) {
- var token = tokens[i];
- if (token[0] != 'block')
- continue;
-
- var candidate = candidates[token[1][0]];
- if (!candidate) {
- candidate = [];
- candidates[token[1][0]] = candidate;
- }
-
- candidate.push(i);
- }
-
- for (var name in candidates) {
- var positions = candidates[name];
-
- positionLoop:
- for (var j = positions.length - 1; j > 0; j--) {
- var source = tokens[positions[j]];
- var target = tokens[positions[j - 1]];
- var movedProperties = extractProperties(source);
-
- for (var k = positions[j] + 1; k < positions[j - 1]; k++) {
- var traversedProperties = extractProperties(tokens[k]);
-
- // moved then traversed as we move @media towards the end
- if (!canReorder(movedProperties, traversedProperties))
- continue positionLoop;
- }
-
- target[2] = source[2].concat(target[2]);
- source[2] = [];
-
- reduced.push(target);
- }
- }
-
- return reduced;
-};
-
AdvancedOptimizer.prototype.removeEmpty = function (tokens) {
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (self.options.mediaMerging) {
removeDuplicateMediaQueries(tokens);
- var reduced = self.mergeMediaQueries(tokens);
+ var reduced = mergeMediaQueries(tokens);
for (var i = reduced.length - 1; i >= 0; i--) {
_optimize(reduced[i][2]);
}
--- /dev/null
+var canReorder = require('./reorderable').canReorder;
+var extractProperties = require('./extractor');
+
+function mergeMediaQueries(tokens) {
+ var candidates = {};
+ var reduced = [];
+
+ for (var i = tokens.length - 1; i >= 0; i--) {
+ var token = tokens[i];
+ if (token[0] != 'block')
+ continue;
+
+ var candidate = candidates[token[1][0]];
+ if (!candidate) {
+ candidate = [];
+ candidates[token[1][0]] = candidate;
+ }
+
+ candidate.push(i);
+ }
+
+ for (var name in candidates) {
+ var positions = candidates[name];
+
+ positionLoop:
+ for (var j = positions.length - 1; j > 0; j--) {
+ var source = tokens[positions[j]];
+ var target = tokens[positions[j - 1]];
+ var movedProperties = extractProperties(source);
+
+ for (var k = positions[j] + 1; k < positions[j - 1]; k++) {
+ var traversedProperties = extractProperties(tokens[k]);
+
+ // moved then traversed as we move @media towards the end
+ if (!canReorder(movedProperties, traversedProperties))
+ continue positionLoop;
+ }
+
+ target[2] = source[2].concat(target[2]);
+ source[2] = [];
+
+ reduced.push(target);
+ }
+ }
+
+ return reduced;
+}
+
+module.exports = mergeMediaQueries;
--- /dev/null
+var vows = require('vows');
+var optimizerContext = require('../test-helper').optimizerContext;
+
+vows.describe('merge media queries')
+ .addBatch(
+ optimizerContext('different ones', {
+ 'different ones': [
+ '@media screen{a{color:red}}@media print{div{display:block}}',
+ '@media screen{a{color:red}}@media print{div{display:block}}'
+ ],
+ 'other than @media': [
+ '@font-face{font-family:A}@font-face{font-family:B}',
+ '@font-face{font-family:A}@font-face{font-family:B}'
+ ],
+ 'with empty selector': [
+ '@media screen{a{color:red}div{}}',
+ '@media screen{a{color:red}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('adjacent', {
+ 'same two adjacent': [
+ '@media screen{a{color:red}}@media screen{div{display:block}}',
+ '@media screen{a{color:red}div{display:block}}'
+ ],
+ 'same three adjacent': [
+ '@media screen{a{color:red}}@media screen{div{display:block}}@media screen{body{width:100%}}',
+ '@media screen{a{color:red}div{display:block}body{width:100%}}'
+ ],
+ 'same two with selectors in between': [
+ '@media screen{a{color:red}}body{width:100%}.one{height:100px}@media screen{div{display:block}}',
+ 'body{width:100%}.one{height:100px}@media screen{a{color:red}div{display:block}}'
+ ],
+ 'same two with other @media in between': [
+ '@media screen{a{color:red}}@media (min-width:1024px){body{width:100%}}@media screen{div{display:block}}',
+ '@media (min-width:1024px){body{width:100%}}@media screen{a{color:red}div{display:block}}'
+ ],
+ 'same two with breaking properties in between': [
+ '@media screen{a{color:red}}.one{color:#00f}@media screen{div{display:block}}',
+ '@media screen{a{color:red}}.one{color:#00f}@media screen{div{display:block}}'
+ ],
+ 'same two with breaking @media in between': [
+ '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f}}@media screen{div{display:block}}',
+ '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f}}@media screen{div{display:block}}'
+ ],
+ 'same two with breaking nested @media in between': [
+ '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f}}}@media screen{div{display:block}}',
+ '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f}}}@media screen{div{display:block}}'
+ ],
+ 'intermixed': [
+ '@media screen{a{color:red}}@media (min-width:1024px){p{width:100%}}@media screen{div{display:block}}@media (min-width:1024px){body{height:100%}}',
+ '@media screen{a{color:red}div{display:block}}@media (min-width:1024px){p{width:100%}body{height:100%}}'
+ ],
+ 'same two with overriding shorthand in between': [
+ '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:12px Helvetica}}@media screen{div{display:block}}',
+ '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:12px Helvetica}}@media screen{div{display:block}}'
+ ],
+ 'same two with different component property in between': [
+ '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font-weight:700}}@media screen{div{display:block}}',
+ '@media (min-width:1024px){.one{font-weight:700}}@media screen{a{font-size:10px}div{display:block}}'
+ ],
+ 'same two with same values as moved in between': [
+ '@media screen{a{color:red}}@media (min-width:1024px){.one{color:red}}@media screen{div{display:block}}',
+ '@media (min-width:1024px){.one{color:red}}@media screen{a{color:red}div{display:block}}'
+ ],
+ 'further optimizations': [
+ '@media screen{a{color:red}}@media screen{a{display:block}}',
+ '@media screen{a{color:red;display:block}}'
+ ],
+ 'with comments': [
+ '@media screen{a{color:red}}/*! a comment */@media screen{a{display:block}}',
+ '/*! a comment */@media screen{a{color:red;display:block}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('advanced off', {
+ 'keeps content same': [
+ '@media screen{a{color:red}}@media screen{a{display:block}}',
+ '@media screen{a{color:red}}@media screen{a{display:block}}'
+ ]
+ }, { advanced: false })
+ )
+ .addBatch(
+ optimizerContext('media merging off', {
+ 'keeps content same': [
+ '@media screen{a{color:red}}@media screen{a{display:block}}',
+ '@media screen{a{color:red}}@media screen{a{display:block}}'
+ ]
+ }, { mediaMerging: false })
+ )
+ .export(module);