SimpleSelector
Represents a simple selector (either a type selector, universal
selector, attribute, class, id or pseudo-class selector).
using AngleSharp.Css;
using AngleSharp.Extensions;
using System;
namespace AngleSharp.Dom.Css
{
internal sealed class SimpleSelector : CssNode, ISelector, ICssNode, IStyleFormattable
{
private readonly Predicate<IElement> _matches;
private readonly Priority _specifity;
private readonly string _code;
public static readonly SimpleSelector All = new SimpleSelector();
public Priority Specifity => _specifity;
public string Text => _code;
public SimpleSelector()
: this((IElement _) => true, Priority.Zero, Keywords.Asterisk)
{
}
public SimpleSelector(string match)
{
Predicate<IElement> matches = (IElement el) => match.Isi(el.LocalName);
this..ctor(matches, Priority.OneTag, match);
}
public SimpleSelector(Predicate<IElement> matches, Priority specifify, string code)
{
_matches = matches;
_specifity = specifify;
_code = code;
}
public static SimpleSelector PseudoElement(Predicate<IElement> action, string pseudoElement)
{
return new SimpleSelector(action, Priority.OneTag, PseudoElementNames.Separator + pseudoElement);
}
public static SimpleSelector PseudoClass(Predicate<IElement> action, string pseudoClass)
{
return new SimpleSelector(action, Priority.OneClass, PseudoClassNames.Separator + pseudoClass);
}
public static SimpleSelector Class(string match)
{
return new SimpleSelector((IElement _) => _.ClassList.Contains(match), Priority.OneClass, "." + match);
}
public static SimpleSelector Id(string match)
{
return new SimpleSelector((IElement _) => _.Id.Is(match), Priority.OneId, "#" + match);
}
public static SimpleSelector AttrAvailable(string match, string prefix = null)
{
string content = match;
if (!string.IsNullOrEmpty(prefix)) {
content = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(content);
return new SimpleSelector((IElement _) => _.HasAttribute(match), Priority.OneClass, code);
}
public static SimpleSelector AttrMatch(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "=", value.CssString());
return new SimpleSelector((IElement _) => _.GetAttribute(match).Is(value), Priority.OneClass, code);
}
public static SimpleSelector AttrNotMatch(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "!=", value.CssString());
return new SimpleSelector((IElement _) => _.GetAttribute(match) != value, Priority.OneClass, code);
}
public static SimpleSelector AttrList(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "~=", value.CssString());
Predicate<IElement> matches = Select(value, (IElement _) => (_.GetAttribute(match) ?? string.Empty).SplitSpaces().Contains(value, StringComparison.Ordinal));
return new SimpleSelector(matches, Priority.OneClass, code);
}
public static SimpleSelector AttrBegins(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "^=", value.CssString());
Predicate<IElement> matches = Select(value, (IElement _) => (_.GetAttribute(match) ?? string.Empty).StartsWith(value));
return new SimpleSelector(matches, Priority.OneClass, code);
}
public static SimpleSelector AttrEnds(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "$=", value.CssString());
Predicate<IElement> matches = Select(value, (IElement _) => (_.GetAttribute(match) ?? string.Empty).EndsWith(value));
return new SimpleSelector(matches, Priority.OneClass, code);
}
public static SimpleSelector AttrContains(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "*=", value.CssString());
Predicate<IElement> matches = Select(value, (IElement _) => (_.GetAttribute(match) ?? string.Empty).Contains(value));
return new SimpleSelector(matches, Priority.OneClass, code);
}
public static SimpleSelector AttrHyphen(string match, string value, string prefix = null)
{
string name = match;
if (!string.IsNullOrEmpty(prefix)) {
name = FormFront(prefix, match);
match = FormMatch(prefix, match);
}
string code = FormCode(name, "|=", value.CssString());
Predicate<IElement> matches = Select(value, (IElement _) => (_.GetAttribute(match) ?? string.Empty).HasHyphen(value));
return new SimpleSelector(matches, Priority.OneClass, code);
}
public static SimpleSelector Type(string match)
{
return new SimpleSelector(match);
}
public bool Match(IElement element)
{
return _matches(element);
}
public override string ToCss(IStyleFormatter formatter)
{
return Text;
}
private static Predicate<IElement> Select(string value, Predicate<IElement> predicate)
{
if (!string.IsNullOrEmpty(value))
return predicate;
return (IElement _) => false;
}
private static string FormCode(string content)
{
return "[" + content + "]";
}
private static string FormCode(string name, string op, string value)
{
string content = name + op + value;
return FormCode(content);
}
private static string FormFront(string prefix, string match)
{
return prefix + CombinatorSymbols.Pipe + match;
}
private static string FormMatch(string prefix, string match)
{
if (!prefix.Is(Keywords.Asterisk))
return prefix + PseudoClassNames.Separator + match;
return match;
}
}
}