Skip to content

Commit be196a8

Browse files
committed
feat table and colgroup
1 parent 9d6e597 commit be196a8

File tree

4 files changed

+123
-12
lines changed

4 files changed

+123
-12
lines changed

example/lib/main.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,19 @@ const htmlData = """
4242
The quick brown fox jumped over the lazy dog.
4343
</p>
4444
<table>
45+
<colgroup>
46+
<col width="70%" />
47+
</colgroup>
48+
<thead>
4549
<tr><th>One</th><th>Two</th><th>Three</th></tr>
50+
</thead>
51+
<tbody>
52+
<tr><td><b>Data</b></td><td>Data</td><td>Data</td></tr>
4653
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
4754
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
48-
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
55+
</tbody>
4956
<tfoot>
50-
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
57+
<tr><td>fData</td><td>fData</td><td>fData</td></tr>
5158
</tfoot>
5259
</table>
5360
<flutter></flutter>

lib/html_parser.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class HtmlParser extends StatelessWidget {
4444
StyledElement cascadedStyledTree = _cascadeStyles(customStyledTree);
4545
StyledElement cleanedTree = cleanTree(cascadedStyledTree);
4646
InlineSpan parsedTree = parseTree(
47-
RenderContext(style: Style.fromTextStyle(Theme.of(context).textTheme.body1)),
47+
RenderContext(parser: this, style: Style.fromTextStyle(Theme.of(context).textTheme.body1)),
4848
cleanedTree,
4949
);
5050

@@ -99,6 +99,8 @@ class HtmlParser extends StatelessWidget {
9999
return parseReplacedElement(node);
100100
} else if (LAYOUT_ELEMENTS.contains(node.localName)) {
101101
return parseLayoutElement(node, children);
102+
} else if (TABLE_STYLE_ELEMENTS.contains(node.localName)) {
103+
return parseTableDefinitionElement(node, children);
102104
} else if (customRenderTags.contains(node.localName)) {
103105
return parseStyledElement(node, children);
104106
} else {
@@ -183,6 +185,7 @@ class HtmlParser extends StatelessWidget {
183185
// Merge this element's style into the context so that children
184186
// inherit the correct style
185187
RenderContext newContext = RenderContext(
188+
parser: this,
186189
style: context.style.merge(tree.style),
187190
);
188191

@@ -515,9 +518,11 @@ class HtmlParser extends StatelessWidget {
515518

516519
///TODO document better
517520
class RenderContext {
521+
final HtmlParser parser;
518522
final Style style;
519523

520524
RenderContext({
525+
this.parser,
521526
this.style,
522527
});
523528
}

lib/src/html_elements.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const STYLED_ELEMENTS = [
3333
"strong",
3434
"sub",
3535
"sup",
36+
"td",
37+
"th",
3638
"time",
3739
"tt",
3840
"u",
@@ -95,6 +97,11 @@ const LAYOUT_ELEMENTS = [
9597
"thead",
9698
];
9799

100+
const TABLE_STYLE_ELEMENTS = [
101+
"col",
102+
"colgroup"
103+
];
104+
98105
/**
99106
Here is a list of elements with planned support:
100107
a - i [x]

lib/src/layout_element.dart

Lines changed: 101 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,47 +19,139 @@ abstract class LayoutElement extends StyledElement {
1919

2020
class TableLayoutElement extends LayoutElement {
2121
TableLayoutElement({
22+
String name,
23+
Style style,
2224
@required List<StyledElement> children,
23-
}) : super(children: children);
25+
dom.Element node,
26+
}) : super(name: name, style: style, children: children, node: node);
2427

2528
@override
2629
Widget toWidget(RenderContext context) {
30+
31+
final colWidths = children.where((c) => c.name == "colgroup").map((group) {
32+
return group.children.where((c) => c.name == "col").map((c) {
33+
final widthStr = c.attributes["width"] ?? "";
34+
if (widthStr.endsWith("%")) {
35+
final width = double.tryParse(widthStr.substring(0, widthStr.length - 1)) * 0.01;
36+
return FractionColumnWidth(width);
37+
} else {
38+
final width = double.tryParse(widthStr);
39+
return FixedColumnWidth(width);
40+
}
41+
});
42+
}).expand((i) => i).toList().asMap();
43+
2744
return Table(
28-
// children: children.where((e) => e.name == 'tr').map(),
45+
columnWidths: colWidths,
46+
children: children
47+
.map((c) {
48+
if (c is TableSectionLayoutElement) {
49+
return c.toTableRows(context);
50+
}
51+
return null;
52+
})
53+
.where((t) {
54+
return t != null;
55+
})
56+
.toList()
57+
.expand((i) => i)
58+
.toList(),
2959
);
3060
}
3161
}
3262

63+
class TableSectionLayoutElement extends LayoutElement {
64+
TableSectionLayoutElement({
65+
String name,
66+
@required List<StyledElement> children,
67+
}) : super(name: name, children: children);
68+
69+
@override
70+
Widget toWidget(RenderContext context) {
71+
return Container(child: Text("TABLE SECTION"));
72+
}
73+
74+
List<TableRow> toTableRows(RenderContext context) {
75+
return children.map((c) {
76+
if (c is TableRowLayoutElement) {
77+
return c.toTableRow(context);
78+
}
79+
return null;
80+
}).where((t) {
81+
return t != null;
82+
}).toList();
83+
}
84+
}
85+
3386
class TableRowLayoutElement extends LayoutElement {
3487
TableRowLayoutElement({
88+
String name,
3589
@required List<StyledElement> children,
36-
}) : super(children: children);
90+
dom.Element node,
91+
}) : super(name: name, children: children, node: node);
3792

3893
@override
3994
Widget toWidget(RenderContext context) {
4095
return Container(child: Text("TABLE ROW"));
4196
}
4297

4398
TableRow toTableRow(RenderContext context) {
44-
99+
return TableRow(
100+
children: children.map((c) {
101+
return RichText(text: context.parser.parseTree(context, c));
102+
}).toList());
45103
}
46104
}
47105

48-
LayoutElement parseLayoutElement(dom.Element element, List<StyledElement> children) {
106+
class TableStyleElement extends StyledElement {
107+
TableStyleElement({
108+
String name,
109+
List<StyledElement> children,
110+
Style style,
111+
dom.Element node,
112+
}) : super(name: name, children: children, style: style, node: node);
113+
}
114+
115+
TableStyleElement parseTableDefinitionElement(
116+
dom.Element element, List<StyledElement> children) {
117+
switch (element.localName) {
118+
case "colgroup":
119+
case "col":
120+
return TableStyleElement(
121+
name: element.localName,
122+
children: children,
123+
node: element
124+
);
125+
default:
126+
return TableStyleElement();
127+
}
128+
}
129+
LayoutElement parseLayoutElement(
130+
dom.Element element, List<StyledElement> children) {
49131
switch (element.localName) {
50132
case "table":
51133
return TableLayoutElement(
134+
name: element.localName,
135+
children: children,
136+
node: element,
137+
);
138+
break;
139+
case "thead":
140+
case "tbody":
141+
case "tfoot":
142+
return TableSectionLayoutElement(
143+
name: element.localName,
52144
children: children,
53145
);
54146
break;
55147
case "tr":
56-
return TableLayoutElement(
148+
return TableRowLayoutElement(
149+
name: element.localName,
57150
children: children,
151+
node: element
58152
);
59153
break;
60154
default:
61-
return TableLayoutElement(
62-
children: children
63-
);
155+
return TableLayoutElement(children: children);
64156
}
65157
}

0 commit comments

Comments
 (0)