void TrimNodeOnStart(HtmlText textNode) { // If we need to decode entities if (settings.DecodeEntityCharacters) { if (textNode.Slice.IndexOf('&') >= 0) { var text = textNode.Slice.ToString(); textNode.Slice = new StringSlice(EntityHelper.Unescape(text)); } } // If we don't do anything for TextNode, we can early exit if (!settings.CollapseWhitespaces) { return; } // Find the first non-transparent parent var parent = textNode.Parent; while (parent != null && (parent.Descriptor == null || parent.Descriptor.Category == ContentKind.Transparent)) { parent = parent.Parent; } if (!textNode.Slice.IsEmptyOrWhiteSpace() || (parent?.Descriptor != null && xmlNamespaceCount == 0)) { pendingTexts.Add(textNode); } else { textNode.Remove(); } }
private void TrimPendingTextNodes() { HtmlText previousTextNode = null; for (int i = 0; i < pendingTexts.Count; i++) { var textNode = pendingTexts[i]; var previousElement = textNode.PreviousSibling as HtmlElement; var nextElement = textNode.NextSibling as HtmlElement; // We can trim the heading whitespaces if: // - we don't have a previous element (either inline or parent container) // - OR the previous element (sibling or parent) is not a tag that require preserving spaces around // - OR the previous text node has already some trailing spaces if ((previousTextNode == null || previousTextNode.Slice.HasTrailingSpaces()) && (previousElement == null || textNode.Slice.IsEmptyOrWhiteSpace())) { textNode.Slice.TrimStart(); } // We can trim the traling whitespaces if: // - we don't have a next element (either inline or parent container) // - OR the next element (sibling or parent) is not a tag that require preserving spaces around if (nextElement == null && previousTextNode != null && textNode.NextSibling == null && (i + 1 >= pendingTexts.Count || pendingTexts[i + 1].Slice.StartsBySpace())) { textNode.Slice.TrimEnd(); } // If we are not in the context of a tag that doesn't accept to collapse whitespaces, // we can collapse them for this text node if (pendingTagNonCollapsibleWithSpaces == 0) { textNode.Slice.CollapseSpaces(); } // If the text node is empty, remove it from the tree if (textNode.Slice.IsEmpty()) { textNode.Remove(); } else { // Replace the previous textnode previousTextNode = textNode; } } // Trim any trailing spaces of the last known text node if we are moving to a block level if (previousTextNode != null) { previousTextNode.Slice.TrimEnd(); if (previousTextNode.Slice.IsEmpty()) { previousTextNode.Remove(); } } pendingTexts.Clear(); }
HtmlText GetTextNode(SourceLocation from) { var textNode = CurrentParent.LastChild as HtmlText; if (textNode == null) { textNode = new HtmlText() { Location = from }; CurrentParent.AppendChild(textNode); } return(textNode); }
protected override void Write(HtmlText node) { var descriptorName = node.Parent.Descriptor?.Name; var isOnlyChild = node.Parent.FirstChild == node.Parent.LastChild && node.IsFirstChild(); var newlineForText = !isOnlyChild || settings.OutputTextNodesOnNewLine; var previousNodeIsNonBreaking = node.PreviousSibling is HtmlElement e && settings.InlineTagsPreservingSpacesAround.ContainsKey(e.Descriptor?.Name ?? "null"); if (ShouldPretty(node.Parent) && newlineForText && (descriptorName == null || !settings.TagsWithNonCollapsibleWhitespaces.ContainsKey(descriptorName)) && !previousNodeIsNonBreaking) { writer.WriteLine(); this.WriteIndent(); node.Slice.TrimStart(); } base.Write(node); }
protected virtual void Write(HtmlText node) { Write(node.Slice.ToString()); }
private void TrimPendingTextNodes() { if (pendingTagNonCollapsibleWithSpaces == 0) { HtmlText previousTextNode = null; HtmlText firstTextNode = null; for (int i = 0; i < pendingTexts.Count; i++) { var textNode = pendingTexts[i]; if (firstTextNode == null) { firstTextNode = textNode; } var previousElement = textNode.PreviousSibling as HtmlElement; var nextElement = textNode.NextSibling as HtmlElement; var isPreviousElementPreservingSpace = previousElement != null && settings.InlineTagsPreservingSpacesAround.ContainsKey( previousElement.Name); var isNextElementPreservingSpace = nextElement != null && settings.InlineTagsPreservingSpacesAround.ContainsKey(nextElement .Name); // If we expect to keep one space after collapsing var isFirstText = textNode == firstTextNode; var isLastText = i + 1 == pendingTexts.Count; if (!settings.KeepOneSpaceWhenCollapsing || isFirstText || isLastText) { var isPreviousTrailing = previousTextNode != null && previousTextNode.Slice.HasTrailingSpaces(); var isNextStartsBySpace = i + 1 >= pendingTexts.Count || pendingTexts[i + 1].Slice.StartsBySpace(); // We can trim the heading whitespaces if: // - we don't have a previous element (either inline or parent container) // - OR the previous element (sibling or parent) is not a tag that require preserving spaces around // - OR the previous text node has already some trailing spaces if (!isPreviousElementPreservingSpace && (previousTextNode == null || isPreviousTrailing) && (previousElement == null || isFirstText)) { textNode.Slice.TrimStart(); } // We can trim the traling whitespaces if: // - we don't have a next element (either inline or parent container) // - OR the next element (sibling or parent) is not a tag that require preserving spaces around if (!isNextElementPreservingSpace && isNextStartsBySpace) { textNode.Slice.TrimEnd(); } } // If we are not in the context of a tag that doesn't accept to collapse whitespaces, // we can collapse them for this text node textNode.Slice.CollapseSpaces(); // If the text node is empty, remove it from the tree if (textNode.Slice.IsEmpty() || (textNode.Slice.IsEmptyOrWhiteSpace() && !isPreviousElementPreservingSpace && !isNextElementPreservingSpace)) { textNode.Remove(); if (firstTextNode == textNode) { firstTextNode = null; } } else { // Replace the previous textnode previousTextNode = textNode; } } // Trim any trailing spaces of the last known text node if we are moving to a block level if (previousTextNode != null && previousTextNode.NextSibling == null) { previousTextNode.Slice.TrimEnd(); if (previousTextNode.Slice.IsEmpty()) { previousTextNode.Remove(); } } } pendingTexts.Clear(); }
protected override void Write(HtmlText node) { Start("#txt"); base.Write(node); FlushDOM(); }