ComplexSelector
Represents a complex selector.
One or more compound selectors separated by combinators.
using AngleSharp.DOM.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AngleSharp.DOM.Css
{
internal class ComplexSelector : Selector
{
private struct CombinatorSelector
{
public char delimiter;
public Func<Element, IEnumerable<Element>> transform;
public Selector selector;
}
private List<CombinatorSelector> selectors;
public override int Specifity {
get {
int num = 0;
for (int i = 0; i < selectors.Count; i++) {
num += selectors[i].selector.Specifity;
}
return num;
}
}
public int Length => selectors.Count;
public bool IsReady { get; set; }
public ComplexSelector()
{
selectors = new List<CombinatorSelector>();
}
public override bool Match(Element element)
{
int num = selectors.Count - 1;
if (selectors[num].selector.Match(element)) {
if (num > 0)
return MatchCascade(num - 1, element);
return true;
}
return false;
}
public ComplexSelector ConcludeSelector(Selector selector)
{
if (!IsReady) {
selectors.Add(new CombinatorSelector {
selector = selector,
transform = null
});
IsReady = true;
}
return this;
}
public ComplexSelector AppendSelector(Selector selector, CssCombinator combinator)
{
if (IsReady)
return this;
Func<Element, IEnumerable<Element>> func = null;
char delimiter;
switch (combinator) {
case CssCombinator.Child:
delimiter = '>';
func = ((Element el) => Single(el.ParentElement));
break;
case CssCombinator.AdjacentSibling:
delimiter = '+';
func = ((Element el) => Single(el.PreviousElementSibling));
break;
case CssCombinator.Descendent:
delimiter = ' ';
func = delegate(Element el) {
List<Element> list = new List<Element>();
for (Element parentElement = el.ParentElement; parentElement != null; parentElement = parentElement.ParentElement) {
list.Add(parentElement);
}
return list;
};
break;
case CssCombinator.Sibling:
delimiter = '~';
func = delegate(Element el) {
Element parentElement2 = el.ParentElement;
if (parentElement2 == null)
return new Element[0];
HTMLCollection children = parentElement2.Children;
bool flag = false;
List<Element> list2 = new List<Element>();
for (int num = children.Length - 1; num >= 0; num--) {
if (children[num] == el)
flag = true;
else if (flag) {
list2.Add(children[num]);
}
}
return list2;
};
break;
default:
return this;
}
selectors.Add(new CombinatorSelector {
selector = selector,
transform = func,
delimiter = delimiter
});
return this;
}
public ComplexSelector ClearSelectors()
{
IsReady = false;
selectors.Clear();
return this;
}
private bool MatchCascade(int pos, Element element)
{
IEnumerable<Element> enumerable = selectors[pos].transform(element);
foreach (Element item in enumerable) {
if (selectors[pos].selector.Match(item) && (pos == 0 || MatchCascade(pos - 1, item)))
return true;
}
return false;
}
private static IEnumerable<Element> Single(Element element)
{
if (element == null)
return Enumerable.Empty<Element>();
return new Element[1] {
element
};
}
public override string ToCss()
{
StringBuilder stringBuilder = new StringBuilder();
if (selectors.Count > 0) {
int num = selectors.Count - 1;
for (int i = 0; i < num; i++) {
stringBuilder.Append(selectors[i].selector.ToCss()).Append(selectors[i].delimiter);
}
stringBuilder.Append(selectors[num].selector.ToCss());
}
return stringBuilder.ToString();
}
}
}