| var canReorder = require('./reorderable').canReorder; |
| var canReorderSingle = require('./reorderable').canReorderSingle; |
| var extractProperties = require('./extract-properties'); |
| var rulesOverlap = require('./rules-overlap'); |
| |
| var serializeRules = require('../../writer/one-time').rules; |
| var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel; |
| var Token = require('../../tokenizer/token'); |
| |
| function mergeMediaQueries(tokens, context) { |
| var mergeSemantically = context.options.level[OptimizationLevel.Two].mergeSemantically; |
| var specificityCache = context.cache.specificity; |
| var candidates = {}; |
| var reduced = []; |
| |
| for (var i = tokens.length - 1; i >= 0; i--) { |
| var token = tokens[i]; |
| if (token[0] != Token.NESTED_BLOCK) { |
| continue; |
| } |
| |
| var key = serializeRules(token[1]); |
| var candidate = candidates[key]; |
| if (!candidate) { |
| candidate = []; |
| candidates[key] = candidate; |
| } |
| |
| candidate.push(i); |
| } |
| |
| for (var name in candidates) { |
| var positions = candidates[name]; |
| |
| positionLoop: |
| for (var j = positions.length - 1; j > 0; j--) { |
| var positionOne = positions[j]; |
| var tokenOne = tokens[positionOne]; |
| var positionTwo = positions[j - 1]; |
| var tokenTwo = tokens[positionTwo]; |
| |
| directionLoop: |
| 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 source = topToBottom ? tokenOne : tokenTwo; |
| var target = topToBottom ? tokenTwo : tokenOne; |
| var movedProperties = extractProperties(source); |
| |
| while (from != to) { |
| var traversedProperties = extractProperties(tokens[from]); |
| from += delta; |
| |
| if (mergeSemantically && allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache)) { |
| continue; |
| } |
| |
| if (!canReorder(movedProperties, traversedProperties, specificityCache)) |
| continue directionLoop; |
| } |
| |
| target[2] = topToBottom ? |
| source[2].concat(target[2]) : |
| target[2].concat(source[2]); |
| source[2] = []; |
| |
| reduced.push(target); |
| continue positionLoop; |
| } |
| } |
| } |
| |
| return reduced; |
| } |
| |
| function allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache) { |
| var movedProperty; |
| var movedRule; |
| var traversedProperty; |
| var traversedRule; |
| var i, l; |
| var j, m; |
| |
| for (i = 0, l = movedProperties.length; i < l; i++) { |
| movedProperty = movedProperties[i]; |
| movedRule = movedProperty[5]; |
| |
| for (j = 0, m = traversedProperties.length; j < m; j++) { |
| traversedProperty = traversedProperties[j]; |
| traversedRule = traversedProperty[5]; |
| |
| if (rulesOverlap(movedRule, traversedRule, true) && !canReorderSingle(movedProperty, traversedProperty, specificityCache)) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| module.exports = mergeMediaQueries; |