Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,21 @@
paragraphBorders.AppendChild(border);
}

// When only "left" is specified, Word anchors the border at the paragraph indent (flush
// with text) instead of at the page content edge. Adding Nil borders for the unspecified
// sides forces Word into box-mode rendering, which anchors the left border at position 0
// so that LeftIndent creates a visible gap between the border line and the text.
var specifiedPositions = new HashSet<string>(positions);
if (specifiedPositions.Contains("left"))
{
if (!specifiedPositions.Contains("top"))
paragraphBorders.AppendChild(new TopBorder { Val = BorderValues.Nil });
if (!specifiedPositions.Contains("bottom"))
paragraphBorders.AppendChild(new BottomBorder { Val = BorderValues.Nil });
if (!specifiedPositions.Contains("right"))
paragraphBorders.AppendChild(new RightBorder { Val = BorderValues.Nil });
}

return paragraphBorders;
}

Expand Down Expand Up @@ -810,7 +825,7 @@
// Adding indent equal to BorderSpace * 20 twips anchors the border at the margin boundary.
if (style.BorderSpace > 0)
{
string indentTwips = (style.BorderSpace * 20).ToString();

Check warning on line 828 in csharp-version/src/MarkdownToDocx.Core/OpenXml/OpenXmlDocumentBuilder.cs

View workflow job for this annotation

GitHub Actions / Build and Test

The behavior of 'uint.ToString()' could vary based on the current user's locale settings. Replace this call in 'OpenXmlDocumentBuilder.CreateCodeBlockParagraphProperties(CodeBlockStyle)' with a call to 'uint.ToString(IFormatProvider)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305)

Check warning on line 828 in csharp-version/src/MarkdownToDocx.Core/OpenXml/OpenXmlDocumentBuilder.cs

View workflow job for this annotation

GitHub Actions / Build and Test

The behavior of 'uint.ToString()' could vary based on the current user's locale settings. Replace this call in 'OpenXmlDocumentBuilder.CreateCodeBlockParagraphProperties(CodeBlockStyle)' with a call to 'uint.ToString(IFormatProvider)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305)
props.AppendChild(new Indentation { Left = indentTwips, Right = indentTwips });
}

Expand Down Expand Up @@ -917,7 +932,7 @@
var indentation = new Indentation { Left = style.LeftIndent };
if (hasPadding && style.PaddingSpace > 0)
{
indentation.Right = (style.PaddingSpace * 20).ToString();

Check warning on line 935 in csharp-version/src/MarkdownToDocx.Core/OpenXml/OpenXmlDocumentBuilder.cs

View workflow job for this annotation

GitHub Actions / Build and Test

The behavior of 'uint.ToString()' could vary based on the current user's locale settings. Replace this call in 'OpenXmlDocumentBuilder.CreateQuoteParagraphProperties(QuoteStyle)' with a call to 'uint.ToString(IFormatProvider)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305)

Check warning on line 935 in csharp-version/src/MarkdownToDocx.Core/OpenXml/OpenXmlDocumentBuilder.cs

View workflow job for this annotation

GitHub Actions / Build and Test

The behavior of 'uint.ToString()' could vary based on the current user's locale settings. Replace this call in 'OpenXmlDocumentBuilder.CreateQuoteParagraphProperties(QuoteStyle)' with a call to 'uint.ToString(IFormatProvider)'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1305)
}
props.AppendChild(indentation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2229,6 +2229,103 @@ public void AddHeading_WithLeftIndentAndBorderExtentText_ShouldRenderIndentation
indentation!.Left!.Value.Should().Be("400");
}

[Fact]
public void AddHeading_WithLeftBorderOnly_ShouldAddNilBordersForBoxMode()
{
// Arrange
using var builder = new OpenXmlDocumentBuilder(_stream, _horizontalProvider);
var style = CreateDefaultHeadingStyle() with
{
ShowBorder = true,
BorderPosition = "left",
BorderColor = "0066cc",
BorderSize = 24,
BorderSpace = 8,
LeftIndent = "200"
};

// Act
builder.AddHeading(3, "Section", style);
builder.Save();

// Assert: left border is Single; top/bottom/right are Nil to force box-mode rendering
_stream.Position = 0;
using var doc = WordprocessingDocument.Open(_stream, false);
var paragraph = doc.MainDocumentPart!.Document.Body!
.Descendants<Paragraph>()
.First(p => p.ParagraphProperties?.ParagraphBorders != null);

var borders = paragraph.ParagraphProperties!.ParagraphBorders!;
borders.GetFirstChild<LeftBorder>()!.Val!.Value.Should().Be(BorderValues.Single);
borders.GetFirstChild<TopBorder>()!.Val!.Value.Should().Be(BorderValues.Nil);
borders.GetFirstChild<BottomBorder>()!.Val!.Value.Should().Be(BorderValues.Nil);
borders.GetFirstChild<RightBorder>()!.Val!.Value.Should().Be(BorderValues.Nil);
}

[Fact]
public void AddHeading_WithAllFourBorders_ShouldNotAddNilBorders()
{
// Arrange
using var builder = new OpenXmlDocumentBuilder(_stream, _horizontalProvider);
var style = CreateDefaultHeadingStyle() with
{
ShowBorder = true,
BorderPosition = "left,top,right,bottom",
BorderColor = "0066cc",
BorderSize = 12,
BorderSpace = 4
};

// Act
builder.AddHeading(2, "Section", style);
builder.Save();

// Assert: all four borders are Single, none are Nil
_stream.Position = 0;
using var doc = WordprocessingDocument.Open(_stream, false);
var paragraph = doc.MainDocumentPart!.Document.Body!
.Descendants<Paragraph>()
.First(p => p.ParagraphProperties?.ParagraphBorders != null);

var borders = paragraph.ParagraphProperties!.ParagraphBorders!;
borders.GetFirstChild<LeftBorder>()!.Val!.Value.Should().Be(BorderValues.Single);
borders.GetFirstChild<TopBorder>()!.Val!.Value.Should().Be(BorderValues.Single);
borders.GetFirstChild<BottomBorder>()!.Val!.Value.Should().Be(BorderValues.Single);
borders.GetFirstChild<RightBorder>()!.Val!.Value.Should().Be(BorderValues.Single);
}

[Fact]
public void AddHeading_WithBottomBorderOnly_ShouldNotAddNilBorders()
{
// Arrange
using var builder = new OpenXmlDocumentBuilder(_stream, _horizontalProvider);
var style = CreateDefaultHeadingStyle() with
{
ShowBorder = true,
BorderPosition = "bottom",
BorderColor = "cccccc",
BorderSize = 8,
BorderSpace = 2
};

// Act
builder.AddHeading(2, "Section", style);
builder.Save();

// Assert: only bottom border exists, no Nil borders added (box-mode only applies to left)
_stream.Position = 0;
using var doc = WordprocessingDocument.Open(_stream, false);
var paragraph = doc.MainDocumentPart!.Document.Body!
.Descendants<Paragraph>()
.First(p => p.ParagraphProperties?.ParagraphBorders != null);

var borders = paragraph.ParagraphProperties!.ParagraphBorders!;
borders.GetFirstChild<BottomBorder>()!.Val!.Value.Should().Be(BorderValues.Single);
borders.GetFirstChild<LeftBorder>().Should().BeNull();
borders.GetFirstChild<TopBorder>().Should().BeNull();
borders.GetFirstChild<RightBorder>().Should().BeNull();
}

public void Dispose()
{
_stream?.Dispose();
Expand Down
Loading