using System; using System.IO; using System.Collections.Generic; using System.Text; namespace Umbraco.Core.Models.Css { #region Base Types /// /// CSS3 inconsistently specifies more than one grammar: /// http://www.w3.org/TR/css3-syntax/#style /// http://www.w3.org/TR/css3-syntax/#detailed-grammar /// internal abstract class CssSyntax { #region Methods public abstract void Write(TextWriter writer, CssCompactor.Options options); protected static bool IsPrettyPrint(CssCompactor.Options options) { return (options & CssCompactor.Options.PrettyPrint) > 0; } #endregion Methods #region Object Overrides public override string ToString() { var writer = new StringWriter(); this.Write(writer, CssCompactor.Options.PrettyPrint); return writer.ToString(); } #endregion Object Overrides } internal interface ICssValue { #region Methods void Write(TextWriter writer, CssCompactor.Options options); #endregion Methods } internal class CssString : CssSyntax { #region Fields private string value; #endregion Fields #region Properties public virtual string Value { get { return this.value; } set { this.value = value; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { writer.Write(this.Value); } #endregion Methods } #endregion Base Types #region Grammar internal class CssStyleSheet : CssSyntax { #region Fields private readonly List statements = new List(); #endregion Fields #region Properties public List Statements { get { return this.statements; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { bool prettyPrint = IsPrettyPrint(options); foreach (CssStatement statement in this.statements) { statement.Write(writer, options); if (prettyPrint) { writer.WriteLine(); } } } #endregion Methods } internal abstract class CssStatement : CssSyntax, ICssValue { } /// /// /// /// /// NOTE: each at-rule might parse differently according to CSS3 /// The @media block for example contains a block of statements /// while other at-rules with a block contain a block of declarations /// internal class CssAtRule : CssStatement { #region Constants internal const string MediaIdent = "media"; #endregion Constants #region Fields private string ident; private string value; private CssBlock block; #endregion Fields #region Properties public string Ident { get { return this.ident; } set { this.ident = value; } } public string Value { get { return this.value; } set { this.value = value; } } public CssBlock Block { get { if (this.block == null) { this.block = new CssBlock(); } return this.block; } set { this.block = value; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { bool prettyPrint = IsPrettyPrint(options); writer.Write('@'); writer.Write(this.ident); if (!String.IsNullOrEmpty(this.value)) { writer.Write(' '); writer.Write(this.value); } if (this.block != null) { if (prettyPrint) { writer.WriteLine(); } this.block.Write(writer, options); } else { writer.Write(';'); } if (prettyPrint) { writer.WriteLine(); } } #endregion Methods } internal class CssBlock : CssSyntax, ICssValue { #region Fields private readonly List values = new List(); #endregion Fields #region Properties public List Values { get { return this.values; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { bool prettyPrint = IsPrettyPrint(options); writer.Write('{'); if (prettyPrint) { writer.WriteLine(); } foreach (ICssValue value in this.Values) { value.Write(writer, options); } if (prettyPrint) { writer.WriteLine(); } writer.Write('}'); } #endregion Methods } internal class CssRuleSet : CssStatement { #region Fields private readonly List selectors = new List(); private readonly List declarations = new List(); #endregion Fields #region Properties public List Selectors { get { return this.selectors; } } public List Declarations { get { return this.declarations; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { bool prettyPrint = IsPrettyPrint(options); bool comma = false; foreach (CssString selector in this.Selectors) { if (comma) { writer.Write(","); if (prettyPrint) { writer.WriteLine(); } } else { comma = true; } selector.Write(writer, options); } if (prettyPrint) { writer.WriteLine(); } writer.Write("{"); if (prettyPrint) { writer.WriteLine(); } foreach (CssDeclaration dec in this.Declarations) { dec.Write(writer, options); } writer.Write("}"); if (prettyPrint) { writer.WriteLine(); } } #endregion Methods } internal class CssSelector : CssString { } internal class CssDeclaration : CssSyntax, ICssValue { #region Fields private string property; private CssValueList value; #endregion Fields #region Properties public string Property { get { return this.property; } set { this.property = value; } } public CssValueList Value { get { return this.value; } set { this.value = value; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { bool prettyPrint = IsPrettyPrint(options); if (prettyPrint) { writer.Write('\t'); } writer.Write(this.Property); writer.Write(':'); if (prettyPrint) { writer.Write(" "); } this.Value.Write(writer, options); writer.Write(";"); if (prettyPrint) { writer.WriteLine(); } } #endregion Methods } internal class CssValueList : CssSyntax { #region Fields private readonly List values = new List(); #endregion Fields #region Properties public List Values { get { return this.values; } } #endregion Properties #region Methods public override void Write(TextWriter writer, CssCompactor.Options options) { bool space = false; foreach (CssString value in this.Values) { if (space) { writer.Write(" "); } else { space = true; } value.Write(writer, options); } } #endregion Methods } #endregion Grammar }