@@ -23,28 +23,68 @@ namespace HtmlToOpenXml.Expressions;
23
23
/// Process the parsing of block contents (like <c>p</c>, <c>span</c>, <c>heading</c>).
24
24
/// A block-level element always starts on a new line, and the browsers automatically add some space (a margin) before and after the element.
25
25
/// </summary>
26
- class BlockElementExpression ( IHtmlElement node , params OpenXmlLeafElement [ ] ? styleProperty ) : PhrasingElementExpression ( node )
26
+ class BlockElementExpression : PhrasingElementExpression
27
27
{
28
- private readonly OpenXmlLeafElement [ ] ? defaultStyleProperties = styleProperty ;
28
+ private readonly OpenXmlLeafElement [ ] ? defaultStyleProperties ;
29
29
protected readonly ParagraphProperties paraProperties = new ( ) ;
30
+ // some style attributes, such as borders or bgcolor, will convert this node to a framed container
31
+ protected bool renderAsFramed ;
32
+ private HtmlBorder styleBorder ;
33
+
34
+
35
+ public BlockElementExpression ( IHtmlElement node , OpenXmlLeafElement ? styleProperty ) : base ( node )
36
+ {
37
+ if ( styleProperty is not null )
38
+ defaultStyleProperties = [ styleProperty ] ;
39
+ }
40
+ public BlockElementExpression ( IHtmlElement node , params OpenXmlLeafElement [ ] ? styleProperty ) : base ( node )
41
+ {
42
+ defaultStyleProperties = styleProperty ;
43
+ }
30
44
31
45
32
46
/// <inheritdoc/>
33
47
public override IEnumerable < OpenXmlElement > Interpret ( ParsingContext context )
34
48
{
35
- var elements = base . Interpret ( context ) ;
49
+ var childElements = base . Interpret ( context ) ;
36
50
37
51
var bookmarkTarget = node . GetAttribute ( InternalNamespaceUri , "bookmark" ) ;
38
52
if ( bookmarkTarget is not null )
39
53
{
40
54
var bookmarkId = IncrementBookmarkId ( context ) . ToString ( CultureInfo . InvariantCulture ) ;
41
- var p = elements . First ( ) ;
55
+ var p = childElements . First ( ) ;
42
56
// need to be inserted after pPr to avoid schema warning
43
57
p . InsertAfter ( new BookmarkStart ( ) { Id = bookmarkId , Name = bookmarkTarget } , p . GetFirstChild < ParagraphProperties > ( ) ) ;
44
58
p . AppendChild ( new BookmarkEnd ( ) { Id = bookmarkId } ) ;
45
59
}
46
60
47
- return elements ;
61
+ if ( ! renderAsFramed )
62
+ return childElements ;
63
+
64
+ var paragraphs = childElements . OfType < Paragraph > ( ) ;
65
+ if ( ! paragraphs . Any ( ) ) return childElements ;
66
+
67
+ // if we have only 1 paragraph, just inline the styles
68
+ if ( paragraphs . Count ( ) == 1 )
69
+ {
70
+ var p = paragraphs . First ( ) ;
71
+
72
+ if ( ! styleBorder . IsEmpty && p . ParagraphProperties ? . ParagraphBorders is null )
73
+ {
74
+ p . ParagraphProperties ??= new ( ) ;
75
+ p . ParagraphProperties ! . ParagraphBorders = new ParagraphBorders {
76
+ LeftBorder = Converter . ToBorder < LeftBorder > ( styleBorder . Left ) ,
77
+ RightBorder = Converter . ToBorder < RightBorder > ( styleBorder . Right ) ,
78
+ TopBorder = Converter . ToBorder < TopBorder > ( styleBorder . Top ) ,
79
+ BottomBorder = Converter . ToBorder < BottomBorder > ( styleBorder . Bottom )
80
+ } ;
81
+ }
82
+
83
+ return childElements ;
84
+ }
85
+
86
+ // if we have 2+ paragraphs, we will embed them inside a stylised table
87
+ return [ CreateFrame ( childElements ) ] ;
48
88
}
49
89
50
90
protected override IEnumerable < OpenXmlElement > Interpret (
@@ -136,17 +176,11 @@ protected override void ComposeStyles (ParsingContext context)
136
176
}
137
177
138
178
139
- var styleBorder = styleAttributes . GetBorders ( ) ;
179
+ styleBorder = styleAttributes . GetBorders ( ) ;
140
180
if ( ! styleBorder . IsEmpty )
141
181
{
142
- var borders = new ParagraphBorders {
143
- LeftBorder = Converter . ToBorder < LeftBorder > ( styleBorder . Left ) ,
144
- RightBorder = Converter . ToBorder < RightBorder > ( styleBorder . Right ) ,
145
- TopBorder = Converter . ToBorder < TopBorder > ( styleBorder . Top ) ,
146
- BottomBorder = Converter . ToBorder < BottomBorder > ( styleBorder . Bottom )
147
- } ;
148
-
149
- paraProperties . ParagraphBorders = borders ;
182
+ renderAsFramed = true ;
183
+ runProperties . Border = null ;
150
184
}
151
185
152
186
foreach ( string className in node . ClassList )
@@ -159,8 +193,8 @@ protected override void ComposeStyles (ParsingContext context)
159
193
}
160
194
}
161
195
162
- Margin margin = styleAttributes . GetMargin ( "margin" ) ;
163
- Indentation ? indentation = null ;
196
+ var margin = styleAttributes . GetMargin ( "margin" ) ;
197
+ Indentation ? indentation = null ;
164
198
if ( ! margin . IsEmpty )
165
199
{
166
200
if ( margin . Top . IsFixed || margin . Bottom . IsFixed )
@@ -236,6 +270,9 @@ protected override void ComposeStyles (ParsingContext context)
236
270
} ;
237
271
}
238
272
}
273
+
274
+ if ( runProperties . Shading != null )
275
+ renderAsFramed = true ;
239
276
}
240
277
241
278
/// <summary>
@@ -322,6 +359,43 @@ private static Paragraph CreateParagraph(ParsingContext context, IList<OpenXmlEl
322
359
return p ;
323
360
}
324
361
362
+
363
+ /// <summary>
364
+ /// Group all the paragraph inside a framed table.
365
+ /// </summary>
366
+ private Table CreateFrame ( IEnumerable < OpenXmlElement > childElements )
367
+ {
368
+ TableCell cell ;
369
+ TableProperties tableProperties ;
370
+ Table framedTable = new (
371
+ tableProperties = new TableProperties {
372
+ TableWidth = new ( ) { Type = TableWidthUnitValues . Pct , Width = "5000" } // 100%
373
+ } ,
374
+ new TableGrid (
375
+ new GridColumn ( ) { Width = "9442" } ) ,
376
+ new TableRow (
377
+ cell = new TableCell ( childElements )
378
+ )
379
+ ) ;
380
+
381
+ if ( ! styleBorder . IsEmpty )
382
+ {
383
+ tableProperties . TableBorders = new TableBorders {
384
+ LeftBorder = Converter . ToBorder < LeftBorder > ( styleBorder . Left ) ,
385
+ RightBorder = Converter . ToBorder < RightBorder > ( styleBorder . Right ) ,
386
+ TopBorder = Converter . ToBorder < TopBorder > ( styleBorder . Top ) ,
387
+ BottomBorder = Converter . ToBorder < BottomBorder > ( styleBorder . Bottom )
388
+ } ;
389
+ }
390
+
391
+ if ( runProperties . Shading != null )
392
+ {
393
+ cell . TableCellProperties = new ( ) { Shading = ( Shading ? ) runProperties . Shading . Clone ( ) } ;
394
+ }
395
+
396
+ return framedTable ;
397
+ }
398
+
325
399
/// <summary>
326
400
/// Resolve the next available <see cref="BookmarkStart.Id"/> (they must be unique).
327
401
/// </summary>
0 commit comments