private void parsePseudoClass() { pseudoClassSelector pseudoClass = new pseudoClassSelector(); pseudoClass.wholeText = _selectorText; if (_buffer.Length > 0) { pseudoClass.elementE = AppendCleanBuffer(_buffer); } char current = ReadNext(); bool InBracketState = false; while (!stop) { if (InBracketState) { _buffer.Append(current); if (current == ')') { InBracketState = false; break; } } else { if (current == ':') { if (_buffer.Length > 0) { pseudoClass.elementE += AppendCleanBuffer(_buffer); } } else { if (current == '(') { InBracketState = true; } _buffer.Append(current); } } current = ReadNext(); } pseudoClass.matchText = AppendCleanBuffer(_buffer); simple = pseudoClass; }
private static int _getSilbingCount(Element element, pseudoClassSelector pseudoClass, bool last, bool sametype) { int counter = 0; Node siblingNode; if (last) { siblingNode = element.nextSibling(); } else { siblingNode = element.previousSibling(); } while (siblingNode != null) { if (siblingNode.nodeType == enumNodeType.ELEMENT) { if (sametype) { if (siblingNode.nodeName == pseudoClass.elementE) { counter += 1; } } else { counter += 1; } } if (last) { siblingNode = siblingNode.nextSibling(); } else { siblingNode = siblingNode.previousSibling(); } } return(counter); }
private static bool _pseudoClassNthMatch(Element element, pseudoClassSelector pseudoClass, bool last, bool sametype) { int firstindex = pseudoClass.matchText.IndexOf("("); int lastindex = pseudoClass.matchText.IndexOf(")"); if (firstindex < 0 || lastindex < 0) { return(false); } string strnumber = pseudoClass.matchText.Substring(firstindex + 1, lastindex - firstindex - 1).Trim(); int counter = _getSilbingCount(element, pseudoClass, last, sametype); if (CommonIdoms.isAsciiDigit(strnumber)) { int nth = Convert.ToInt32(strnumber); return(nth == (counter + 1)); } else { if (strnumber.Contains("n")) { int beforen = 0; int aftern = 0; string strbefore = strnumber.Substring(0, strnumber.IndexOf("n")).Trim(); if (string.IsNullOrEmpty(strbefore)) { return(false); } if (!int.TryParse(strbefore, out beforen)) { return(false); } if (CommonIdoms.isAsciiDigit(strbefore)) { beforen = Convert.ToInt32(strbefore); } if (strnumber.IndexOf("+") > 0) { string strafter = strnumber.Substring(strnumber.IndexOf("+") + 1).Trim(); if (!string.IsNullOrEmpty(strafter)) { if (!int.TryParse(strafter, out aftern)) { return(false); } } } if (beforen == 0) { return((counter + 1) == aftern); } else { return((counter + 1) % beforen == aftern); } } else if (strnumber == "odd") { return((counter + 1) % 2 == 1); } else if (strnumber == "even") { return((counter + 1) % 2 == 0); } else { return(false); } } }
private static bool matchPseudoClass(Element element, pseudoClassSelector pseudoClass) { if (!string.IsNullOrEmpty(pseudoClass.elementE)) { if (!selectorMatch.Match(element, pseudoClass.ElementSelector)) { return(false); } } pseudoClass.matchText = pseudoClass.matchText.ToLower().Trim(); // E:root an E element, root of the document Structural pseudo-classes 3 if (pseudoClass.matchText == "root") { if (element.tagName == "html" && element.depth == 0) { return(true); } else { return(false); } } //E:nth-child(n) an E element, the n-th child of its parent Structural pseudo-classes 3 else if (pseudoClass.matchText.Contains("nth-child")) { return(_pseudoClassNthMatch(element, pseudoClass, false, false)); } else if (pseudoClass.matchText.Contains("not")) { if (pseudoClass.NotSelector == null) { return(false); } var innermatch = selectorMatch.Match(element, pseudoClass.NotSelector); return(!innermatch); } //E:nth-last-child(n) an E element, the n-th child of its parent, counting from the last one Structural pseudo-classes 3 else if (pseudoClass.matchText.Contains("nth-last-child")) { return(_pseudoClassNthMatch(element, pseudoClass, true, false)); } //E:nth-of-type(n) an E element, the n-th sibling of its type Structural pseudo-classes 3 else if (pseudoClass.matchText.Contains("nth-of-type")) { return(_pseudoClassNthMatch(element, pseudoClass, false, true)); } //E:nth-last-of-type(n) an E element, the n-th sibling of its type, counting from the last one Structural pseudo-classes 3 else if (pseudoClass.matchText.Contains("nth-last-of-type")) { return(_pseudoClassNthMatch(element, pseudoClass, true, true)); } //E:first-child an E element, first child of its parent Structural pseudo-classes 2 else if (pseudoClass.matchText == "first-child") { int counter = _getSilbingCount(element, pseudoClass, false, false); return(counter == 0); } //E:last-child an E element, last child of its parent Structural pseudo-classes 3 else if (pseudoClass.matchText == "last-child") { int counter = _getSilbingCount(element, pseudoClass, true, false); return(counter == 0); } //E:first-of-type an E element, first sibling of its type Structural pseudo-classes 3 else if (pseudoClass.matchText == "first-of-type") { int counter = _getSilbingCount(element, pseudoClass, false, true); return(counter == 0); } //E:last-of-type an E element, last sibling of its type Structural pseudo-classes 3 else if (pseudoClass.matchText == "last-of-type") { int counter = _getSilbingCount(element, pseudoClass, true, true); return(counter == 0); } //E:only-child an E element, only child of its parent Structural pseudo-classes 3 else if (pseudoClass.matchText == "only-child") { int counterbefore = _getSilbingCount(element, pseudoClass, false, false); int counterafter = _getSilbingCount(element, pseudoClass, true, false); return(counterafter == 0 && counterbefore == 0); } //E:only-of-type an E element, only sibling of its type Structural pseudo-classes 3 else if (pseudoClass.matchText == "only-of-type") { int counterbefore = _getSilbingCount(element, pseudoClass, false, true); int counterafter = _getSilbingCount(element, pseudoClass, true, true); return(counterafter == 0 && counterbefore == 0); } // E:empty an E element that has no children (including text nodes) Structural pseudo-classes 3 else if (pseudoClass.matchText == "empty") { return(element.childNodes.length == 0); } //E:link //E:visited an E element being the source anchor of a hyperlink of which the target is not yet visited (:link) or already visited (:visited) The link pseudo-classes 1 //E:active //E:hover //E:focus an E element during certain user actions The user action pseudo-classes 1 and 2 //E:enabled //E:disabled a user interface element E which is enabled or disabled The UI element states pseudo-classes 3 //E:checked a user interface element E which is checked (for instance a radio-button or checkbox) The UI element states pseudo-classes 3 else if (pseudoClass.matchText.isOneOf("active", "hover", "focus")) { return(true); } else if (pseudoClass.matchText.isOneOf("link", "visited")) { return(element.tagName == "a" || element.tagName == "area"); } else if (pseudoClass.matchText.isOneOf("enabled", "disabled")) { return(true); } else if (pseudoClass.matchText == "checked") { return(element.tagName == "input"); } //E:target an E element being the target of the referring URI The target pseudo-class 3 else if (pseudoClass.matchText == "target") { // Not supported. return(true); } //E:lang(fr) an element of type E in language "fr" (the document language specifies how language is determined) The :lang() pseudo-class 2 else if (pseudoClass.matchText.StartsWith("lang")) { /// not supported, always return true because we do not know when the language will be switched. has to assume it will match. return(true); } else { //Unrecognized syntax. return(false); } }