diff --git a/html.d b/html.d index bdb9522..de7e712 100644 --- a/html.d +++ b/html.d @@ -1210,22 +1210,31 @@ class CssAtRule : CssPart { assert(css[0] == '@'); int braceCount = 0; + int startOfInnerSlice = -1; foreach(i, c; css) { if(braceCount == 0 && c == ';') { content = css[0 .. i + 1]; css = css[i + 1 .. $]; + + opener = content; break; } - if(c == '{') + if(c == '{') { braceCount++; + if(startOfInnerSlice == -1) + startOfInnerSlice = i; + } if(c == '}') { braceCount--; if(braceCount < 0) throw new Exception("Bad CSS: mismatched }"); if(braceCount == 0) { + opener = css[0 .. startOfInnerSlice]; + inner = css[startOfInnerSlice + 1 .. i]; + content = css[0 .. i + 1]; css = css[i + 1 .. $]; break; @@ -1236,9 +1245,14 @@ class CssAtRule : CssPart { string content; + string opener; + string inner; + override CssAtRule clone() const { auto n = new CssAtRule(); n.content = content; + n.opener = opener; + n.inner = inner; return n; } override string toString() const { return content; } @@ -1477,11 +1491,30 @@ string cssToString(in CssPart[] css) { const(CssPart)[] denestCss(CssPart[] css) { CssPart[] ret; foreach(part; css) { - auto set = cast(CssRuleSet) part; - if(set is null) - ret ~= part; - else { - ret ~= set.deNest(); + auto at = cast(CssAtRule) part; + if(at is null) { + auto set = cast(CssRuleSet) part; + if(set is null) + ret ~= part; + else { + ret ~= set.deNest(); + } + } else { + // at rules with content may be denested at the top level... + // FIXME: is this even right all the time? + + if(at.inner.length) { + auto newCss = at.opener ~ "{\n"; + + // the whitespace manipulations are just a crude indentation thing + newCss ~= "\t" ~ (cssToString(denestCss(lexCss(at.inner))).replace("\n", "\n\t").replace("\n\t\n\t", "\n\n\t")); + + newCss ~= "\n}"; + + ret ~= new CssAtRule(newCss); + } else { + ret ~= part; // no inner content, nothing special needed + } } }