CssSelectorConstructor
Class for construction for CSS selectors as specified in
http://www.w3.org/html/wg/drafts/html/master/selectors.html.
using AngleSharp.DOM;
using AngleSharp.DOM.Css;
using AngleSharp.DOM.Html;
using System;
using System.Diagnostics;
namespace AngleSharp.Parser.Css
{
[DebuggerStepThrough]
internal sealed class CssSelectorConstructor
{
private enum State
{
Data,
Attribute,
AttributeOperator,
AttributeValue,
AttributeEnd,
Class,
PseudoClass,
PseudoClassFunction,
PseudoClassFunctionEnd,
PseudoElement
}
private abstract class NthChildSelector : SimpleSelector
{
public int step;
public int offset;
public override int Specifity => 10;
}
private sealed class NthFirstChildSelector : NthChildSelector
{
public override bool Match(Element element)
{
Node parentNode = element.ParentNode;
if (parentNode == null)
return false;
int num = 1;
for (int i = 0; i < parentNode.ChildNodes.Length; i++) {
if (parentNode.ChildNodes[i] == element) {
if (step != 0)
return (num - offset) % step == 0;
return num == offset;
}
if (parentNode.ChildNodes[i] is Element)
num++;
}
return true;
}
public override string ToCss()
{
return string.Format(":{0}({1}n+{2})", new object[3] {
"nth-child",
step,
offset
});
}
}
private sealed class NthLastChildSelector : NthChildSelector
{
public override bool Match(Element element)
{
Element parentElement = element.ParentElement;
if (parentElement == null)
return false;
int num = 1;
for (int num2 = parentElement.ChildNodes.Length - 1; num2 >= 0; num2--) {
if (parentElement.ChildNodes[num2] == element) {
if (step != 0)
return (num - offset) % step == 0;
return num == offset;
}
if (parentElement.ChildNodes[num2] is Element)
num++;
}
return true;
}
public override string ToCss()
{
return string.Format(":{0}({1}n+{2})", new object[3] {
"nth-last-child",
step,
offset
});
}
}
private sealed class FirstChildSelector : SimpleSelector
{
private static FirstChildSelector instance;
public static FirstChildSelector Instance => instance ?? (instance = new FirstChildSelector());
public override int Specifity => 10;
private FirstChildSelector()
{
}
public override bool Match(Element element)
{
Node parentNode = element.ParentNode;
if (parentNode == null)
return false;
for (int i = 0; i <= parentNode.ChildNodes.Length; i++) {
if (parentNode.ChildNodes[i] == element)
return true;
if (parentNode.ChildNodes[i] is Element)
return false;
}
return false;
}
public override string ToCss()
{
return ":first-child";
}
}
private sealed class LastChildSelector : SimpleSelector
{
private static LastChildSelector instance;
public static LastChildSelector Instance => instance ?? (instance = new LastChildSelector());
public override int Specifity => 10;
private LastChildSelector()
{
}
public override bool Match(Element element)
{
Element parentElement = element.ParentElement;
if (parentElement == null)
return false;
for (int num = parentElement.ChildNodes.Length - 1; num >= 0; num--) {
if (parentElement.ChildNodes[num] == element)
return true;
if (parentElement.ChildNodes[num] is Element)
return false;
}
return false;
}
public override string ToCss()
{
return ":last-child";
}
}
private const string pseudoclass_root = "root";
private const string pseudoclass_firstoftype = "first-of-type";
private const string pseudoclass_lastoftype = "last-of-type";
private const string pseudoclass_onlychild = "only-child";
private const string pseudoclass_firstchild = "first-child";
private const string pseudoclass_lastchild = "last-child";
private const string pseudoclass_empty = "empty";
private const string pseudoclass_link = "link";
private const string pseudoclass_visited = "visited";
private const string pseudoclass_active = "active";
private const string pseudoclass_hover = "hover";
private const string pseudoclass_focus = "focus";
private const string pseudoclass_target = "target";
private const string pseudoclass_enabled = "enabled";
private const string pseudoclass_disabled = "disabled";
private const string pseudoclass_checked = "checked";
private const string pseudoclass_unchecked = "unchecked";
private const string pseudoclass_indeterminate = "indeterminate";
private const string pseudoclass_default = "default";
private const string pseudoclass_valid = "valid";
private const string pseudoclass_invalid = "invalid";
private const string pseudoclass_required = "required";
private const string pseudoclass_inrange = "in-range";
private const string pseudoclass_outofrange = "out-of-range";
private const string pseudoclass_optional = "optional";
private const string pseudoclass_readonly = "read-only";
private const string pseudoclass_readwrite = "read-write";
private const string pseudoclassfunction_dir = "dir";
private const string pseudoclassfunction_nthchild = "nth-child";
private const string pseudoclassfunction_nthlastchild = "nth-last-child";
private const string pseudoclassfunction_not = "not";
private const string pseudoclassfunction_lang = "lang";
private const string pseudoclassfunction_contains = "contains";
private const string pseudoelement_before = "before";
private const string pseudoelement_after = "after";
private const string pseudoelement_selection = "selection";
private const string pseudoelement_firstline = "first-line";
private const string pseudoelement_firstletter = "first-letter";
private static readonly string nth_child_odd = "odd";
private static readonly string nth_child_even = "even";
private static readonly string nth_child_n = "n";
private State state;
private Selector temp;
private ListSelector group;
private ComplexSelector complex;
private bool hasCombinator;
private bool ignoreErrors;
private CssCombinator combinator;
private CssSelectorConstructor nested;
private string attrName;
private string attrValue;
private string attrOp;
public bool IgnoreErrors {
get {
return ignoreErrors;
}
set {
ignoreErrors = value;
}
}
public Selector Result {
get {
if (complex != null) {
complex.ConcludeSelector(temp);
temp = complex;
}
if (group == null || group.Length == 0)
return temp ?? SimpleSelector.All;
if (temp == null && group.Length == 1)
return group[0];
if (temp != null) {
group.AppendSelector(temp);
temp = null;
}
return group;
}
}
public CssSelectorConstructor()
{
Reset();
}
public void Apply(CssToken token)
{
switch (state) {
case State.Data:
OnData(token);
break;
case State.Class:
OnClass(token);
break;
case State.Attribute:
OnAttribute(token);
break;
case State.AttributeOperator:
OnAttributeOperator(token);
break;
case State.AttributeValue:
OnAttributeValue(token);
break;
case State.AttributeEnd:
OnAttributeEnd(token);
break;
case State.PseudoClass:
OnPseudoClass(token);
break;
case State.PseudoClassFunction:
OnPseudoClassFunction(token);
break;
case State.PseudoClassFunctionEnd:
OnPseudoClassFunctionEnd(token);
break;
case State.PseudoElement:
OnPseudoElement(token);
break;
}
}
public CssSelectorConstructor Reset()
{
attrName = null;
attrValue = null;
attrOp = string.Empty;
state = State.Data;
combinator = CssCombinator.Descendent;
hasCombinator = false;
ignoreErrors = false;
temp = null;
group = null;
complex = null;
return this;
}
private void OnData(CssToken token)
{
switch (token.Type) {
case CssTokenType.SquareBracketOpen:
attrName = null;
attrValue = null;
attrOp = string.Empty;
state = State.Attribute;
break;
case CssTokenType.Colon:
state = State.PseudoClass;
break;
case CssTokenType.Hash:
Insert(SimpleSelector.Id(((CssKeywordToken)token).Data));
break;
case CssTokenType.Ident:
Insert(SimpleSelector.Type(((CssKeywordToken)token).Data));
break;
case CssTokenType.Whitespace:
Insert(CssCombinator.Descendent);
break;
case CssTokenType.Delim:
OnDelim(token);
break;
case CssTokenType.Comma:
InsertOr();
break;
default:
if (!ignoreErrors)
throw new DOMException(ErrorCode.SyntaxError);
break;
}
}
private void OnAttribute(CssToken token)
{
if (token.Type != CssTokenType.Whitespace) {
state = State.AttributeOperator;
if (token.Type == CssTokenType.Ident)
attrName = ((CssKeywordToken)token).Data;
else if (token.Type == CssTokenType.String) {
attrName = ((CssStringToken)token).Data;
} else {
if (!ignoreErrors)
throw new DOMException(ErrorCode.SyntaxError);
state = State.Data;
}
}
}
private void OnAttributeOperator(CssToken token)
{
if (token.Type != CssTokenType.Whitespace) {
state = State.AttributeValue;
if (token.Type == CssTokenType.SquareBracketClose)
OnAttributeEnd(token);
else if (token is CssMatchToken || token.Type == CssTokenType.Delim) {
attrOp = token.ToValue();
} else {
if (!ignoreErrors)
throw new DOMException(ErrorCode.SyntaxError);
state = State.AttributeEnd;
}
}
}
private void OnAttributeValue(CssToken token)
{
if (token.Type != CssTokenType.Whitespace) {
state = State.AttributeEnd;
if (token.Type == CssTokenType.Ident)
attrValue = ((CssKeywordToken)token).Data;
else if (token.Type == CssTokenType.String) {
attrValue = ((CssStringToken)token).Data;
} else if (token.Type == CssTokenType.Number) {
attrValue = ((CssNumberToken)token).Data.ToString();
} else {
if (!ignoreErrors)
throw new DOMException(ErrorCode.SyntaxError);
state = State.Data;
}
}
}
private void OnAttributeEnd(CssToken token)
{
if (token.Type != CssTokenType.Whitespace) {
state = State.Data;
if (token.Type == CssTokenType.SquareBracketClose) {
switch (attrOp) {
case "=":
Insert(SimpleSelector.AttrMatch(attrName, attrValue));
break;
case "~=":
Insert(SimpleSelector.AttrList(attrName, attrValue));
break;
case "|=":
Insert(SimpleSelector.AttrHyphen(attrName, attrValue));
break;
case "^=":
Insert(SimpleSelector.AttrBegins(attrName, attrValue));
break;
case "$=":
Insert(SimpleSelector.AttrEnds(attrName, attrValue));
break;
case "*=":
Insert(SimpleSelector.AttrContains(attrName, attrValue));
break;
case "!=":
Insert(SimpleSelector.AttrNotMatch(attrName, attrValue));
break;
default:
Insert(SimpleSelector.AttrAvailable(attrName));
break;
}
} else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
}
}
private void OnPseudoClass(CssToken token)
{
state = State.Data;
if (token.Type == CssTokenType.Colon)
state = State.PseudoElement;
else if (token.Type == CssTokenType.Function) {
attrName = ((CssKeywordToken)token).Data;
attrValue = string.Empty;
state = State.PseudoClassFunction;
if (nested != null)
nested.Reset();
} else if (token.Type == CssTokenType.Ident) {
SimpleSelector pseudoSelector = GetPseudoSelector(token);
if (pseudoSelector != null)
Insert(pseudoSelector);
else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
} else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
}
private void OnPseudoElement(CssToken token)
{
if (token.Type == CssTokenType.Ident) {
string data = ((CssKeywordToken)token).Data;
switch (data) {
case "before":
Insert(SimpleSelector.PseudoElement(MatchBefore, "before"));
break;
case "after":
Insert(SimpleSelector.PseudoElement(MatchAfter, "after"));
break;
case "selection":
Insert(SimpleSelector.PseudoElement((Element el) => true, "selection"));
break;
case "first-line":
Insert(SimpleSelector.PseudoElement(MatchFirstLine, "first-line"));
break;
case "first-letter":
Insert(SimpleSelector.PseudoElement(MatchFirstLetter, "first-letter"));
break;
default:
if (!ignoreErrors)
throw new DOMException(ErrorCode.SyntaxError);
Insert(SimpleSelector.PseudoElement((Element el) => false, data));
break;
}
} else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
}
private void OnClass(CssToken token)
{
state = State.Data;
if (token.Type == CssTokenType.Ident)
Insert(SimpleSelector.Class(((CssKeywordToken)token).Data));
else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
}
private void OnPseudoClassFunction(CssToken token)
{
if (token.Type != CssTokenType.Whitespace) {
switch (attrName) {
case "nth-child":
case "nth-last-child":
switch (token.Type) {
case CssTokenType.Ident:
case CssTokenType.Number:
case CssTokenType.Dimension:
attrValue += token.ToValue();
return;
case CssTokenType.Delim: {
char data = ((CssDelimToken)token).Data;
if (data == '+' || data == '-') {
attrValue += data;
return;
}
break;
}
}
break;
case "not":
if (nested == null)
nested = new CssSelectorConstructor();
if (token.Type != CssTokenType.RoundBracketClose || nested.state != 0) {
nested.Apply(token);
return;
}
break;
case "dir":
if (token.Type == CssTokenType.Ident)
attrValue = ((CssKeywordToken)token).Data;
state = State.PseudoClassFunctionEnd;
return;
case "lang":
if (token.Type == CssTokenType.Ident)
attrValue = ((CssKeywordToken)token).Data;
state = State.PseudoClassFunctionEnd;
return;
case "contains":
if (token.Type == CssTokenType.String)
attrValue = ((CssStringToken)token).Data;
else if (token.Type == CssTokenType.Ident) {
attrValue = ((CssKeywordToken)token).Data;
}
state = State.PseudoClassFunctionEnd;
return;
}
OnPseudoClassFunctionEnd(token);
}
}
private void OnPseudoClassFunctionEnd(CssToken token)
{
state = State.Data;
if (token.Type == CssTokenType.RoundBracketClose) {
string a;
if ((a = attrName) != null) {
if (!(a == "nth-child")) {
if (!(a == "nth-last-child")) {
if (!(a == "not")) {
if (!(a == "dir")) {
if (!(a == "lang")) {
if (a == "contains") {
string pseudoClass = string.Format("{0}({1})", new object[2] {
"contains",
attrValue
});
Insert(SimpleSelector.PseudoClass((Element el) => el.TextContent.Contains(attrValue), pseudoClass));
}
} else {
string pseudoClass2 = string.Format("{0}({1})", new object[2] {
"lang",
attrValue
});
Insert(SimpleSelector.PseudoClass((Element el) => el.Lang.StartsWith(attrValue, StringComparison.OrdinalIgnoreCase), pseudoClass2));
}
} else {
string pseudoClass3 = string.Format("{0}({1})", new object[2] {
"dir",
attrValue
});
DirectionMode dirCode = (!(attrValue == "ltr")) ? DirectionMode.Rtl : DirectionMode.Ltr;
Insert(SimpleSelector.PseudoClass((Element el) => el.Dir == dirCode, pseudoClass3));
}
} else {
Selector sel = nested.Result;
string pseudoClass4 = string.Format("{0}({1})", new object[2] {
"not",
sel.ToCss()
});
Insert(SimpleSelector.PseudoClass((Element el) => !sel.Match(el), pseudoClass4));
}
} else
Insert(GetChildSelector<NthLastChildSelector>());
} else
Insert(GetChildSelector<NthFirstChildSelector>());
}
} else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
}
private void InsertOr()
{
if (temp != null) {
if (group == null)
group = new ListSelector();
if (complex != null) {
complex.ConcludeSelector(temp);
group.AppendSelector(complex);
complex = null;
} else
group.AppendSelector(temp);
temp = null;
}
}
private void Insert(Selector selector)
{
if (temp != null) {
if (!hasCombinator) {
CompoundSelector compoundSelector = temp as CompoundSelector;
if (compoundSelector == null) {
compoundSelector = new CompoundSelector();
compoundSelector.AppendSelector(temp);
}
compoundSelector.AppendSelector(selector);
temp = compoundSelector;
} else {
if (complex == null)
complex = new ComplexSelector();
complex.AppendSelector(temp, combinator);
combinator = CssCombinator.Descendent;
hasCombinator = false;
temp = selector;
}
} else {
combinator = CssCombinator.Descendent;
hasCombinator = false;
temp = selector;
}
}
private void Insert(CssCombinator cssCombinator)
{
hasCombinator = true;
if (cssCombinator != CssCombinator.Descendent)
combinator = cssCombinator;
}
private void OnDelim(CssToken token)
{
switch (((CssDelimToken)token).Data) {
case ',':
InsertOr();
break;
case '>':
Insert(CssCombinator.Child);
break;
case '+':
Insert(CssCombinator.AdjacentSibling);
break;
case '~':
Insert(CssCombinator.Sibling);
break;
case '*':
Insert(SimpleSelector.All);
break;
case '.':
state = State.Class;
break;
default:
if (!ignoreErrors)
throw new DOMException(ErrorCode.SyntaxError);
break;
}
}
private SimpleSelector GetChildSelector<T>() where T : NthChildSelector, new
{
new NthFirstChildSelector();
T val = new T();
if (attrValue.Equals(nth_child_odd, StringComparison.OrdinalIgnoreCase)) {
val.step = 2;
val.offset = 1;
} else if (attrValue.Equals(nth_child_even, StringComparison.OrdinalIgnoreCase)) {
val.step = 2;
val.offset = 0;
} else if (!int.TryParse(attrValue, out val.offset)) {
int num = attrValue.IndexOf(nth_child_n, StringComparison.OrdinalIgnoreCase);
if (attrValue.Length > 0 && num != -1) {
string text = attrValue.Substring(0, num).Replace(" ", "");
string text2 = attrValue.Substring(num + 1).Replace(" ", "");
if (text == string.Empty || (text.Length == 1 && text[0] == '+'))
val.step = 1;
else if (text.Length == 1 && text[0] == '-') {
val.step = -1;
} else if (!int.TryParse(text, out val.step)) {
throw new DOMException(ErrorCode.SyntaxError);
}
if (text2 == string.Empty)
val.offset = 0;
else if (!int.TryParse(text2, out val.offset) && !ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
} else if (!ignoreErrors) {
throw new DOMException(ErrorCode.SyntaxError);
}
}
return val;
}
private SimpleSelector GetPseudoSelector(CssToken token)
{
switch (((CssKeywordToken)token).Data) {
case "root":
return SimpleSelector.PseudoClass((Element el) => el.OwnerDocument.DocumentElement == el, "root");
case "first-of-type":
return SimpleSelector.PseudoClass(delegate(Element el) {
Element parentElement3 = el.ParentElement;
if (parentElement3 == null)
return true;
for (int j = 0; j < parentElement3.ChildNodes.Length; j++) {
if (parentElement3.ChildNodes[j].NodeName == el.NodeName)
return parentElement3.ChildNodes[j] == el;
}
return false;
}, "first-of-type");
case "last-of-type":
return SimpleSelector.PseudoClass(delegate(Element el) {
Element parentElement = el.ParentElement;
if (parentElement == null)
return true;
for (int num = parentElement.ChildNodes.Length - 1; num >= 0; num--) {
if (parentElement.ChildNodes[num].NodeName == el.NodeName)
return parentElement.ChildNodes[num] == el;
}
return false;
}, "last-of-type");
case "only-child":
return SimpleSelector.PseudoClass(delegate(Element el) {
Element parentElement2 = el.ParentElement;
if (parentElement2 == null)
return false;
int num2 = 0;
for (int i = 0; i < parentElement2.ChildNodes.Length; i++) {
if (parentElement2.ChildNodes[i] is Element && ++num2 == 2)
return false;
}
return true;
}, "only-child");
case "first-child":
return FirstChildSelector.Instance;
case "last-child":
return LastChildSelector.Instance;
case "empty":
return SimpleSelector.PseudoClass((Element el) => el.ChildNodes.Length == 0, "empty");
case "link":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLAnchorElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return !((HTMLAnchorElement)el).IsVisited;
return false;
}
if (el is HTMLAreaElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return !((HTMLAreaElement)el).IsVisited;
return false;
}
if (el is HTMLLinkElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return !((HTMLLinkElement)el).IsVisited;
return false;
}
return false;
}, "link");
case "visited":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLAnchorElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return ((HTMLAnchorElement)el).IsVisited;
return false;
}
if (el is HTMLAreaElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return ((HTMLAreaElement)el).IsVisited;
return false;
}
if (el is HTMLLinkElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return ((HTMLLinkElement)el).IsVisited;
return false;
}
return false;
}, "visited");
case "active":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLAnchorElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return ((HTMLAnchorElement)el).IsActive;
return false;
}
if (el is HTMLAreaElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return ((HTMLAreaElement)el).IsActive;
return false;
}
if (el is HTMLLinkElement) {
if (!string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href)))
return ((HTMLLinkElement)el).IsActive;
return false;
}
if (el is HTMLButtonElement) {
if (!((HTMLButtonElement)el).Disabled)
return ((HTMLButtonElement)el).IsActive;
return false;
}
if (el is HTMLInputElement) {
HTMLInputElement hTMLInputElement2 = (HTMLInputElement)el;
if (hTMLInputElement2.Type == HTMLInputElement.InputType.Submit || hTMLInputElement2.Type == HTMLInputElement.InputType.Image || hTMLInputElement2.Type == HTMLInputElement.InputType.Reset || hTMLInputElement2.Type == HTMLInputElement.InputType.Button)
return hTMLInputElement2.IsActive;
return false;
}
if (el is HTMLMenuItemElement) {
if (string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Disabled)))
return ((HTMLMenuItemElement)el).IsActive;
return false;
}
return false;
}, "active");
case "hover":
return SimpleSelector.PseudoClass((Element el) => el.IsHovered, "hover");
case "focus":
return SimpleSelector.PseudoClass((Element el) => el.IsFocused, "focus");
case "target":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el.OwnerDocument != null)
return el.Id == el.OwnerDocument.Location.Hash;
return false;
}, "target");
case "enabled":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLAnchorElement || el is HTMLAreaElement || el is HTMLLinkElement)
return !string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Href));
if (el is HTMLButtonElement)
return !((HTMLButtonElement)el).Disabled;
if (el is HTMLInputElement)
return !((HTMLInputElement)el).Disabled;
if (el is HTMLSelectElement)
return !((HTMLSelectElement)el).Disabled;
if (el is HTMLTextAreaElement)
return !((HTMLTextAreaElement)el).Disabled;
if (el is HTMLOptionElement)
return !((HTMLOptionElement)el).Disabled;
if (el is HTMLOptGroupElement || el is HTMLMenuItemElement || el is HTMLFieldSetElement)
return string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Disabled));
return false;
}, "enabled");
case "disabled":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLButtonElement)
return ((HTMLButtonElement)el).Disabled;
if (el is HTMLInputElement)
return ((HTMLInputElement)el).Disabled;
if (el is HTMLSelectElement)
return ((HTMLSelectElement)el).Disabled;
if (el is HTMLTextAreaElement)
return ((HTMLTextAreaElement)el).Disabled;
if (el is HTMLOptionElement)
return ((HTMLOptionElement)el).Disabled;
if (el is HTMLOptGroupElement || el is HTMLMenuItemElement || el is HTMLFieldSetElement)
return !string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Disabled));
return false;
}, "disabled");
case "default":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLButtonElement) {
HTMLButtonElement hTMLButtonElement = (HTMLButtonElement)el;
HTMLFormElement form = hTMLButtonElement.Form;
if (form != null)
return true;
} else if (el is HTMLInputElement) {
HTMLInputElement hTMLInputElement3 = (HTMLInputElement)el;
if (hTMLInputElement3.Type == HTMLInputElement.InputType.Submit || hTMLInputElement3.Type == HTMLInputElement.InputType.Image) {
HTMLFormElement form2 = hTMLInputElement3.Form;
if (form2 != null)
return true;
}
} else if (el is HTMLOptionElement) {
return !string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Selected));
}
return false;
}, "default");
case "checked":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement) {
HTMLInputElement hTMLInputElement4 = (HTMLInputElement)el;
if (hTMLInputElement4.Type == HTMLInputElement.InputType.Checkbox || hTMLInputElement4.Type == HTMLInputElement.InputType.Radio)
return hTMLInputElement4.Checked;
return false;
}
if (el is HTMLMenuItemElement) {
HTMLMenuItemElement hTMLMenuItemElement2 = (HTMLMenuItemElement)el;
if (hTMLMenuItemElement2.Type == HTMLMenuItemElement.ItemType.Checkbox || hTMLMenuItemElement2.Type == HTMLMenuItemElement.ItemType.Radio)
return hTMLMenuItemElement2.Checked;
return false;
}
if (el is HTMLOptionElement)
return ((HTMLOptionElement)el).Selected;
return false;
}, "checked");
case "indeterminate":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement) {
HTMLInputElement hTMLInputElement5 = (HTMLInputElement)el;
if (hTMLInputElement5.Type == HTMLInputElement.InputType.Checkbox)
return hTMLInputElement5.Indeterminate;
return false;
}
if (el is HTMLProgressElement)
return string.IsNullOrEmpty(el.GetAttribute(AttributeNames.Value));
return false;
}, "indeterminate");
case "unchecked":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement) {
HTMLInputElement hTMLInputElement = (HTMLInputElement)el;
if (hTMLInputElement.Type == HTMLInputElement.InputType.Checkbox || hTMLInputElement.Type == HTMLInputElement.InputType.Radio)
return !hTMLInputElement.Checked;
return false;
}
if (el is HTMLMenuItemElement) {
HTMLMenuItemElement hTMLMenuItemElement = (HTMLMenuItemElement)el;
if (hTMLMenuItemElement.Type == HTMLMenuItemElement.ItemType.Checkbox || hTMLMenuItemElement.Type == HTMLMenuItemElement.ItemType.Radio)
return !hTMLMenuItemElement.Checked;
return false;
}
if (el is HTMLOptionElement)
return !((HTMLOptionElement)el).Selected;
return false;
}, "unchecked");
case "valid":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is IValidation)
return ((IValidation)el).CheckValidity();
if (el is HTMLFormElement)
return ((HTMLFormElement)el).CheckValidity();
return false;
}, "valid");
case "invalid":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is IValidation)
return !((IValidation)el).CheckValidity();
if (el is HTMLFormElement)
return !((HTMLFormElement)el).CheckValidity();
return false;
}, "invalid");
case "required":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement)
return ((HTMLInputElement)el).Required;
if (el is HTMLSelectElement)
return ((HTMLSelectElement)el).Required;
if (el is HTMLTextAreaElement)
return ((HTMLTextAreaElement)el).Required;
return false;
}, "required");
case "read-only":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement)
return !((HTMLInputElement)el).IsMutable;
if (el is HTMLTextAreaElement)
return !((HTMLTextAreaElement)el).IsMutable;
return !el.IsContentEditable;
}, "read-only");
case "read-write":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement)
return ((HTMLInputElement)el).IsMutable;
if (el is HTMLTextAreaElement)
return ((HTMLTextAreaElement)el).IsMutable;
return el.IsContentEditable;
}, "read-write");
case "in-range":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is IValidation) {
ValidityState validity = ((IValidation)el).Validity;
if (!validity.RangeOverflow)
return !validity.RangeUnderflow;
return false;
}
return false;
}, "in-range");
case "out-of-range":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is IValidation) {
ValidityState validity2 = ((IValidation)el).Validity;
if (!validity2.RangeOverflow)
return validity2.RangeUnderflow;
return true;
}
return false;
}, "out-of-range");
case "optional":
return SimpleSelector.PseudoClass(delegate(Element el) {
if (el is HTMLInputElement)
return !((HTMLInputElement)el).Required;
if (el is HTMLSelectElement)
return !((HTMLSelectElement)el).Required;
if (el is HTMLTextAreaElement)
return !((HTMLTextAreaElement)el).Required;
return false;
}, "optional");
case "before":
return SimpleSelector.PseudoClass(MatchBefore, "before");
case "after":
return SimpleSelector.PseudoClass(MatchAfter, "after");
case "first-line":
return SimpleSelector.PseudoClass(MatchFirstLine, "first-line");
case "first-letter":
return SimpleSelector.PseudoClass(MatchFirstLetter, "first-letter");
default:
return null;
}
}
private static bool MatchBefore(Element element)
{
return true;
}
private static bool MatchAfter(Element element)
{
return true;
}
private static bool MatchFirstLine(Element element)
{
return true;
}
private static bool MatchFirstLetter(Element element)
{
return true;
}
}
}