From 7c6d6f026c239a696831149e53bd8b09d2af4965 Mon Sep 17 00:00:00 2001 From: GoalSmashers Date: Sat, 2 Nov 2013 21:12:50 +0100 Subject: [PATCH] Improves property overriding & redefining algorithm. * Handles redefining overridden properties. * Treats -ms-filter/filter as a background / background-image property. --- lib/properties/optimizer.js | 38 +++++++++++++++++++++++-------------- lib/selectors/optimizer.js | 3 ++- test/data/big-min.css | 2 +- test/unit-test.js | 14 +++++++++++++- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/properties/optimizer.js b/lib/properties/optimizer.js index 10e67de8..6106f379 100644 --- a/lib/properties/optimizer.js +++ b/lib/properties/optimizer.js @@ -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; diff --git a/lib/selectors/optimizer.js b/lib/selectors/optimizer.js index b2be39ed..2d406d70 100644 --- a/lib/selectors/optimizer.js +++ b/lib/selectors/optimizer.js @@ -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); diff --git a/test/data/big-min.css b/test/data/big-min.css index 61b680bc..70d40ef7 100644 --- a/test/data/big-min.css +++ b/test/data/big-min.css @@ -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)} diff --git a/test/unit-test.js b/test/unit-test.js index 96131ce5..e97de433 100644 --- a/test/unit-test.js +++ b/test/unit-test.js @@ -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}', -- 2.34.1