Skip to content

Commit de8a03a

Browse files
committed
Support table columns with percentage width #206
1 parent 61a7c64 commit de8a03a

File tree

2 files changed

+75
-7
lines changed

2 files changed

+75
-7
lines changed

src/Html2OpenXml/Expressions/Table/TableColExpression.cs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,33 @@ namespace HtmlToOpenXml.Expressions;
2323
/// </summary>
2424
sealed class TableColExpression(IHtmlTableColumnElement node) : TableElementExpressionBase(node)
2525
{
26+
private const int MaxTablePortraitWidth = 9622;
27+
private const int MaxTableLandscapeWidth = 12996;
2628
private readonly IHtmlTableColumnElement colNode = node;
29+
private double? percentWidth;
2730

2831

2932
/// <inheritdoc/>
30-
public override IEnumerable<OpenXmlElement> Interpret (ParsingContext context)
33+
public override IEnumerable<OpenXmlElement> Interpret(ParsingContext context)
3134
{
3235
ComposeStyles(context);
3336

3437
var column = new GridColumn();
3538
var width = styleAttributes!.GetUnit("width");
36-
if (width.IsValid && width.IsFixed)
39+
if (width.IsValid)
3740
{
38-
// This value is specified in twentieths of a point.
39-
// If this attribute is omitted, then the last saved width of the grid column is assumed to be zero.
40-
column.Width = Math.Round( width.ValueInPoint * 20 ).ToString(CultureInfo.InvariantCulture);
41+
if (width.IsFixed)
42+
{
43+
// This value is specified in twentieths of a point.
44+
// If this attribute is omitted, then the last saved width of the grid column is assumed to be zero.
45+
column.Width = Math.Round(width.ValueInPoint * 20).ToString(CultureInfo.InvariantCulture);
46+
}
47+
else if (width.Type == UnitMetric.Percent)
48+
{
49+
var maxWidth = context.IsLandscape ? MaxTableLandscapeWidth : MaxTablePortraitWidth;
50+
percentWidth = Math.Max(0, Math.Min(100, width.Value));
51+
column.Width = Math.Ceiling(maxWidth / 100d * percentWidth.Value).ToString(CultureInfo.InvariantCulture);
52+
}
4153
}
4254

4355
if (colNode.Span == 0)
@@ -51,4 +63,18 @@ public override IEnumerable<OpenXmlElement> Interpret (ParsingContext context)
5163

5264
return elements;
5365
}
66+
67+
public override void CascadeStyles(OpenXmlElement element)
68+
{
69+
base.CascadeStyles(element);
70+
71+
if (percentWidth.HasValue && element is TableCell cell &&
72+
cell.TableCellProperties?.TableCellWidth is null)
73+
{
74+
cell.TableCellProperties!.TableCellWidth = new() {
75+
Type = TableWidthUnitValues.Pct,
76+
Width = ((int) (percentWidth.Value * 50)).ToString(CultureInfo.InvariantCulture)
77+
};
78+
}
79+
}
5480
}

test/HtmlToOpenXml.Tests/TableTests.cs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ public void Colstyle_ReturnsStyleAppliedOnCell()
522522
Assert.Multiple(() =>
523523
{
524524
Assert.That(columns.Count(), Is.EqualTo(2));
525-
//Assert.That(columns.First().Width?.Value, Is.EqualTo("1500"));
526-
//Assert.That(columns.Last().Width?.Value, Is.EqualTo("750"));
525+
Assert.That(columns.First().Width?.Value, Is.EqualTo("1500"));
526+
Assert.That(columns.Last().Width?.Value, Is.EqualTo("750"));
527527
});
528528

529529
var cells = elements[0].GetFirstChild<TableRow>()?.Elements<TableCell>();
@@ -683,5 +683,47 @@ public void Width_ReturnsRefineTableWidth(string width, string expectedUnit, str
683683
Assert.That(tableWidth?.Width?.Value, Is.EqualTo(expectedValue));
684684
});
685685
}
686+
687+
public void ColWithPercentWidth_ReturnsRefineTableWidth()
688+
{
689+
var elements = converter.Parse(@"<table style='width: 75%'>
690+
<colgroup><col style='width: 13.185%;'><col style='width: 86.9293%;'></colgroup>
691+
<tbody>
692+
<tr>
693+
<td>Cell 1</td>
694+
<td>Cell 2</td>
695+
</tr>
696+
</tbody>
697+
</table>");
698+
699+
Assert.That(elements, Has.Count.EqualTo(1));
700+
Assert.That(elements, Has.All.TypeOf<Table>());
701+
var tableWidth = elements[0].GetFirstChild<TableProperties>()?.TableWidth;
702+
Assert.That(tableWidth, Is.Not.Null);
703+
Assert.Multiple(() =>
704+
{
705+
Assert.That(tableWidth?.Type?.Value, Is.EqualTo(TableWidthUnitValues.Pct));
706+
Assert.That(tableWidth?.Width?.Value, Is.EqualTo("3750"));
707+
});
708+
709+
var columns = elements[0].GetFirstChild<TableGrid>()?.Elements<GridColumn>();
710+
Assert.That(columns, Is.Not.Null);
711+
Assert.Multiple(() =>
712+
{
713+
Assert.That(columns.Count(), Is.EqualTo(2));
714+
Assert.That(columns.First().Width?.Value, Is.EqualTo("1269"));
715+
Assert.That(columns.Last().Width?.Value, Is.EqualTo("8365"));
716+
});
717+
718+
var cells = elements[0].GetFirstChild<TableRow>()?.Elements<TableCell>();
719+
Assert.That(cells, Is.Not.Null);
720+
Assert.Multiple(() =>
721+
{
722+
Assert.That(cells.Count(), Is.EqualTo(2));
723+
// width on cell are on 5000 basis
724+
Assert.That(cells.First().TableCellProperties?.TableCellWidth?.Width?.Value, Is.EqualTo("659"));
725+
Assert.That(cells.Last().TableCellProperties?.TableCellWidth?.Width?.Value, Is.EqualTo("4346"));
726+
});
727+
}
686728
}
687729
}

0 commit comments

Comments
 (0)