NodeExtensions
Useful methods for node objects.
using AngleSharp.DOM;
using AngleSharp.DOM.Html;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace AngleSharp.Extensions
{
[DebuggerStepThrough]
internal static class NodeExtensions
{
public static INode GetRoot(this INode node)
{
if (node.Parent == null)
return node;
return node.Parent.GetRoot();
}
public static bool IsDescendantOf(this INode node, INode parent)
{
if (node.Parent == null)
return false;
if (object.ReferenceEquals(node.Parent, parent))
return true;
return node.Parent.IsDescendantOf(parent);
}
public static IEnumerable<INode> GetDescendantsOf(this INode parent)
{
foreach (INode childNode in parent.ChildNodes) {
yield return childNode;
foreach (INode item in childNode.GetDescendantsOf()) {
yield return item;
}
}
}
public static bool IsInclusiveDescendantOf(this INode node, INode parent)
{
if (node != parent)
return node.IsDescendantOf(parent);
return true;
}
public static bool IsAncestorOf(this INode parent, INode node)
{
return node.IsDescendantOf(parent);
}
public static IEnumerable<INode> GetAncestorsOf(this INode node)
{
while (true) {
INode parent;
node = (parent = node.Parent);
if (parent == null)
break;
yield return node;
}
}
public static bool IsInclusiveAncestorOf(this INode parent, INode node)
{
if (node != parent)
return node.IsDescendantOf(parent);
return true;
}
public static bool IsSiblingOf(this INode node, INode element)
{
if (node.Parent != null)
return node.Parent == element.Parent;
return false;
}
public static int IndexOf(this INode parent, INode node)
{
int num = 0;
foreach (INode childNode in parent.ChildNodes) {
if (object.ReferenceEquals(childNode, node))
return num;
num++;
}
return -1;
}
public static bool IsPreceding(this INode before, INode after)
{
INode parent = before.Parent;
if (parent == null)
return false;
if (parent == after)
return true;
if (parent == after.Parent)
return parent.IndexOf(before) < parent.IndexOf(after);
return parent.IsPreceding(after);
}
public static bool IsFollowing(this INode after, INode before)
{
return before.IsPreceding(after);
}
public static INode GetAssociatedHost(this INode node)
{
if (node is IDocumentFragment && node.Owner != null)
return node.Owner.All.OfType<IHtmlTemplateElement>().FirstOrDefault((IHtmlTemplateElement m) => m.Content == node);
return null;
}
public static bool IsHostIncludingInclusiveAncestor(this INode parent, INode node)
{
if (parent.IsInclusiveAncestorOf(node))
return true;
INode associatedHost = node.GetRoot().GetAssociatedHost();
if (associatedHost != null)
return parent.IsInclusiveAncestorOf(associatedHost);
return false;
}
public static void EnsurePreInsertionValidity(this INode parent, INode node, INode child)
{
if ((!(parent is IDocument) && !(parent is IDocumentFragment) && !(parent is IElement)) || node.IsHostIncludingInclusiveAncestor(parent))
throw new DomException(ErrorCode.HierarchyRequest);
if (child != null && child.Parent != parent)
throw new DomException(ErrorCode.NotFound);
if (!(node is IElement) && !(node is ICharacterData) && !(node is IDocumentType) && !(node is IDocumentFragment))
throw new DomException(ErrorCode.HierarchyRequest);
IDocument document = parent as IDocument;
if (document != null) {
bool flag = false;
switch (node.NodeType) {
case NodeType.Element:
flag = (document.DocumentElement != null || child is IDocumentType || child.IsFollowedByDoctype());
break;
case NodeType.DocumentFragment: {
int elementCount = node.GetElementCount();
flag = (elementCount > 1 || node.HasTextNodes() || (elementCount == 1 && document.DocumentElement != null) || child is IDocumentType || child.IsFollowedByDoctype());
break;
}
case NodeType.DocumentType:
flag = (document.Doctype != null || (child != null && child.IsPrecededByElement()) || (child == null && document.DocumentElement != null));
break;
case NodeType.Text:
flag = true;
break;
}
if (flag)
throw new DomException(ErrorCode.HierarchyRequest);
} else if (node is IDocumentType) {
throw new DomException(ErrorCode.HierarchyRequest);
}
}
public static INode PreInsert(this INode parent, INode node, INode child)
{
Node node2 = parent as Node;
Node node3 = node as Node;
if (node2 == null)
throw new DomException(ErrorCode.NotSupported);
parent.EnsurePreInsertionValidity(node, child);
Node node4 = child as Node;
if (node4 == node)
node4 = node3.NextSibling;
parent.Owner.AdoptNode(node);
node2.InsertBefore(node3, node4, false);
return node;
}
public static INode PreRemove(this INode parent, INode child)
{
Node node = parent as Node;
if (node == null)
throw new DomException(ErrorCode.NotSupported);
if (child.Parent != parent)
throw new DomException(ErrorCode.NotFound);
node.RemoveChild(child as Node, false);
return child;
}
public static void AdoptNode(this IDocument document, INode node)
{
Node node2 = node as Node;
if (node2 == null)
throw new DomException(ErrorCode.NotSupported);
if (node2.Parent != null)
node2.Parent.RemoveChild(node2, false);
node2.Owner = (document as Document);
}
public static bool HasTextNodes(this INode node)
{
return node.ChildNodes.OfType<IText>().Any();
}
public static bool IsFollowedByDoctype(this INode child)
{
if (child == null)
return false;
bool flag = true;
foreach (INode childNode in child.Parent.ChildNodes) {
if (flag)
flag = (childNode != child);
else if (childNode.NodeType == NodeType.DocumentType) {
return true;
}
}
return false;
}
public static bool IsPrecededByElement(this INode child)
{
foreach (INode childNode in child.Parent.ChildNodes) {
if (childNode == child)
break;
if (childNode.NodeType == NodeType.Element)
return true;
}
return false;
}
public static int GetElementCount(this INode parent)
{
int num = 0;
foreach (INode childNode in parent.ChildNodes) {
if (childNode.NodeType == NodeType.Element)
num++;
}
return num;
}
public static TNode FindChild<TNode>(this INode parent) where TNode : class, INode
{
if (parent == null)
return null;
for (int i = 0; i < parent.ChildNodes.Length; i++) {
TNode val = parent.ChildNodes[i] as TNode;
if (val != null)
return val;
}
return null;
}
public static TNode FindDescendant<TNode>(this INode parent) where TNode : class, INode
{
if (parent == null)
return null;
for (int i = 0; i < parent.ChildNodes.Length; i++) {
INode node = parent.ChildNodes[i];
TNode val = (node as TNode) ?? node.FindDescendant<TNode>();
if (val != null)
return val;
}
return null;
}
public static string ToCss(this object obj)
{
ICssObject cssObject = obj as ICssObject;
if (cssObject == null)
return string.Empty;
return cssObject.ToCss();
}
}
}