From: Jakub Pawlowicz Date: Thu, 22 Jan 2015 20:10:00 +0000 (+0000) Subject: Fixes #442 - space before adjacent `nav`. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=3bf9dc10c8ae4b4987fada08adf06601b8396528;p=clean-css.git Fixes #442 - space before adjacent `nav`. As it turns out Android stock browser <= 4.3 needs a space between `+` and `nav`, e.g. `div+ nav{}`. It's off by default and can be turned on with: * `--compatibility +selectors.adjacentSpace` or * `compatibility: { selectors: { adjacentSpace: true } }` See http://codepen.io/anon/pen/QwgLVv --- diff --git a/History.md b/History.md index a0751347..2fea22f6 100644 --- a/History.md +++ b/History.md @@ -10,6 +10,7 @@ * Fixed issue [#416](https://github.com/GoalSmashers/clean-css/issues/416) - accepts hash as `minify` argument. * Fixed issue [#435](https://github.com/GoalSmashers/clean-css/issues/435) - `background-clip` in shorthand. * Fixed issue [#439](https://github.com/GoalSmashers/clean-css/issues/439) - `background-origin` in shorthand. +* Fixed issue [#442](https://github.com/GoalSmashers/clean-css/issues/442) - space before adjacent `nav`. [3.0.7 / 2015-01-22](https://github.com/jakubpawlowicz/clean-css/compare/v3.0.6...v3.0.7) ================== diff --git a/README.md b/README.md index 66150a61..3dabed05 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,7 @@ with the following options available: * `'[+-]properties.backgroundSizeMerging'` - turn on / off background-size merging into shorthand * `'[+-]properties.merging'` - turn on / off property merging based on understandability * `'[+-]properties.spaceAfterClosingBrace'` - turn on / off removing space after closing brace - `url() no-repeat` into `url()no-repeat` +* `'[+-]selectors.adjacentSpace'` - turn on / off extra space before `nav` element * `'[+-]selectors.ie7Hack'` - turn on / off IE7 selector hack removal (`*+html...`) * `'[+-]units.rem'` - turn on / off treating `rem` as a proper unit diff --git a/lib/selectors/optimizers/advanced.js b/lib/selectors/optimizers/advanced.js index 7fe297bb..c82826f3 100644 --- a/lib/selectors/optimizers/advanced.js +++ b/lib/selectors/optimizers/advanced.js @@ -79,6 +79,7 @@ AdvancedOptimizer.prototype.removeDuplicates = function (tokens) { AdvancedOptimizer.prototype.mergeAdjacent = function (tokens) { var forRemoval = []; var lastToken = { selector: null, body: null }; + var adjacentSpace = this.options.compatibility.selectors.adjacentSpace; for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; @@ -97,7 +98,7 @@ AdvancedOptimizer.prototype.mergeAdjacent = function (tokens) { !this.isSpecial(token.metadata.selector) && !this.isSpecial(lastToken.metadata.selector)) { changeSelectorOf( lastToken, - CleanUp.selectors(lastToken.value.concat(token.value), false) + CleanUp.selectors(lastToken.value.concat(token.value), false, adjacentSpace) ); forRemoval.push(i); } else { @@ -321,6 +322,7 @@ AdvancedOptimizer.prototype.mergeNonAdjacentBySelector = function (tokens) { AdvancedOptimizer.prototype.mergeNonAdjacentByBody = function (tokens) { var candidates = {}; + var adjacentSpace = this.options.compatibility.selectors.adjacentSpace; for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; @@ -334,7 +336,7 @@ AdvancedOptimizer.prototype.mergeNonAdjacentByBody = function (tokens) { if (oldToken && !this.isSpecial(token.metadata.selector) && !this.isSpecial(oldToken.metadata.selector)) { changeSelectorOf( token, - CleanUp.selectors(oldToken.value.concat(token.value), false) + CleanUp.selectors(oldToken.value.concat(token.value), false, adjacentSpace) ); oldToken.body = []; diff --git a/lib/selectors/optimizers/clean-up.js b/lib/selectors/optimizers/clean-up.js index 943e405f..5c2555e2 100644 --- a/lib/selectors/optimizers/clean-up.js +++ b/lib/selectors/optimizers/clean-up.js @@ -7,7 +7,7 @@ function selectorSorter(s1, s2) { } var CleanUp = { - selectors: function (selectors, removeUnsupported) { + selectors: function (selectors, removeUnsupported, adjacentSpace) { var plain = []; var tokenized = []; @@ -19,6 +19,9 @@ var CleanUp = { .replace(/\s*([>\+\~])\s*/g, '$1') .trim(); + if (adjacentSpace && reduced.indexOf('nav') > 0) + reduced = reduced.replace(/\+nav(\S|$)/, '+ nav$1'); + if (removeUnsupported && (reduced.indexOf('*+html ') != -1 || reduced.indexOf('*:first-child+html ') != -1)) continue; diff --git a/lib/selectors/optimizers/simple.js b/lib/selectors/optimizers/simple.js index 1190723d..3153e5fe 100644 --- a/lib/selectors/optimizers/simple.js +++ b/lib/selectors/optimizers/simple.js @@ -240,7 +240,7 @@ SimpleOptimizer.prototype.optimize = function(tokens) { break; if (token.kind == 'selector') { - var newSelectors = CleanUp.selectors(token.value, !options.compatibility.selectors.ie7Hack); + var newSelectors = CleanUp.selectors(token.value, !options.compatibility.selectors.ie7Hack, options.compatibility.selectors.adjacentSpace); token.value = newSelectors.tokenized; if (token.value.length === 0) { diff --git a/lib/utils/compatibility.js b/lib/utils/compatibility.js index 23684e5a..70c38747 100644 --- a/lib/utils/compatibility.js +++ b/lib/utils/compatibility.js @@ -13,6 +13,7 @@ var DEFAULTS = { spaceAfterClosingBrace: false // 'url() no-repeat' to 'url()no-repeat' }, selectors: { + adjacentSpace: false, // div+ nav Android stock browser hack ie7Hack: false, // *+html hack special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right)/ // special selectors which prevent merging }, @@ -32,6 +33,7 @@ var DEFAULTS = { spaceAfterClosingBrace: true }, selectors: { + adjacentSpace: false, ie7Hack: false, special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/ }, @@ -51,6 +53,7 @@ var DEFAULTS = { spaceAfterClosingBrace: true }, selectors: { + adjacentSpace: false, ie7Hack: true, special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:focus|:before|:after|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/ }, diff --git a/test/integration-test.js b/test/integration-test.js index e2bea441..0b15265b 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -1852,6 +1852,12 @@ title']{display:block}", 'of supported and unsupported selector': '.one{color:red}.two:last-child{color:red}', 'of two unsupported selectors': '.one:before{color:red}.two:last-child{color:red}' }, { compatibility: 'ie7' }), + 'same bodies - +adjacentSpace': cssContext({ + 'of two supported selectors': [ + '.one{color:red}.two + nav{color:red}', + '.one,.two+ nav{color:red}' + ] + }, { compatibility: { selectors: { adjacentSpace: true } } }), 'units - IE8 compatibility': cssContext({ 'rems': 'div{padding-top:16px;padding-top:1rem}' }, { compatibility: 'ie8' }), diff --git a/test/selectors/optimizers/simple-test.js b/test/selectors/optimizers/simple-test.js index d5af0da7..da90646b 100644 --- a/test/selectors/optimizers/simple-test.js +++ b/test/selectors/optimizers/simple-test.js @@ -72,6 +72,10 @@ vows.describe(SimpleOptimizer) '+html': [ '*+html .foo{display:inline}', null + ], + 'adjacent nav': [ + 'div + nav{}', + [{ value: 'div+nav' }] ] }) ) @@ -103,6 +107,18 @@ vows.describe(SimpleOptimizer) ] }, { compatibility: 'ie7' }) ) + .addBatch( + selectorContext('+adjacentSpace', { + 'with whitespace': [ + 'div + nav{}', + [{ value: 'div+ nav' }] + ], + 'without whitespace': [ + 'div+nav{}', + [{ value: 'div+ nav' }] + ] + }, { compatibility: { selectors: { adjacentSpace: true } } }) + ) .addBatch( propertyContext('@background', { 'none to 0 0': [ @@ -499,4 +515,12 @@ vows.describe(SimpleOptimizer) ] }, { compatibility: 'ie8' }) ) + .addBatch( + propertyContext('whitespace in compatibility mode', { + 'stripped spaces': [ + 'div{text-shadow:rgba(255,1,1,.5) 1px}', + ['text-shadow:rgba(255,1,1,.5) 1px'] + ] + }, { compatibility: 'ie8' }) + ) .export(module); diff --git a/test/utils/compatibility-test.js b/test/utils/compatibility-test.js index 95b3fbb7..cbf7b8c4 100644 --- a/test/utils/compatibility-test.js +++ b/test/utils/compatibility-test.js @@ -9,6 +9,7 @@ vows.describe(Compatibility) 'gets default options': function(options) { assert.isFalse(options.properties.iePrefixHack); assert.isFalse(options.properties.ieSuffixHack); + assert.isFalse(options.selectors.adjacentSpace); assert.isFalse(options.selectors.ie7Hack); assert.isFalse(options.properties.backgroundSizeMerging); assert.isTrue(options.properties.merging); @@ -29,6 +30,7 @@ vows.describe(Compatibility) 'gets merged options': function(options) { assert.isFalse(options.properties.iePrefixHack); assert.isFalse(options.properties.ieSuffixHack); + assert.isFalse(options.selectors.adjacentSpace); assert.isFalse(options.selectors.ie7Hack); assert.isFalse(options.properties.backgroundSizeMerging); assert.isTrue(options.properties.merging); @@ -45,6 +47,7 @@ vows.describe(Compatibility) 'gets template options': function(options) { assert.isTrue(options.properties.iePrefixHack); assert.isTrue(options.properties.ieSuffixHack); + assert.isFalse(options.selectors.adjacentSpace); assert.isFalse(options.selectors.ie7Hack); assert.isFalse(options.properties.backgroundSizeMerging); assert.isFalse(options.properties.merging); @@ -60,6 +63,7 @@ vows.describe(Compatibility) assert.isTrue(options.properties.iePrefixHack); assert.isTrue(options.properties.ieSuffixHack); assert.isTrue(options.selectors.ie7Hack); + assert.isFalse(options.selectors.adjacentSpace); assert.isFalse(options.properties.backgroundSizeMerging); assert.isFalse(options.properties.merging); assert.isTrue(options.properties.spaceAfterClosingBrace);