Skip to content

Commit

Permalink
Fix CSS pseudo-class and pseudo-element formatting. Closes #363
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Stockman committed Nov 23, 2013
1 parent 0e73419 commit f416b0b
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 2 deletions.
60 changes: 58 additions & 2 deletions js/lib/beautify-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
var indentString = source_text.match(/^[\r\n]*[\t ]*/)[0];
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
var indentLevel = 0;
var nestedLevel = 0;

function indent() {
indentLevel++;
Expand Down Expand Up @@ -207,6 +208,8 @@
/*_____________________--------------------_____________________*/

var insideRule = false;
var enteringConditionalGroup = false;

while (true) {
var isAfterSpace = skipWhitespace();

Expand All @@ -221,6 +224,20 @@
}
} else if (ch === '/' && peek() === '/') { // single line comment
output.push(eatComment(true), indentString);
} else if (ch === '@') {
// strip trailing space, if present, for hash property checks
var atRule = eatString(" ").replace(/ $/, '');

// pass along the space we found as a separate item
output.push(atRule, ch);

// might be a nesting at-rule
if (atRule in css_beautify.NESTED_AT_RULE) {
nestedLevel += 1;
if (atRule in css_beautify.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
}
} else if (ch === '{') {
eatWhitespace();
if (peek() === '}') {
Expand All @@ -229,15 +246,38 @@
} else {
indent();
print["{"](ch);
// when entering conditional groups, only rulesets are allowed
if (enteringConditionalGroup) {
enteringConditionalGroup = false;
insideRule = (indentLevel > nestedLevel);
} else {
// otherwise, declarations are also allowed
insideRule = (indentLevel >= nestedLevel);
}
}
} else if (ch === '}') {
outdent();
print["}"](ch);
insideRule = false;
if (nestedLevel) {
nestedLevel--;
}
} else if (ch === ":") {
eatWhitespace();
output.push(ch, " ");
insideRule = true;
if (insideRule || enteringConditionalGroup) {
// 'property: value' delimiter
// which could be in a conditional group query
output.push(ch, " ");
} else {
if (peek() === ":") {
// pseudo-element
next();
output.push("::");
} else {
// pseudo-class
output.push(ch);
}
}
} else if (ch === '"' || ch === '\'') {
output.push(eatString(ch));
} else if (ch === ';') {
Expand Down Expand Up @@ -305,6 +345,22 @@
return sweetCode;
}

// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
css_beautify.NESTED_AT_RULE = {
"@page": true,
"@font-face": true,
"@keyframes": true,
// also in CONDITIONAL_GROUP_RULE below
"@media": true,
"@supports": true,
"@document": true
};
css_beautify.CONDITIONAL_GROUP_RULE = {
"@media": true,
"@supports": true,
"@document": true
};

/*global define */
if (typeof define === "function") {
// Add support for require.js
Expand Down
38 changes: 38 additions & 0 deletions js/test/beautify-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,7 @@ function run_beautifier_tests(test_obj, Urlencoded, js_beautify, html_beautify,
btc(".tabs{background:url('back.jpg')}", ".tabs {\n\tbackground: url('back.jpg')\n}\n");
btc("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}\n");
btc("@media print {.tab{}}", "@media print {\n\t.tab {}\n}\n");
btc("@media print {.tab{background-image:url(foo@2x.png)}}", "@media print {\n\t.tab {\n\t\tbackground-image: url(foo@2x.png)\n\t}\n}\n");

// comments
btc("/* test */", "/* test */\n");
Expand All @@ -1753,15 +1754,52 @@ function run_beautifier_tests(test_obj, Urlencoded, js_beautify, html_beautify,
btc("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}\n");
btc("a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}\n");

// block nesting
btc("#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}\n");
btc("@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}\n");
/*
@font-face {
font-family: 'Bitstream Vera Serif Bold';
src: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');
}
@media screen {
#foo:hover {
background-image: url(foo.png);
}
@media screen and (min-device-pixel-ratio: 2) {
@font-face {
font-family: 'Helvetica Neue'
}
#foo:hover {
background-image: url(foo@2x.png);
}
}
}
*/
btc("@font-face {\n\tfont-family: 'Bitstream Vera Serif Bold';\n\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: 'Helvetica Neue'\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}\n");

// test options
opts.indent_size = 2;
opts.indent_char = ' ';
opts.selector_separator_newline = false;

btc("#bla, #foo{color:green}", "#bla, #foo {\n color: green\n}\n");
btc("@media print {.tab{}}", "@media print {\n .tab {}\n}\n");
btc("@media print {.tab,.bat{}}", "@media print {\n .tab, .bat {}\n}\n");
btc("#bla, #foo{color:black}", "#bla, #foo {\n color: black\n}\n");

// pseudo-classes and pseudo-elements
btc("#foo:hover {\n background-image: url(foo@2x.png)\n}\n");
btc("#foo *:hover {\n color: purple\n}\n");
btc("::selection {\n color: #ff0000;\n}\n");

// TODO: don't break nested pseduo-classes
btc("@media screen {.tab,.bat:hover {color:red}}", "@media screen {\n .tab, .bat:hover {\n color: red\n }\n}\n");

// particular edge case with braces and semicolons inside tags that allows custom text
btc("a:not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}",
"a:not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}\n");

return sanitytest;
}

Expand Down

0 comments on commit f416b0b

Please sign in to comment.