From: GoalSmashers Date: Sun, 27 Oct 2013 09:50:59 +0000 (+0100) Subject: Adds removing duplicate selectors (same body) within the same scope. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=2c4d7c0a92932411e745223ac6ce8ad68abb0e72;p=clean-css.git Adds removing duplicate selectors (same body) within the same scope. * Always preserve the last one as it overrides previous ones and intermediate overriding. --- diff --git a/lib/selectors/optimizer.js b/lib/selectors/optimizer.js index cacef242..68de01bc 100644 --- a/lib/selectors/optimizer.js +++ b/lib/selectors/optimizer.js @@ -15,6 +15,33 @@ module.exports = function Optimizer(data) { return plain.join(','); }; + var removeDuplicates = function(tokens) { + var matched = {}; + var forRemoval = []; + + for (var i = 0, l = tokens.length; i < l; i++) { + if (typeof(tokens[i]) == 'string' || tokens[i].block) + continue; + + var selector = tokens[i].selector; + var body = tokens[i].body; + var id = body + '@' + selector; + var alreadyMatched = matched[id]; + + if (alreadyMatched) { + forRemoval.push(alreadyMatched[alreadyMatched.length - 1]); + alreadyMatched.push(i); + } else { + matched[id] = [i]; + } + } + + forRemoval = forRemoval.sort(function(a, b) { return a > b ? 1 : -1; }); + for (var j = 0, n = forRemoval.length; j < n; j++) { + tokens.splice(forRemoval[j] - j, 1); + } + }; + var optimize = function(tokens) { tokens = (Array.isArray(tokens) ? tokens : [tokens]); for (var i = 0, l = tokens.length; i < l; i++) { @@ -25,6 +52,8 @@ module.exports = function Optimizer(data) { if (token.block) optimize(token.body); } + + removeDuplicates(tokens); }; var rebuild = function(tokens) { diff --git a/test/data/big-min.css b/test/data/big-min.css index 9e4a5bac..abadd09b 100644 --- a/test/data/big-min.css +++ b/test/data/big-min.css @@ -239,7 +239,6 @@ figure img,article img,.img_bord{border:1px solid #eef1f5;vertical-align:bottom} .pad_top20{padding-top:20px} .bord_top6_gris{border-top:6px solid #e9edf0;padding-top:16px} .bord_bot6_gris{border-bottom:6px solid #e9edf0} -.bord_bot6_gris{border-bottom:6px solid #e9edf0} .bord_top3_gris{border-top:3px solid #e9edf0;padding-top:15px} .bord_top3_politique{border-top:3px solid #1f0d67} .bord_bot3_gris{border-bottom:3px solid #e9edf0} @@ -248,7 +247,6 @@ figure img,article img,.img_bord{border:1px solid #eef1f5;vertical-align:bottom} .bord_top1_gris{border-top:1px solid #e9edf0;padding-top:10px} .bord_bot1_gris{border-bottom:1px solid #e9edf0;padding-bottom:10px} .bord_double_gris_blanc{display:inline-block;line-height:25px;font-size:12px;border:solid #d2d6db;border-width:1px 0} -.bord_double_gris_blanc span{display:inline-block;border:solid #fff;border-width:1px 0} .bord1_gris_clair{border:1px solid #eef1f5} .bord_double_gris_blanc{display:inline-block;border:solid #d2d6db;border-width:1px 0} .bord_double_gris_blanc span{display:inline-block;border:solid #fff;border-width:1px 0} @@ -603,11 +601,7 @@ img[height="97"]+.ico29x29{bottom:6%;left:3.5%} .carousel_petit .repere.actif{background-position:-11px -24px;cursor:pointer} .conteneur_pagination{background:#f8f9fb;font-weight:700;border:1px solid #d2d6db;border-radius:4px;height:26px;margin-top:20px} .pagination_large{margin-top:10px} -.pagination a:hover,.pagination span:hover{cursor:pointer} -.pagination li{display:block;float:left} .pagination .adroite{float:right} -.pagination>li{background:#f8f9fb} -.pagination>li:hover{background:#e4e6e9} .pagination .page{display:block;float:left;padding:0 9px;height:26px;border:solid #e4e6e9;border-width:0 0 0 1px;text-align:center;line-height:26px;font-size:12px} .conteneur_pagination .prev,.conteneur_pagination .next{display:block;float:left;width:27px;height:26px;text-shadow:0 1px 1px rgba(255,255,255,.75);background-color:#fafafa;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fefefe),color-stop(25%,#fefefe),to(#e4e6e9));background-image:-webkit-linear-gradient(#fefefe,#fefefe 25%,#e4e6e9);background-image:-moz-linear-gradient(left,#fefefe,#fefefe 25%,#e4e6e9);background-image:-ms-linear-gradient(#fefefe,#fefefe 25%,#e4e6e9);background-image:-o-linear-gradient(#fefefe,#fefefe 25%,#e4e6e9);background-image:linear-gradient(#fefefe,#fefefe 25%,#e4e6e9);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fefefe', endColorstr='#e4e6e9', GradientType=0);text-align:center;line-height:26px;font-size:15px;color:#2e3942} .conteneur_pagination .prev:hover,.conteneur_pagination .next:hover{color:#2e3942;text-decoration:none;background-color:#e4e6e9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-ms-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear} @@ -925,7 +919,6 @@ label i{display:none;font-style:normal;display:none} .ie #nav_ariane a,#nav_ariane h1{font-size:12px} #nav_ariane .sous_rub{border-right:1px solid #e4e6e9} #nav_ariane .az{position:absolute;left:-9999px} -#nav_ariane .ariane{background:url(/medias/web/img/sprites/sous_nav.png) no-repeat right -175px} #nav_ariane .ariane{position:relative;padding:0 13px 0 0;margin:0 0 0 -13px;border:0} #nav_ariane .ariane.z1{z-index:1} #nav_ariane .ariane.z2{z-index:2} @@ -1089,7 +1082,6 @@ label i{display:none;font-style:normal;display:none} .bloc_part .footer{clear:both;height:21px;padding:4px 15px 0;text-align:right;background:#eef1f5;color:#5d666d;font-size:11px;font-weight:700} .bloc_part .logo_header{height:21px;color:#b9c0c5;font-size:11px;font-weight:400;float:right} .bloc_part .footer span,.bloc_part .footer img{vertical-align:middle} -.bloc_part .footer img{margin:0 0 0 5px} .bloc_part .contenu.attractive{background:#e4e6e9} .global .bloc_part .bandeau{height:24px;padding:0 15px;background:#d2d6db!important;color:#16212c;line-height:22px;white-space:nowrap;overflow:hidden} .bloc_part .attractive.carrousel_petit .texte{width:125px;height:150px} @@ -1099,12 +1091,10 @@ label i{display:none;font-style:normal;display:none} .bloc_part.attractive.format-text.exigeant .texte{padding:0 15px 9px;width:190px} .bloc_part.attractive.format-text.exigeant .btn_fonce{margin:0 0 26px 57px} .bloc_part.attractive.format-text.exigeant.grid_6 .btn_fonce{margin:0;right:15px} -.bloc_part.attractive.text{height:208px} .bloc_part.attractive.temoignage .img,.bloc_part.attractive.escapade .img{margin-right:0;padding:15px 0 15px 15px} .bloc_part.attractive.temoignage.petit .img{margin-right:0;padding:15px 0 15px 15px} .bloc_part.attractive.temoignage .texte,.bloc_part.attractive.escapade .texte{height:166px;margin:0;width:142px} .bloc_part.attractive.temoignage.petit .texte{height:108px} -.bloc_part.attractive.temoignage.petit .texte{height:108px} .bloc_part.attractive.text{height:208px} .bloc_part.attractive.format-text .img img{padding:15px 15px 9px} .services .bloc_part.gymglish.grid_12,.services .bloc_part.darqroom.grid_12.promo{background-color:#e9ecf0;background-image:-moz-linear-gradient(top,#fff,#e9ecf0);background-image:-ms-linear-gradient(top,#fafbfc #e9ecf0);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fafbfc),to(#e9ecf0));background-image:-webkit-linear-gradient(top,#fafbfc,#e9ecf0);background-image:-o-linear-gradient(top,#fafbfc,#e9ecf0);background-image:linear-gradient(top,#fff,#e9ecf0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafbfc', endColorstr='#e9ecf0', GradientType=0)} @@ -1594,7 +1584,6 @@ body.access-pre .block-ad,body.access-ess .block-ad{display:none!important} img.spacer{width:1px;height:1px} .visual-square-90{width:90px;height:90px} .visual-rect-0302-460{width:460px;height:307px} -.visual-rect-0302-460{width:460px;height:307px} .visual-rect-0302-150{width:150px;height:100px} .visual-rect-2305-460{width:460px;height:100px} .txt-up-c{text-transform:uppercase} @@ -2209,7 +2198,6 @@ a.god:hover{background:#3c3c3c;color:#fff;text-decoration:none} #core-liberation .block-search-head .advanced .searchform .source ul li{padding:0 20px 0 12px} #core-liberation .block-search-head .advanced .searchform .category select{margin-left:20px;outline:0} #core-liberation .block-search-head .advanced .searchform input[type=submit]{margin:10px 0 0 165px} -#core-liberation .block-search-head .results{margin-bottom:15px} #core-liberation .block-search-head .results p{margin-bottom:15px} #core-liberation .block-search-head .results p.filters{text-align:right;margin-bottom:0} #core-liberation .block-search-results .block-top{margin-bottom:0} @@ -2617,7 +2605,6 @@ body.access-ess #page-paywall .content .arguments .arg{float:none;margin:auto} .site-liberation .block-call-items .tpl-labo-podcast .emission p.subtitle{margin-bottom:10px} .site-liberation .block-call-items .tpl-labo-podcast .emission .visual{width:60px;height:40px} .site-liberation .block-call-items .tpl-labo-podcast .emission .subscribe{clear:both} -.site-liberation .block-call-items .tpl-labo-podcast .emission .subscribe p{color:#e20000} .site-liberation .block-call-items .tpl-labo-podcast .emission .subscribe p.infos{font-weight:700;color:#222} .site-liberation .block-call-items .tpl-labo-podcast .emission .subscribe p.infos span{text-transform:uppercase} .site-liberation .block-call-items .tpl-labo-podcast .emission .subscribe .sb-podcasts{margin-top:10px} @@ -2845,8 +2832,6 @@ body.slideshow .ad-top .megaban{background:#333} #core-liberation .flat-comments .comment>.comment_outer,#core-liberation .block-comments .comment_level_0>.comment_outer{border-color:#878787} #core-liberation .block-comments .block-content .detail_comment{border-top-color:#fe9900} #core-liberation .block-comments .block-content .detail_comment>.comment_outer{border-color:#fe9900} -#core-liberation .block-comments .block-content .detail_comment{border-top-color:#fe9900} -#core-liberation .block-comments .block-content .detail_comment>.comment_outer{border-color:#fe9900} #core-liberation .block-comments .block-content .meta .who,#core-liberation .block-comments .block-content .meta .who a{color:#878787} #core-liberation .block-comments .block-content .meta .details{color:#b2b2b2} #core-liberation .block-comments .block-content .meta .details a.profile{color:#b2b2b2} @@ -3054,4 +3039,4 @@ html.js body.dummy div#mainContent div#core-liberation div.col9 div.block div.bl html.js body.dummy div#mainContent div#core-liberation div.col9 div.block div.block-content div.favorites-frontpages div.col-left div.cartridge{width:388px} html.js body.dummy div#mainContent div#core-liberation div.col9 div.block div.block-content div.favorites-folders div.block-call-items div.block-content div.mini-tpl div.cartridge{margin-left:0;width:129px} html.js body.dummy div#mainContent div#core-liberation div.col7 div.block-call-items div.block-content div.mini-tpl div.folder-on-demand div.object-content{margin-right:0;min-height:0;border-bottom:0} -html.js body.dummy div#mainContent div#core-liberation div.col7 div.block-call-items div.block-content div.mini-tpl div.folder-on-demand{border-bottom:1px solid #E7E7E7} +html.js body.dummy div#mainContent div#core-liberation div.col7 div.block-call-items div.block-content div.mini-tpl div.folder-on-demand{border-bottom:1px solid #E7E7E7} \ No newline at end of file diff --git a/test/unit-test.js b/test/unit-test.js index e95a92c4..39d0972b 100644 --- a/test/unit-test.js +++ b/test/unit-test.js @@ -637,8 +637,8 @@ vows.describe('clean-units').addBatch({ 'a{background:url(/images/blank.png) 0 0 no-repeat}' ], 'strip more': [ - 'a{background:url("/images/blank.png") 0 0 no-repeat}a{display:block}a{background:url("/images/blank.png") 0 0 no-repeat}', - 'a{background:url(/images/blank.png) 0 0 no-repeat}a{display:block}a{background:url(/images/blank.png) 0 0 no-repeat}' + 'a{background:url("/images/blank.png") 0 0 no-repeat}a{display:block}a{background:url("/images/blank2.png") 0 0 no-repeat}', + 'a{background:url(/images/blank.png) 0 0 no-repeat}a{display:block}a{background:url(/images/blank2.png) 0 0 no-repeat}' ], 'not strip comments if spaces inside': [ 'a{background:url("/images/long image name.png") 0 0 no-repeat}a{display:block}a{background:url("/images/no-spaces.png") 0 0 no-repeat}', @@ -1057,5 +1057,35 @@ title']{display:block}", '@media screen{a,#foo[data-path^="bar bar"],p,#foo[data-path^="bar bar"]{color:red}}', '@media screen{a,#foo[data-path^="bar bar"],p{color:red}}' ] + }), + 'duplicate selectors in a scope': cssContext({ + 'of two successive selectors': [ + 'a{color:red}a{color:red}', + 'a{color:red}' + ], + 'of two successive selectors with different body': [ + 'a{color:red}a{display:block}', + 'a{color:red}a{display:block}' + ], + 'of many successive selectors': [ + 'a{color:red}a{color:red}a{color:red}a{color:red}', + 'a{color:red}' + ], + 'of two non-successive selectors': [ + 'a{color:red}p{color:#fff}a{color:red}', + 'p{color:#fff}a{color:red}' + ], + 'of many non-successive selectors': [ + 'div{width:100%}a{color:red}a{color:red}p{color:#fff}div{width:100%}ol{margin:0}p{color:#fff}', + 'a{color:red}div{width:100%}ol{margin:0}p{color:#fff}' + ], + 'with global and media scope': [ + 'a{color:red}@media screen{a{color:red}p{width:100px}a{color:red}}', + 'a{color:red}@media screen{p{width:100px}a{color:red}}' + ], + 'with two media scopes': [ + '@media (min-width:100px){a{color:red}}@media screen{a{color:red}p{width:100px}a{color:red}}', + '@media (min-width:100px){a{color:red}}@media screen{p{width:100px}a{color:red}}' + ] }) }).export(module);