ApiExtensions
A set of useful extension methods when dealing with the DOM.
using AngleSharp.Dom;
using AngleSharp.Dom.Events;
using AngleSharp.Dom.Html;
using AngleSharp.Html;
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 m.Implements<TElement>()
select m).FirstOrDefault((Type m) => !m.IsAbstractClass());
if ((object)type == null)
return default(TElement);
ConstructorInfo[] constructors = PortableExtensions.GetConstructors(type);
foreach (ConstructorInfo item in (IEnumerable<ConstructorInfo>)(from m in constructors
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;
document.Adopt((INode)(object)val);
return val;
}
}
throw new ArgumentException("No element could be created for the provided interface.");
}
private static IDocumentFragment CreateFromHtml(this IDocument document, string html)
{
if (document == null)
throw new ArgumentNullException("document");
Element element = document.Body as Element;
if (element == null)
throw new ArgumentException("The provided document does not have a valid body element.");
return new DocumentFragment(element, html ?? string.Empty);
}
public static async Task<Event> AwaitEvent<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 async Task WhenLoadFired<TElement>(this IDocument document) where TElement : IElement
{
IEnumerable<TElement> elements = ApiExtensions.QuerySelectorAll<TElement>((IParentNode)document, "*");
Task<Event>[] tasks = Enumerable.ToArray<Task<Event>>(Enumerable.Select<TElement, Task<Event>>(elements, (Func<TElement, Task<Event>>)((TElement m) => ApiExtensions.AwaitEvent<TElement>(m, EventNames.Load))));
for (int i = 0; i < tasks.Length; i++) {
await tasks[i].ConfigureAwait(false);
}
}
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 Task<IDocument> < >(this TElement element) where : IUrlUtilities, IElement
{
return element.Navigate(CancellationToken.None);
}
public static Task<IDocument> < >(this TElement element, CancellationToken cancel) where : IUrlUtilities, IElement
{
if (element == null)
throw new ArgumentNullException("element");
string href = element.Href;
Url url = Url.Create(href);
return element.Owner.Context.OpenAsync(url, cancel);
}
public static Task<IDocument> Submit(this IHtmlFormElement form, object fields)
{
return form.Submit(fields.ToDictionary());
}
public static Task<IDocument> Submit(this IHtmlFormElement form, IDictionary<string, string> fields)
{
if (form == null)
throw new ArgumentNullException("form");
if (fields == null)
throw new ArgumentNullException("fields");
IHtmlFormControlsCollection elements = form.Elements;
foreach (IHtmlInputElement item in elements.OfType<IHtmlInputElement>()) {
string value = null;
if (fields.TryGetValue(item.Name ?? string.Empty, out value))
item.Value = value;
}
return form.Submit();
}
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 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<T>(this T element) where T : IElement
{
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<T>(this T elements, string className) where T : IEnumerable<IElement>
{
if (elements == null)
throw new ArgumentNullException("elements");
if (className == null)
throw new ArgumentNullException("className");
bool flag = false;
string[] array = className.SplitSpaces();
foreach (IElement item in (IEnumerable<IElement>)elements) {
flag = true;
string[] array2 = array;
foreach (string token in array2) {
if (!item.ClassList.Contains(token)) {
flag = false;
break;
}
}
if (flag)
return flag;
}
return flag;
}
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) {
innerMostElement.AppendChild(item.ChildNodes[0]);
}
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 string Text<T>(this T element) where T : INode
{
if (element == null)
throw new ArgumentNullException("element");
return element.TextContent;
}
public static T Text<T>(this T elements, string text) where T : IEnumerable<INode>
{
if (elements == null)
throw new ArgumentNullException("elements");
foreach (INode item in (IEnumerable<INode>)elements) {
item.TextContent = text;
}
return elements;
}
public static int Index<T>(this IEnumerable<T> elements, T item) where T : INode
{
if (elements == null)
throw new ArgumentNullException("elements");
if (item != null) {
int num = 0;
foreach (T element in elements) {
if (object.ReferenceEquals(element, item))
return num;
num++;
}
}
return -1;
}
private static IDocumentFragment CreateFragment(this IElement context, string html)
{
return new DocumentFragment(context as Element, html ?? string.Empty);
}
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;
}
}
}