* E.g. "strong{color:red}.one,strong{color:#fff}" can be reduced to ".one,strong{color:#fff}".
* Fixes property optimizer when body is empty.
* Fixes property optimizer with merging on joins.
* Adds property overriding so more coarse properties override more granular ones.
* Adds reducing non-adjacent selectors.
* Adds `--skip-advanced`/`noAdvanced` switch to disable advanced optimizations.
+* Adds reducing non-adjacent selectors when overridden by more complex selectors.
1.1.7 / 2013-10-28
==================
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
+ if (token === '')
+ continue;
+
var firstColon = token.indexOf(':');
keyValues.push([
token.substring(0, firstColon),
if (allowAdjacent === false || allowAdjacent === true)
return allowAdjacent;
- return allowAdjacent.indexOf(position - 1) > -1;
+ return allowAdjacent.indexOf(position) > -1;
};
for (var i = 0, l = tokens.length; i < l; i++) {
var reduceNonAdjacent = function(tokens) {
var matched = {};
var matchedMoreThanOnce = [];
+ var partiallyReduced = [];
+ var token, selector, selectors;
+ var removeEmpty = function(value) {
+ return value.length > 0 ? value : '';
+ };
for (var i = 0, l = tokens.length; i < l; i++) {
- var token = tokens[i];
- var selector = token.selector;
+ token = tokens[i];
+ selector = token.selector;
if (typeof(token) == 'string' || token.block)
continue;
- var alreadyMatched = matched[selector];
- if (alreadyMatched) {
- if (alreadyMatched.length == 1)
- matchedMoreThanOnce.push(selector);
- alreadyMatched.push(i);
- } else {
- matched[selector] = [i];
+ selectors = selector.split(',');
+ if (selectors.length > 1)
+ selectors.unshift(selector);
+
+ for (var j = 0, m = selectors.length; j < m; j++) {
+ var sel = selectors[j];
+ var alreadyMatched = matched[sel];
+ if (alreadyMatched) {
+ if (alreadyMatched.length == 1)
+ matchedMoreThanOnce.push(sel);
+ alreadyMatched.push(i);
+ } else {
+ matched[sel] = [i];
+ }
}
}
for (var j = 0, m = matchPositions.length; j < m; j++) {
var body = tokens[matchPositions[j]].body;
bodies.push(body);
- joinsAt.push((joinsAt[j - 1] || 0) + body.split(';').length - 1);
+ joinsAt.push((joinsAt[j - 1] || 0) + body.split(';').length);
}
var optimizedBody = propertyOptimizer.process(bodies.join(';'), joinsAt);
var k = optimizedTokens.length - 1;
var currentMatch = matchPositions.length - 1;
+
while (currentMatch >= 0) {
if (bodies[currentMatch].indexOf(optimizedTokens[k]) > - 1) {
k -= 1;
continue;
}
- tokens[matchPositions[currentMatch]].body = optimizedTokens.splice(k + 1).join(';');
+ var tokenIndex = matchPositions[currentMatch];
+ var token = tokens[tokenIndex];
+ var reducedBody = optimizedTokens
+ .splice(k + 1)
+ .filter(removeEmpty)
+ .join(';');
+
+ if (token.selector == selector) {
+ token.body = reducedBody;
+ } else {
+ token._partials = token._partials || [];
+ token._partials.push(reducedBody);
+
+ if (partiallyReduced.indexOf(tokenIndex) == -1)
+ partiallyReduced.push(tokenIndex);
+ }
+
currentMatch -= 1;
}
});
+
+ // process those tokens which were partially reduced
+ // i.e. at least one of token's selectors saw reduction
+ // if all selectors were reduced to same value we can override it
+ for (i = 0, l = partiallyReduced.length; i < l; i++) {
+ token = tokens[partiallyReduced[i]];
+ selectors = token.selector.split(',');
+
+ if (token._partials.length == selectors.length && token.body != token._partials[0]) {
+ var newBody = token._partials[0];
+ for (var k = 1, n = token._partials.length; k < n; k++) {
+ if (token._partials[k] != newBody)
+ break;
+ }
+
+ if (k == n)
+ token.body = newBody;
+ }
+
+ delete token._partials;
+ }
};
var optimize = function(tokens) {
ol,ul{margin:0;padding:0;list-style-type:none}
dd{margin:0 0 0 40px}
nav ol,nav ul{list-style:none;list-style-image:none}
-img{border:0;-ms-interpolation-mode:bicubic}
+img{-ms-interpolation-mode:bicubic}
svg:not(:root){overflow:hidden}
figure,form{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
#header .acces_compte a{display:block;color:#000}
#header .acces_compte a:hover{color:#000;font-weight:700}
.filtre_page{position:fixed;width:100%;height:100%;z-index:15;left:0;top:0;background:rgba(0,0,0,.5)}
-.lightbox_ext{background:#fff;width:770px;margin:0 auto;position:absolute;top:100px;left:25%;z-index:15;-webkit-box-shadow:0 0 15px #000;-moz-box-shadow:0 0 15px #000;box-shadow:0 0 15px #000}
+.lightbox_ext{width:770px;margin:0 auto;position:absolute;top:100px;left:25%;z-index:15;-webkit-box-shadow:0 0 15px #000;-moz-box-shadow:0 0 15px #000;box-shadow:0 0 15px #000}
.lightbox_ext,.loginbox{overflow:hidden;background:#f5f8f9}
.lightbox_ext h2,.loginbox h2{padding:7px 16px 5px;background:#16212c;border-top:3px solid #747b83;color:#fff}
.lightbox_ext .fermer,.loginbox .fermer{float:right;font-size:11px;line-height:18px;color:#747b83;cursor:pointer}
.ombrelle .autopromo_edito{overflow:hidden;width:314px;height:64px}
.autopromo_edito img{border:1px solid #eef1f5}
.autopromo_edito .nature_edito{display:inline}
-#nav{clear:both;height:32px;margin:0 auto;width:1000px;background:#fafbfc;border-top:3px solid transparent;border-bottom:1px solid #dddee0}
+#nav{clear:both;height:32px;margin:0 auto;width:1000px;background:#fafbfc;border-bottom:1px solid #dddee0}
#nav .conteneur_bordure{width:998px;margin:-3px auto 0;border-top:3px solid #ffd500;border-left:1px solid #d2d6db;border-right:1px solid #d2d6db}
#nav.accueil{width:auto;background:#fff}
#nav ul{overflow:hidden;width:1000px;margin:-3px auto 0}
#nav.acceuil ul{width:998px}
-#nav li{display:block;float:left;border-top-width:3px;border-top-style:solid}
+#nav li{display:block;float:left}
#nav a,#nav span{display:inline-block;height:25px;padding:7px 10px 0 9px;border-left:1px solid #d2d6db;border-bottom:1px solid #d2d6db;font-size:12px;font-weight:700;text-transform:uppercase;color:#000}
#nav .obf:hover,#nav a:hover,#nav li:hover .obf,#nav li:hover a{color:#fff}
#nav .actif{background:#fff}
.bloc_part.gymglish .exercice .texte,.bloc_part.gymglish .mot_mois .texte{width:166px;height:126px;padding:0}
.bloc_part.gymglish .mot_mois .texte{width:155px;padding:4px 15px 0 0}
.bloc_part.gymglish .cours .texte{width:145px;height:170px;padding:0 15px 0 0}
-.bloc_part.gymglish .cours .img{width:120px}
.bloc_part.gymglish .mot_mois .enonce{display:block;overflow:hidden;height:45px;clear:both}
.bloc_part.gymglish .exercice.contenu{position:relative;background:#FFF}
.bloc_part.gymglish .exercice.contenu .btn_fonce{left:16px}
#core-liberation .pagination{height:21px}
#core-liberation .pagination a{display:block;float:left;background:#e6e6e6;height:19px;margin-right:5px;padding:1px 6px}
#core-liberation .pagination span{display:inline;height:19px;margin-right:5px;padding:1px 6px}
-#core-liberation .pagination .current,#core-liberation .pagination .disabled{background:#7d7d7d;color:#fff}
+#core-liberation .pagination .current,#core-liberation .pagination .disabled{background:#7d7d7d}
#core-liberation .js-loader{width:0;height:0}
img#hit-count{position:absolute;bottom:0;right:0;margin:0;padding:0;height:0}
#DOMWindow iframe{height:96%!important}
.site-liberation .block-call-items .tpl-search-results .object-picture .np a.date{background-color:#c8c8c8}
#core-liberation .block-item .object-picture .legende{color:#838383}
.site-liberation .block-item .object-content a:hover{color:#e20000}
-#core-liberation .block-item-locked{border-top-color:#c1b0bb;border-bottom-color:#c1b0bb;background:-moz-linear-gradient(top,#dbdad6 0,#fff 2%,#fff 98%,#e1e0de 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#dbdad6),color-stop(2%,#fff),color-stop(98%,#fff),color-stop(100%,#e1e0de));background:-o-linear-gradient(top,#dbdad6 0,#fff 2%,#fff 98%,#e1e0de 100%)}
+#core-liberation .block-item-locked{border-top-color:#c1b0bb;border-bottom-color:#c1b0bb;background:#fff;background:-moz-linear-gradient(top,#dbdad6 0,#fff 2%,#fff 98%,#e1e0de 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#dbdad6),color-stop(2%,#fff),color-stop(98%,#fff),color-stop(100%,#e1e0de));background:-o-linear-gradient(top,#dbdad6 0,#fff 2%,#fff 98%,#e1e0de 100%)}
#core-liberation .block-item-locked .block-top span{background-color:#fff}
#core-liberation .block-item-locked .btn-zoneabo a:hover{color:#fff}
#core-liberation .block-item-read-more{border-color:#ddd}
.bottom{margin-bottom:0;padding-bottom:0}
label{font-weight:700}
fieldset{padding:0 1.4em 1.4em;margin:0 0 1.5em;border:1px solid #ccc}
-legend{font-weight:700;font-size:1.2em;margin-top:-.2em;margin-bottom:1em}
+legend{font-weight:700;font-size:1.2em}
#IE8#HACK,fieldset{padding-top:1.4em}
#IE8#HACK,legend{margin-top:0;margin-bottom:0}
input.text,input.title,input[type=password],input[type=text],textarea{background-color:#fff;border:1px solid #bbb}
hr.space{background:#fff;color:#fff;visibility:hidden}
.clearfix:after,.container:after{content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden}
.clearfix,.container{display:block}
-.clear{clear:both}
\ No newline at end of file
+.clear{clear:both}
'of two adjacent complex selectors with different selector order': [
'.one,.two{color:red}.two,.one{line-height:1em}',
'.one,.two{color:red;line-height:1em}'
+ ],
+ 'two adjacent with hex color definitions': [
+ "a:link,a:visited{color:#fff}.one{display:block}a:link,a:visited{color:red}",
+ ".one{display:block}a:link,a:visited{color:red}"
]
}),
'same non-adjacent selectors': cssContext({
'a{display:inline-block;display:-moz-inline-box;color:red}.one{font-size:12px}a{color:#fff;margin:2px}',
'a{display:inline-block;display:-moz-inline-box}.one{font-size:12px}a{color:#fff;margin:2px}'
],
+ 'with intentionally redefined properties on nultiple joins': [
+ 'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{font-weight:400}a{margin:0}',
+ '.one{font-size:12px}a{color:#fff}.two{font-weight:400}a{margin:0}'
+ ],
'with all redefined properties': [
'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
'.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
'many with all redefined properties': [
'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
'a{padding:10px}.zero{color:transparent}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
+ ],
+ 'when overriden by an empty selector': [
+ 'a{padding:10px}.one{color:red}a{}',
+ 'a{padding:10px}.one{color:red}'
+ ],
+ 'when overriden by a complex selector': [
+ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}',
+ 'a{margin:0}.one{color:red}a,p{color:red;padding:0}'
+ ],
+ 'when overriden by complex selectors': [
+ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}.one,a{color:#fff}',
+ 'a{margin:0}a,p{color:red;padding:0}.one,a{color:#fff}'
+ ],
+ 'when complex selector overriden by simple selectors': 'a,p{margin:0;color:red}a{color:#fff}',
+ // Pending re-run selectors merge - see #160
+ 'when complex selector overriden by complex and simple selectors': [
+ 'a,p{margin:0;color:red}a{color:#fff}a,p{color:#00f}p{color:#0f0}',
+ 'a,p{margin:0}a,p{color:#00f}p{color:#0f0}'
+ ],
+ 'when complex selector overriden by complex selectors': [
+ '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}',
+ '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}'
]
}),
'same bodies': cssContext({