Skip to content

Commit

Permalink
Handle standalone paragraphs nested in list that must be aligned with…
Browse files Browse the repository at this point in the history
… other list items #177
  • Loading branch information
onizet committed Nov 14, 2024
1 parent 07fae6d commit fed20de
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 11 deletions.
43 changes: 32 additions & 11 deletions src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,38 @@ public override IEnumerable<OpenXmlElement> Interpret(ParsingContext context)
var expression = new BlockElementExpression(liNode);
var childElements = expression.Interpret(context);
if (!childElements.Any()) continue;
Paragraph p = (Paragraph) childElements.First();

p.ParagraphProperties ??= new();
p.ParagraphProperties.ParagraphStyleId = GetStyleIdForListItem(context.DocumentStyle, liNode);
p.ParagraphProperties.NumberingProperties = new NumberingProperties {
NumberingLevelReference = new() { Val = level - 1 },
NumberingId = new() { Val = listContext.InstanceId }
};
if (listContext.Dir.HasValue) {
p.ParagraphProperties.BiDi = new() {
Val = OnOffValue.FromBoolean(listContext.Dir == DirectionMode.Rtl)

// ensure to filter out any non-paragraph like any nested table
var paragraphs = childElements.OfType<Paragraph>();
var listItemStyleId = GetStyleIdForListItem(context.DocumentStyle, liNode);

if (paragraphs.Any())
{
var p = paragraphs.First();
p.ParagraphProperties ??= new();
p.ParagraphProperties.ParagraphStyleId = listItemStyleId;
p.ParagraphProperties!.NumberingProperties ??= new NumberingProperties {
NumberingLevelReference = new() { Val = level - 1 },
NumberingId = new() { Val = listContext.InstanceId }
};
if (listContext.Dir.HasValue) {
p.ParagraphProperties.BiDi = new() {
Val = OnOffValue.FromBoolean(listContext.Dir == DirectionMode.Rtl)
};
}
}

// any standalone paragraphs must be aligned (indented) along its current level
foreach (var p in paragraphs.Skip(1))
{
// if this is a list item paragraph, skip it
if (p.ParagraphProperties?.NumberingProperties is not null)
continue;

p.ParagraphProperties ??= new();
p.ParagraphProperties.ParagraphStyleId ??= (ParagraphStyleId?) listItemStyleId!.CloneNode(true);
p.ParagraphProperties.Indentation = new() {
Left = (level * Indentation * 2).ToString()
};
}

Expand Down
30 changes: 30 additions & 0 deletions test/HtmlToOpenXml.Tests/NumberingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -581,5 +581,35 @@ await converter.ParseBody(@"<ol>
});
AssertThatOpenXmlDocumentIsValid();
}

[Test]
public void NestedParagraph_ReturnsIndentedItems()
{
var elements = converter.Parse(@"<ul>
<li>
<p>Paragraph text</p>
<p>Paragraph text</p>
</li>
</ul>");

Assert.That(elements, Is.Not.Empty);

var inst = mainPart.NumberingDefinitionsPart?.Numbering
.Elements<NumberingInstance>()
.SingleOrDefault();
Assert.That(inst, Is.Not.Null);
Assert.Multiple(() => {
Assert.That(elements.Last().GetFirstChild<ParagraphProperties>()?.NumberingProperties?.NumberingId,
Is.Null,
"Last paragraph is standalone and not linked to a list instance");
Assert.That(elements.Cast<Paragraph>().Select(e =>
e.ParagraphProperties?.ParagraphStyleId?.Val?.Value),
Has.All.EqualTo("ListParagraph"),
"All paragraphs use the same paragraph style");
Assert.That(elements.Last().GetFirstChild<ParagraphProperties>()?.Indentation?.Left?.Value,
Is.EqualTo("720"),
"Last standalone paragraph is aligned with the level 1");
});
}
}
}

0 comments on commit fed20de

Please sign in to comment.