internal NodeFilterResult FilterNode(Node node) { if (((uint)WhatToShow & 1 << (int)(node.NodeType - 1)) == 0) return NodeFilterResult.Skip; if (Filter != null) return Filter(node); return NodeFilterResult.Accept; }
internal NodeIterator(Node root, WhatToShow whatToShow, NodeFilter filter) { Root = root; ReferenceNode = root; PointerBeforeReferenceNode = true; WhatToShow = whatToShow; Filter = filter; }
protected override bool IsEqualNodeOverride(Node node) { var element = (Attr)node; if (NamespaceUri != element.NamespaceUri) return false; if (LocalName != element.LocalName) return false; if (Value != element.Value) return false; return true; }
protected override bool IsEqualNodeOverride(Node node) { var element = (Element)node; if (NamespaceUri != element.NamespaceUri) return false; if (Prefix != element.Prefix) return false; if (LocalName != element.LocalName) return false; if (!AttributeList.SequenceEqual(element.AttributeList)) return false; return true; }
internal void ReplaceAll(Node node) { if (node != null) OwnerDocument.AdoptNode(node); var removedNodes = new List<Node>(ChildNodes); var addedNodes = new List<Node>(); if (node is DocumentFragment) foreach (var child in node.ChildNodes) addedNodes.Add(child); else addedNodes.Add(node); while (HasChildNodes()) Remove(ChildNodes[0], true); if (node != null) Insert(node, -1, true); }
private static void SerializeHtmlFragment(Node node, StringBuilder builder) { if (node is HtmlTemplateElement template) node = template.Content; foreach (var child in node.ChildNodes) SerializeHtmlFragmentCore(child, builder); }
public Node PreviousNode() { var node = CurrentNode; while (node != Root) { var sibling = node.PreviousSibling; while (sibling != null) { node = sibling; var result = FilterNode(node); while (result != NodeFilterResult.Reject && node.HasChildNodes()) { node = node.LastChild; result = FilterNode(node); } if (result == NodeFilterResult.Accept) { CurrentNode = node; return node; } sibling = node.PreviousSibling; } if (node == Root || node.ParentNode == null) return null; node = node.ParentNode; if (FilterNode(node) == NodeFilterResult.Accept) { CurrentNode = node; return node; } } return null; }
internal Node TraverseChildren(bool firstChild) { var node = firstChild ? CurrentNode.FirstChild : CurrentNode.LastChild; while (node != null) { switch (FilterNode(node)) { case NodeFilterResult.Accept: CurrentNode = node; return node; case NodeFilterResult.Reject: while (node != null) { var sibling = firstChild ? node.NextSibling : node.PreviousSibling; if (sibling != null) { node = sibling; break; } node = node.ParentNode; if (node == null || node == Root || node == CurrentNode) return null; } break; case NodeFilterResult.Skip: break; } } return null; }
internal TreeWalker(Node root, WhatToShow whatToShow, NodeFilter filter) { Root = root; WhatToShow = whatToShow; Filter = filter; }
public Node ReplaceChild(Node node, Node child) { throw new NotImplementedException(); }
public abstract Node SetNamedItemNS(Node arg);
private static void CreateElement(InlineCollection parent, Node node, RichTextBlockStatus status) { switch (node) { case Element element: switch (element.TagName.ToLower()) { case "a": { // We want to change BaseUri easily, so we use `GetAttribute("href")` instead of `HtmlAnchorElement.Href` var href = element.GetAttribute("href"); if (!status.TryCreateUri(href, out var uri)) break; parent.Add(new Run() { Text = " " }); var hyperlink = new Hyperlink() { NavigateUri = uri, Foreground = status.Foreground }; foreach (var child in element.ChildNodes) { switch (child) { case HtmlImageElement childElement: if (CreateImage(element, status) is Image image) { if (hyperlink.Inlines.Count != 0) { hyperlink.SetUri(href); status.Hyperlinks.Add(hyperlink); parent.Add(hyperlink); } var button = new HyperlinkButton() { NavigateUri = uri, Content = image, RequestedTheme = status.RequestedTheme }; button.SetUri(href); status.HyperlinkButtons.Add(button); parent.Add(new InlineUIContainer() { Child = button }); hyperlink = new Hyperlink() { NavigateUri = uri, Foreground = status.Foreground }; } break; default: CreateElement(hyperlink.Inlines, child, status); break; } break; } if (hyperlink.Inlines.Count != 0) { hyperlink.SetUri(href); status.Hyperlinks.Add(hyperlink); parent.Add(hyperlink); } parent.Add(new Run() { Text = " " }); } break; case "img": { if (CreateImage(element, status) is Image image) parent.Add(new InlineUIContainer() { Child = image }); } break; case "strong": case "b": { var span = new Span() { FontWeight = FontWeights.Bold }; CreateChildren(span.Inlines, element, status); parent.Add(span); } break; case "div": case "font": case "p": case "span": { var span = new Span(); foreach (var s in ParseStyle(element.GetAttribute("style"))) switch (s.Key) { case "font-size": { var value = s.Value; double fontSize; if (value.EndsWith("px")) fontSize = double.Parse(value.Remove(value.Length - 2)); else if (value.EndsWith("%")) fontSize = 14 * double.Parse(value.Remove(value.Length - 1)) / 100; else fontSize = 14 * double.Parse(value); span.FontSize = fontSize; } break; case "font-weight": switch (s.Value) { case "bold": span.FontWeight = FontWeights.Bold; break; } break; } CreateChildren(span.Inlines, element, status); parent.Add(span); } break; case "br": if (element.NextSibling is Text nextText && nextText.Data.StartsWith("\n")) break; parent.Add(new LineBreak()); break; case "hr": parent.Add(new LineBreak()); var line = new Border() { BorderThickness = new Thickness(0, 1, 0, 0), BorderBrush = status.Foreground, Margin = new Thickness(8, 0, 8, 0), Height = 1, }; if (status.ActualWidth > 16) line.Width = status.ActualWidth - 16; status.Lines.Add(line); parent.Add(new InlineUIContainer() { Child = line }); parent.Add(new LineBreak()); break; case "iframe": // Ignore case "script": case "noscript": break; #if DEBUG default: Debug.WriteLine($"Ignore unknown tag {element.TagName}"); break; #endif } break; case Text text: parent.Add(new Run() { Text = text.Data }); break; } }
protected override bool IsEqualNodeOverride(Node other) => Data == ((Text)other).Data;
public ParentNodeImplementation(Node owner) { Owner = owner; Children = new LazyHtmlCollection(owner.ChildNodes); }
public Node InsertBefore(Node node, Node child) { switch (NodeType) { case NodeType.Document: case NodeType.DocumentFragment: case NodeType.Element: break; default: throw new DomException(DomExceptionCode.HierarchyRequestError); } var parent = this; do { if (node == parent) throw new DomException(DomExceptionCode.HierarchyRequestError); } while ((parent = parent.ParentNode) != null); if (child != null && child.ParentNode != this) throw new DomException(DomExceptionCode.NotFoundError); switch (node.NodeType) { case NodeType.DocumentFragment: if (NodeType == NodeType.Document) { var fragment = (DocumentFragment)node; if (fragment.ChildElementCount > 1) throw new DomException(DomExceptionCode.HierarchyRequestError); foreach (var item in fragment.ChildNodes) if (item.NodeType == NodeType.Text) throw new DomException(DomExceptionCode.HierarchyRequestError); if (fragment.ChildElementCount == 1) { if (OwnerDocument.ChildElementCount != 0) throw new DomException(DomExceptionCode.HierarchyRequestError); if (child?.NodeType == NodeType.DocumentType) throw new DomException(DomExceptionCode.HierarchyRequestError); if (child != null) { var iterator = OwnerDocument.CreateNodeIterator(child); Node next; while ((next = iterator.NextNode()) != null) if (next.NodeType == NodeType.DocumentType) throw new DomException(DomExceptionCode.HierarchyRequestError); } } } break; case NodeType.DocumentType: if (NodeType != NodeType.Document) throw new DomException(DomExceptionCode.HierarchyRequestError); var hasElement = false; foreach (var item in ChildNodes) { if (item.NodeType == NodeType.DocumentType) throw new DomException(DomExceptionCode.HierarchyRequestError); if (item.NodeType == NodeType.Element) hasElement = true; if (item == child && hasElement) throw new DomException(DomExceptionCode.HierarchyRequestError); } if (child == null && hasElement) throw new DomException(DomExceptionCode.HierarchyRequestError); break; case NodeType.Element: if (NodeType == NodeType.Document) { if (OwnerDocument.ChildElementCount != 0) throw new DomException(DomExceptionCode.HierarchyRequestError); if (child?.NodeType == NodeType.DocumentType) throw new DomException(DomExceptionCode.HierarchyRequestError); if (child != null) { var iterator = OwnerDocument.CreateNodeIterator(child); Node next; while ((next = iterator.NextNode()) != null) if (next.NodeType == NodeType.DocumentType) throw new DomException(DomExceptionCode.HierarchyRequestError); } } break; case NodeType.Text: if (NodeType == NodeType.Document) throw new DomException(DomExceptionCode.HierarchyRequestError); break; case NodeType.ProcessingInstruction: case NodeType.Comment: break; default: throw new DomException(DomExceptionCode.HierarchyRequestError); } if (child == node) child = node.NextSibling; OwnerDocument.AdoptNode(node); Insert(node, ChildNodes.IndexOf(child)); return node; }
public Node AppendChild(Node node) => InsertBefore(node, null);
protected virtual bool IsEqualNodeOverride(Node node) => true;
public Node RemoveChild(Node child) { if (child.ParentNode != this) throw new DomException(DomExceptionCode.NotFoundError); Remove(child); return child; }
/// <summary> /// Returns whether node and other have the same properties. /// </summary> /// <param name="node">The other node.</param> /// <returns></returns> public bool IsEqualNode(Node node) { if (ReferenceEquals(node, null)) return false; if (ReferenceEquals(this, node)) return true; if (NodeType != node.NodeType) return false; if (!IsEqualNodeOverride(node)) return false; if (ChildNodes.Length != node.ChildNodes.Length) return false; if (!ChildNodes.SequenceEqual(node.ChildNodes)) return false; return true; }
public Node ParentNode() { if (CurrentNode != Root) { var node = CurrentNode.ParentNode; if (node != null && FilterNode(node) == NodeFilterResult.Accept) { CurrentNode = node; return node; } } return null; }
/// <summary> /// Returns a bitmask indicating the position of other relative to node. /// </summary> /// <param name="other">The other node.</param> /// <returns></returns> public DocumentPosition CompareDocumentPosition(Node other) { throw new NotImplementedException(); }
internal Node TraverseSiblings(bool nextSibling) { var node = CurrentNode; if (node == Root) return null; while (true) { var sibling = nextSibling ? node.NextSibling : node.PreviousSibling; while (sibling != null) { node = sibling; var result = FilterNode(node); if (result == NodeFilterResult.Accept) { CurrentNode = node; return node; } sibling = nextSibling ? node.FirstChild : node.LastChild; if (result == NodeFilterResult.Reject || sibling == null) sibling = nextSibling ? node.NextSibling : node.PreviousSibling; } node = node.ParentNode; if (node == null || node == Root) return null; if (FilterNode(node) == NodeFilterResult.Accept) return null; } }
/// <summary> /// Returns <c>true</c> if other is an inclusive descendant of <see cref="Node"/>, and <c>fase</c> otherwise. /// </summary> /// <param name="other">The other node.</param> /// <returns><c>true</c> if other is an inclusive descendant of <see cref="Node"/>, and <c>fase</c> otherwise. </returns> public bool Contains(Node other) { if (other == null) return false; foreach (var child in ChildNodes) { if (child.IsEqualNode(other)) return true; if (child.Contains(other)) return true; } return false; }
public Node NextNode() { var node = CurrentNode; var result = NodeFilterResult.Accept; while (true) { while (result != NodeFilterResult.Reject && node.HasChildNodes()) { node = node.FirstChild; result = FilterNode(node); if (result == NodeFilterResult.Accept) { CurrentNode = node; return node; } } return null; } }
internal void Remove(Node child, bool suppressObservers = false) { var index = ChildNodes.IndexOf(child); var oldPreviousSibling = child.PreviousSibling; if (!suppressObservers) { } child.ParentNode = null; ChildNodes.RemoveAt(index); }
internal void Insert(Node node, int index, bool suppressObservers = false) { var addedNodes = new List<Node>(); if (node is DocumentFragment) { addedNodes.Capacity = node.ChildNodes.Count; while (node.HasChildNodes()) { var item = node.ChildNodes[0]; node.Remove(item, true); addedNodes.Add(item); item.ParentNode = this; if (index == -1) ChildNodes.Add(item); else ChildNodes.Insert(index++, item); } } else { addedNodes.Add(node); node.ParentNode = this; if (index == -1) ChildNodes.Add(node); else ChildNodes.Insert(index++, node); } }
private static void SerializeHtmlFragmentCore(Node node, StringBuilder builder) { switch (node) { case Element element: string tagName; if (element.NamespaceUri == HtmlElement.HtmlNamespace) tagName = element.LocalName; else tagName = element.QualifiedName; builder.EnsureCapacity(builder.Length + tagName.Length * 2 + 5); builder.Append('<').Append(tagName); foreach (var attr in element.AttributeList) builder.Append($" {attr.Name}=\"{EscapeString(attr.Value, true)}\""); builder.Append('>'); SerializeHtmlFragment(element, builder); builder.Append($"</{tagName}>"); break; case Text text: if (text.ParentNode is Element parent && parent.TagName == OneOf("style", "script", "xmp", "iframe", "noembed", "noframes")) builder.Append(text.Data); else builder.Append(EscapeString(text.Data, false)); break; case Comment comment: builder.EnsureCapacity(builder.Capacity + comment.Data.Length + 7); builder.Append("<!--").Append(comment.Data).Append("-->"); break; case ProcessingInstruction instruction: builder.EnsureCapacity(builder.Capacity + instruction.Target.Length + instruction.Data.Length + 4); builder.Append("<?").Append(instruction.Target).Append(" ").Append(instruction.Data).Append(">"); break; case DocumentType type: builder.EnsureCapacity(builder.Capacity + type.Name.Length + 11); builder.Append("<!DOCTYPE ").Append(type.Name).Append(">"); break; } }