ApiExtensions
A set of useful extension methods when dealing with the DOM.
using AngleSharp.Dom;
using AngleSharp.Dom.Collections;
using AngleSharp.Dom.Css;
using AngleSharp.Dom.Events;
using AngleSharp.Dom.Html;
using AngleSharp.Html;
using AngleSharp.Network;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.Extensions
{
public static class ApiExtensions
{
public static TElement CreateElement<TElement>(this IDocument document) where TElement : IElement
{
if (document == null)
throw new ArgumentNullException("document");
Type type = (from m in PortableExtensions.GetTypes(typeof(ApiExtensions).GetAssembly())
where PortableExtensions.Implements<TElement>(m)
select m).FirstOrDefault((Type m) => !m.IsAbstractClass());
if ((object)type != null) {
foreach (ConstructorInfo item in (IEnumerable<ConstructorInfo>)(from m in PortableExtensions.GetConstructors(type)
orderby m.GetParameters().Length
select m)) {
ParameterInfo[] parameters = item.GetParameters();
object[] array = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++) {
bool flag = (object)parameters[i].ParameterType == typeof(Document);
array[i] = (flag ? document : parameters[i].DefaultValue);
}
object obj = item.Invoke(array);
if (obj != null) {
TElement val = (TElement)obj;
(val as Element)?.SetupElement();
document.Adopt((INode)(object)val);
return val;
}
}
}
throw new ArgumentException("No element could be created for the provided interface.");
}
public static async Task<Event> AwaitEventAsync<TEventTarget>(this TEventTarget node, string eventName) where TEventTarget : IEventTarget
{
if (node == null)
throw new ArgumentNullException("node");
if (eventName != null) {
TaskCompletionSource<Event> completion = new TaskCompletionSource<Event>();
DomEventHandler handler = delegate(object s, Event ev) {
completion.TrySetResult(ev);
};
node.AddEventListener(eventName, handler, false);
try {
return await completion.Task.ConfigureAwait(false);
} finally {
node.RemoveEventListener(eventName, handler, false);
}
}
throw new ArgumentNullException("eventName");
}
public static TElement AppendElement<TElement>(this INode parent, TElement element) where TElement : class, IElement
{
if (parent == null)
throw new ArgumentNullException("parent");
return parent.AppendChild(element) as TElement;
}
public static TElement InsertElement<TElement>(this INode parent, TElement newElement, INode referenceElement) where TElement : class, IElement
{
if (parent == null)
throw new ArgumentNullException("parent");
return parent.InsertBefore(newElement, referenceElement) as TElement;
}
public static TElement RemoveElement<TElement>(this INode parent, TElement element) where TElement : class, IElement
{
if (parent == null)
throw new ArgumentNullException("parent");
return parent.RemoveChild(element) as TElement;
}
public static TElement QuerySelector<TElement>(this IParentNode parent, string selectors) where TElement : class, IElement
{
if (parent == null)
throw new ArgumentNullException("parent");
if (selectors == null)
throw new ArgumentNullException("selectors");
return parent.QuerySelector(selectors) as TElement;
}
public static IEnumerable<TElement> QuerySelectorAll<TElement>(this IParentNode parent, string selectors) where TElement : IElement
{
if (parent == null)
throw new ArgumentNullException("parent");
if (selectors == null)
throw new ArgumentNullException("selectors");
return parent.QuerySelectorAll(selectors).OfType<TElement>();
}
public static IEnumerable<TNode> Descendents<TNode>(this INode parent)
{
return parent.Descendents().OfType<TNode>();
}
public static IEnumerable<INode> Descendents(this INode parent)
{
if (parent == null)
throw new ArgumentNullException("parent");
return parent.GetDescendants();
}
public static IEnumerable<TNode> Ancestors<TNode>(this INode child)
{
return child.Ancestors().OfType<TNode>();
}
public static IEnumerable<INode> Ancestors(this INode child)
{
if (child == null)
throw new ArgumentNullException("child");
return child.GetAncestors();
}
public static IHtmlFormElement SetValues(this IHtmlFormElement form, IDictionary<string, string> fields, bool createMissing = false)
{
if (form == null)
throw new ArgumentNullException("form");
if (fields == null)
throw new ArgumentNullException("fields");
IEnumerable<HtmlFormControlElement> source = form.Elements.OfType<HtmlFormControlElement>();
foreach (KeyValuePair<string, string> field in fields) {
HtmlFormControlElement targetInput = source.FirstOrDefault((HtmlFormControlElement e) => e.Name.Is(field.Key));
if (targetInput != null) {
if (targetInput is IHtmlInputElement) {
IHtmlInputElement htmlInputElement = (IHtmlInputElement)targetInput;
if (htmlInputElement.Type.Is(InputTypeNames.Radio)) {
foreach (IHtmlInputElement item in from i in source.OfType<IHtmlInputElement>()
where i.Name.Is(targetInput.Name)
select i) {
item.IsChecked = item.Value.Is(field.Value);
}
} else
htmlInputElement.Value = field.Value;
} else if (targetInput is IHtmlTextAreaElement) {
((IHtmlTextAreaElement)targetInput).Value = field.Value;
} else if (targetInput is IHtmlSelectElement) {
((IHtmlSelectElement)targetInput).Value = field.Value;
}
} else {
if (!createMissing)
throw new KeyNotFoundException($"""{new object[1] {
field.Key
}}""");
IHtmlInputElement htmlInputElement2 = form.Owner.CreateElement<IHtmlInputElement>();
htmlInputElement2.Type = InputTypeNames.Hidden;
htmlInputElement2.Name = field.Key;
htmlInputElement2.Value = field.Value;
form.AppendChild(htmlInputElement2);
}
}
return form;
}
public static Task<IDocument> < >(this TElement element) where : IUrlUtilities, IElement
{
return element.NavigateAsync(CancellationToken.None);
}
public static Task<IDocument> < >(this TElement element, CancellationToken cancel) where : IUrlUtilities, IElement
{
if (element == null)
throw new ArgumentNullException("element");
Url url = Url.Create(element.Href);
return element.Owner.Context.OpenAsync(url, cancel);
}
public static Task<IDocument> SubmitAsync(this IHtmlFormElement form, object fields)
{
return form.SubmitAsync(fields.ToDictionary(), false);
}
public static Task<IDocument> SubmitAsync(this IHtmlFormElement form, IDictionary<string, string> fields, bool createMissing = false)
{
form.SetValues(fields, createMissing);
return form.SubmitAsync();
}
public static Task<IDocument> SubmitAsync(this IHtmlElement element, object fields = null)
{
return element.SubmitAsync(fields.ToDictionary(), false);
}
public static Task<IDocument> SubmitAsync(this IHtmlElement element, IDictionary<string, string> fields, bool createMissing = false)
{
HtmlFormControlElement htmlFormControlElement = element as HtmlFormControlElement;
if (htmlFormControlElement == null)
throw new ArgumentException("element");
IHtmlFormElement form = htmlFormControlElement.Form;
if (form != null) {
form.SetValues(fields, createMissing);
return form.SubmitAsync(htmlFormControlElement);
}
return null;
}
public static T Eq<T>(this IEnumerable<T> elements, int index) where T : IElement
{
if (elements == null)
throw new ArgumentNullException("elements");
return elements.Skip(index).FirstOrDefault();
}
public static IEnumerable<T> Gt<T>(this IEnumerable<T> elements, int index) where T : IElement
{
if (elements == null)
throw new ArgumentNullException("elements");
return elements.Skip(index + 1);
}
public static IEnumerable<T> Lt<T>(this IEnumerable<T> elements, int index) where T : IElement
{
if (elements == null)
throw new ArgumentNullException("elements");
return elements.Take(index);
}
public static IEnumerable<T> Even<T>(this IEnumerable<T> elements) where T : IElement
{
if (elements == null)
throw new ArgumentNullException("elements");
bool even = true;
foreach (T element in elements) {
if (even)
yield return element;
even = !even;
}
}
public static IEnumerable<T> Odd<T>(this IEnumerable<T> elements) where T : IElement
{
if (elements == null)
throw new ArgumentNullException("elements");
bool odd = false;
foreach (T element in elements) {
if (odd)
yield return element;
odd = !odd;
}
}
public static ICssStyleDeclaration ComputeCurrentStyle(this IElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return (element.Owner?.DefaultView)?.GetComputedStyle(element, null);
}
public static T Attr<T>(this T elements, string attributeName, string attributeValue) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (attributeName == null)
throw new ArgumentNullException("attributeName");
foreach (IElement item in (IEnumerable<IElement>)elements) {
item.SetAttribute(attributeName, attributeValue);
}
return elements;
}
public static T Attr<T>(this T elements, IEnumerable<KeyValuePair<string, string>> attributes) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (attributes == null)
throw new ArgumentNullException("attributes");
foreach (IElement item in (IEnumerable<IElement>)elements) {
foreach (KeyValuePair<string, string> attribute in attributes) {
item.SetAttribute(attribute.Key, attribute.Value);
}
}
return elements;
}
public static T Attr<T>(this T elements, object attributes) where T : IEnumerable<IElement>
{
Dictionary<string, string> attributes2 = attributes.ToDictionary();
return elements.Attr(attributes2);
}
public static IEnumerable<string> Attr<T>(this T elements, string attributeName) where T : IEnumerable<IElement>
{
return from m in (IEnumerable<IElement>)(object)elements
select m.GetAttribute(attributeName);
}
public static T Empty<T>(this T elements) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
item.InnerHtml = string.Empty;
}
return elements;
}
public static T Css<T>(this T elements, string propertyName, string propertyValue) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (propertyName == null)
throw new ArgumentNullException("propertyName");
foreach (IHtmlElement item in ((IEnumerable)(object)elements).OfType<IHtmlElement>()) {
item.Style.SetProperty(propertyName, propertyValue, null);
}
return elements;
}
public static T Css<T>(this T elements, IEnumerable<KeyValuePair<string, string>> properties) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (properties == null)
throw new ArgumentNullException("properties");
foreach (IHtmlElement item in ((IEnumerable)(object)elements).OfType<IHtmlElement>()) {
foreach (KeyValuePair<string, string> property in properties) {
item.Style.SetProperty(property.Key, property.Value, null);
}
}
return elements;
}
public static T Css<T>(this T elements, object properties) where T : IEnumerable<IElement>
{
Dictionary<string, string> properties2 = properties.ToDictionary();
return elements.Css(properties2);
}
public static string Html(this IElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return element.InnerHtml;
}
public static T Html<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
item.InnerHtml = html;
}
return elements;
}
public static T AddClass<T>(this T elements, string className) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (className == null)
throw new ArgumentNullException("className");
string[] tokens = className.SplitSpaces();
foreach (IElement item in (IEnumerable<IElement>)elements) {
item.ClassList.Add(tokens);
}
return elements;
}
public static T RemoveClass<T>(this T elements, string className) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (className == null)
throw new ArgumentNullException("className");
string[] tokens = className.SplitSpaces();
foreach (IElement item in (IEnumerable<IElement>)elements) {
item.ClassList.Remove(tokens);
}
return elements;
}
public static T ToggleClass<T>(this T elements, string className) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (className == null)
throw new ArgumentNullException("className");
string[] array = className.SplitSpaces();
foreach (IElement item in (IEnumerable<IElement>)elements) {
string[] array2 = array;
foreach (string token in array2) {
item.ClassList.Toggle(token, false);
}
}
return elements;
}
public static bool HasClass(this IEnumerable<IElement> elements, string className)
{
if (elements == null)
throw new ArgumentNullException("elements");
if (className == null)
throw new ArgumentNullException("className");
string[] array = className.SplitSpaces();
foreach (IElement element in elements) {
bool flag = true;
string[] array2 = array;
foreach (string token in array2) {
if (!element.ClassList.Contains(token)) {
flag = false;
break;
}
}
if (flag)
return true;
}
return false;
}
public static T Before<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
IElement parentElement = item.ParentElement;
if (parentElement != null) {
IDocumentFragment newElement = parentElement.CreateFragment(html);
parentElement.InsertBefore(newElement, item);
}
}
return elements;
}
public static T After<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
IElement parentElement = item.ParentElement;
if (parentElement != null) {
IDocumentFragment newElement = parentElement.CreateFragment(html);
parentElement.InsertBefore(newElement, item.NextSibling);
}
}
return elements;
}
public static T Append<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
IDocumentFragment documentFragment = item.CreateFragment(html);
item.Append(documentFragment);
}
return elements;
}
public static T Prepend<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
IDocumentFragment newElement = item.CreateFragment(html);
item.InsertBefore(newElement, item.FirstChild);
}
return elements;
}
public static T Wrap<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
IDocumentFragment documentFragment = item.CreateFragment(html);
IElement innerMostElement = documentFragment.GetInnerMostElement();
item.Parent?.InsertBefore(documentFragment, item);
innerMostElement.AppendChild(item);
}
return elements;
}
public static T WrapInner<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (IElement item in (IEnumerable<IElement>)elements) {
IDocumentFragment documentFragment = item.CreateFragment(html);
IElement innerMostElement = documentFragment.GetInnerMostElement();
while (item.ChildNodes.Length > 0) {
INode child = item.ChildNodes[0];
innerMostElement.AppendChild(child);
}
item.AppendChild(documentFragment);
}
return elements;
}
public static T WrapAll<T>(this T elements, string html) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
IElement element = ((IEnumerable<IElement>)(object)elements).FirstOrDefault();
if (element != null) {
IDocumentFragment documentFragment = element.CreateFragment(html);
IElement innerMostElement = documentFragment.GetInnerMostElement();
element.Parent?.InsertBefore(documentFragment, element);
{
foreach (IElement item in (IEnumerable<IElement>)elements) {
innerMostElement.AppendChild(item);
}
return elements;
}
}
return elements;
}
public static IHtmlCollection<TElement> ToCollection<TElement>(this IEnumerable<TElement> elements) where TElement : class, IElement
{
return new HtmlCollection<TElement>(elements);
}
public static IEnumerable<IDownload> GetDownloads(this IDocument document)
{
if (document == null)
throw new ArgumentNullException("document");
return from m in document.All.OfType<ILoadableElement>()
select m.CurrentDownload into m
where m != null
select m;
}
private static IDocumentFragment CreateFromHtml(this IDocument document, string html)
{
if (document == null)
throw new ArgumentNullException("document");
Element obj = document.Body as Element;
if (obj == null)
throw new ArgumentException("The provided document does not have a valid body element.");
return new DocumentFragment(obj, html ?? string.Empty);
}
public static string Text(this INode node)
{
if (node == null)
throw new ArgumentNullException("node");
return node.TextContent;
}
public static T Text<T>(this T nodes, string text) where T : IEnumerable<INode>
{
if (nodes == null)
throw new ArgumentNullException("nodes");
foreach (INode item in (IEnumerable<INode>)nodes) {
item.TextContent = text;
}
return nodes;
}
public static int Index(this IEnumerable<INode> nodes, INode item)
{
if (nodes == null)
throw new ArgumentNullException("nodes");
if (item != null) {
int num = 0;
foreach (INode node in nodes) {
if (node == item)
return num;
num++;
}
}
return -1;
}
private static IDocumentFragment CreateFragment(this IElement context, string html)
{
Element context2 = context as Element;
string html2 = html ?? string.Empty;
return new DocumentFragment(context2, html2);
}
private static IElement GetInnerMostElement(this IDocumentFragment fragment)
{
if (fragment.ChildElementCount != 1)
throw new InvalidOperationException("The provided HTML code did not result in any element.");
IElement element = null;
IElement firstElementChild = fragment.FirstElementChild;
do {
element = firstElementChild;
firstElementChild = element.FirstElementChild;
} while (firstElementChild != null);
return element;
}
}
}