diff --git a/src/Umbraco.Infrastructure/DeliveryApi/ApiRichTextElementParser.cs b/src/Umbraco.Infrastructure/DeliveryApi/ApiRichTextElementParser.cs index eed3b848eb..ceaf1b48bd 100644 --- a/src/Umbraco.Infrastructure/DeliveryApi/ApiRichTextElementParser.cs +++ b/src/Umbraco.Infrastructure/DeliveryApi/ApiRichTextElementParser.cs @@ -101,8 +101,9 @@ internal sealed class ApiRichTextElementParser : ApiRichTextParserBase, IApiRich // - non-#comment nodes // - non-#text nodes // - non-empty #text nodes + // - empty #text between inline elements (see #17037) HtmlNode[] childNodes = element.ChildNodes - .Where(c => c.Name != CommentNodeName && (c.Name != TextNodeName || string.IsNullOrWhiteSpace(c.InnerText) is false)) + .Where(c => c.Name != CommentNodeName && (c.Name != TextNodeName || c.NextSibling is not null || string.IsNullOrWhiteSpace(c.InnerText) is false)) .ToArray(); var tag = TagName(element); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/RichTextParserTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/RichTextParserTests.cs index a2522a5ecd..2a8da7acb0 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/RichTextParserTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/RichTextParserTests.cs @@ -357,6 +357,48 @@ public class RichTextParserTests : PropertyValueConverterTests Assert.IsEmpty(blockLevelBlock.Elements); } + [Test] + public void ParseElement_CanHandleWhitespaceAroundInlineElemements() + { + var parser = CreateRichTextElementParser(); + + var element = parser.Parse("

What follows from here is just a bunch of text.

") as RichTextRootElement; + Assert.IsNotNull(element); + var paragraphElement = element.Elements.Single() as RichTextGenericElement; + Assert.IsNotNull(paragraphElement); + + var childElements = paragraphElement.Elements.ToArray(); + Assert.AreEqual(7, childElements.Length); + + var childElementCounter = 0; + + void AssertNextChildElementIsText(string expectedText) + { + var textElement = childElements[childElementCounter++] as RichTextTextElement; + Assert.IsNotNull(textElement); + Assert.AreEqual(expectedText, textElement.Text); + } + + void AssertNextChildElementIsGeneric(string expectedTag, string expectedInnerText) + { + var genericElement = childElements[childElementCounter++] as RichTextGenericElement; + Assert.IsNotNull(genericElement); + Assert.AreEqual(expectedTag, genericElement.Tag); + Assert.AreEqual(1, genericElement.Elements.Count()); + var textElement = genericElement.Elements.First() as RichTextTextElement; + Assert.IsNotNull(textElement); + Assert.AreEqual(expectedInnerText, textElement.Text); + } + + AssertNextChildElementIsText("What follows from "); + AssertNextChildElementIsGeneric("strong", "here"); + AssertNextChildElementIsText(" "); + AssertNextChildElementIsGeneric("em", "is"); + AssertNextChildElementIsText(" "); + AssertNextChildElementIsGeneric("a", "just"); + AssertNextChildElementIsText(" a bunch of text."); + } + [Test] public void ParseMarkup_CanParseContentLink() {