public void TestGroupCSSSelectors() { Hashtable initialCSSClasses = new Hashtable(); Hashtable optimizedCSSClasses = new Hashtable(); //same initial CSS properties string props1 = "font-family:sans-serif;font-size:100%;color:red;"; string props2 = "color:red;font-size:100%;font-family:sans-serif;"; //the expected properties (ordered alphabetically) string expectedProp = "color:red;font-family:sans-serif;font-size:100%"; //initial CSS selectors string[] classes1 = { ".xoffice0", ".xoffice1", ".xoffice2", "textarea" }; string[] classes2 = { ".xoffice3", ".xoffice4", ".myCssClass", "#one", "p#two" }; for (int i = 0; i < classes1.Length; i++) { initialCSSClasses.Add(classes1[i], props1); } for (int i = 0; i < classes2.Length; i++) { initialCSSClasses.Add(classes2[i], props2); } optimizedCSSClasses = CSSUtil.GroupCSSSelectors(initialCSSClasses); ICollection optimizedKeys = optimizedCSSClasses.Keys; //all the selectors should be grouped Assert.IsTrue(optimizedKeys.Count == 1); foreach (string key in optimizedKeys) { string val = optimizedCSSClasses[key].ToString(); //in the new key there must be all initial CSS selectors foreach (string cssClass in classes1) { Assert.IsTrue(key.IndexOf(cssClass) >= 0); } foreach (string cssClass in classes2) { Assert.IsTrue(key.IndexOf(cssClass) >= 0); } //expected properties are the same, but ordered alphabetically Assert.IsTrue(val.IndexOf(expectedProp) >= 0); } }
/// <summary> /// Extracts the inline styles, optimizes CSS and adds CSS classes in the head section for current page /// </summary> /// <param name="xmlDoc">A reference to a XmlDocument instance.</param> public void Filter(ref System.Xml.XmlDocument xmlDoc) { XmlNode body = xmlDoc.GetElementsByTagName("body")[0]; XmlNode head = xmlDoc.GetElementsByTagName("head")[0]; if (head == null) { head = xmlDoc.CreateNode(XmlNodeType.Element, "head", xmlDoc.NamespaceURI); body.ParentNode.InsertBefore(head, body); } //step1: inline CSS for existing CSS classes and ids, for better manipulation at step2 and step3 CSSUtil.InlineCSS(ref xmlDoc); //step2: convert all inlined style to CSS classes //(including, but not limited to, those generated at step1) body = CSSUtil.ConvertInlineStylesToCssClasses(body, ref xmlDoc, ref counter, ref cssClasses); //step3: optimize CSS by grouping selectors with the same properties cssClasses = CSSUtil.GroupCSSSelectors(cssClasses); InsertCssClassesInHeader(ref head, ref xmlDoc); }