// "Therefore those skilled at the unorthodox // are infinite as heaven and earth, // inexhaustible as the great rivers. // When they come to an end, // they begin again, // like the days and months; // they die and are reborn, // like the four seasons." // // - Sun Tsu, // "The Art of War" using System.Collections.Generic; using TheArtOfDev.HtmlRenderer.Core.Utils; namespace TheArtOfDev.HtmlRenderer.Core.Entities { /// /// Represents a block of CSS property values.
/// Contains collection of key-value pairs that are CSS properties for specific css class.
/// Css class can be either custom or html tag name. ///
/// /// To learn more about CSS blocks visit CSS spec: http://www.w3.org/TR/CSS21/syndata.html#block /// public sealed class CssBlock { #region Fields and Consts /// /// the name of the css class of the block /// private readonly string _class; /// /// the CSS block properties and values /// private readonly Dictionary _properties; /// /// additional selectors to used in hierarchy (p className1 > className2) /// private readonly List _selectors; /// /// is the css block has :hover pseudo-class /// private readonly bool _hover; #endregion /// /// Creates a new block from the block's source /// /// the name of the css class of the block /// the CSS block properties and values /// optional: additional selectors to used in hierarchy /// optional: is the css block has :hover pseudo-class public CssBlock(string @class, Dictionary properties, List selectors = null, bool hover = false) { ArgChecker.AssertArgNotNullOrEmpty(@class, "@class"); ArgChecker.AssertArgNotNull(properties, "properties"); _class = @class; _selectors = selectors; _properties = properties; _hover = hover; } /// /// the name of the css class of the block /// public string Class { get { return _class; } } /// /// additional selectors to used in hierarchy (p className1 > className2) /// public List Selectors { get { return _selectors; } } /// /// Gets the CSS block properties and its values /// public IDictionary Properties { get { return _properties; } } /// /// is the css block has :hover pseudo-class /// public bool Hover { get { return _hover; } } /// /// Merge the other block properties into this css block.
/// Other block properties can overwrite this block properties. ///
/// the css block to merge with public void Merge(CssBlock other) { ArgChecker.AssertArgNotNull(other, "other"); foreach (var prop in other._properties.Keys) { _properties[prop] = other._properties[prop]; } } /// /// Create deep copy of the CssBlock. /// /// new CssBlock with same data public CssBlock Clone() { return new CssBlock(_class, new Dictionary(_properties), _selectors != null ? new List(_selectors) : null); } /// /// Check if the two css blocks are the same (same class, selectors and properties). /// /// the other block to compare to /// true - the two blocks are the same, false - otherwise public bool Equals(CssBlock other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (!Equals(other._class, _class)) return false; if (!Equals(other._properties.Count, _properties.Count)) return false; foreach (var property in _properties) { if (!other._properties.ContainsKey(property.Key)) return false; if (!Equals(other._properties[property.Key], property.Value)) return false; } if (!EqualsSelector(other)) return false; return true; } /// /// Check if the selectors of the css blocks is the same. /// /// the other block to compare to /// true - the selectors on blocks are the same, false - otherwise public bool EqualsSelector(CssBlock other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (other.Hover != Hover) return false; if (other._selectors == null && _selectors != null) return false; if (other._selectors != null && _selectors == null) return false; if (other._selectors != null && _selectors != null) { if (!Equals(other._selectors.Count, _selectors.Count)) return false; for (int i = 0; i < _selectors.Count; i++) { if (!Equals(other._selectors[i].Class, _selectors[i].Class)) return false; if (!Equals(other._selectors[i].DirectParent, _selectors[i].DirectParent)) return false; } } return true; } /// /// Check if the two css blocks are the same (same class, selectors and properties). /// /// the other block to compare to /// true - the two blocks are the same, false - otherwise public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof(CssBlock)) return false; return Equals((CssBlock)obj); } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current . public override int GetHashCode() { unchecked { return ((_class != null ? _class.GetHashCode() : 0) * 397) ^ (_properties != null ? _properties.GetHashCode() : 0); } } /// /// Returns a that represents the current . /// public override string ToString() { var str = _class + " { "; foreach (var property in _properties) { str += string.Format("{0}={1}; ", property.Key, property.Value); } return str + " }"; } } }