Skip to content

Commit 2931bce

Browse files
committed
Merge branch 'new-parser' of https://github.com/Sub6Resources/flutter_html into new-parser
2 parents 63f7bb0 + 1086f15 commit 2931bce

File tree

4 files changed

+162
-16
lines changed

4 files changed

+162
-16
lines changed

example/lib/main.dart

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,24 @@ const htmlData = """
4242
The quick brown fox jumped over the lazy dog.
4343
</p>
4444
<table>
45+
<colgroup>
46+
<col width="50%" />
47+
<col width="25%" />
48+
<col width="25%" />
49+
</colgroup>
50+
<thead>
4551
<tr><th>One</th><th>Two</th><th>Three</th></tr>
46-
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
47-
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
48-
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
52+
</thead>
53+
<tbody>
54+
<tr>
55+
<td>Data</td><td>Data</td><td>Data</td>
56+
</tr>
57+
<tr>
58+
<td>Data</td><td>Data</td><td>Data</td>
59+
</tr>
60+
</tbody>
4961
<tfoot>
50-
<tr><td>Data</td><td>Data</td><td>Data</td></tr>
62+
<tr><td>fData</td><td>fData</td><td>fData</td></tr>
5163
</tfoot>
5264
</table>
5365
<flutter></flutter>
@@ -113,6 +125,20 @@ class _MyHomePageState extends State<MyHomePage> {
113125
"#whitespace": Style(
114126
backgroundColor: Colors.purple,
115127
),
128+
"table": Style(
129+
backgroundColor: Color.fromARGB(0x50, 0xee, 0xee, 0xee)
130+
),
131+
"tr": Style(
132+
border: Border(bottom: BorderSide(color: Colors.grey))
133+
),
134+
"th": Style(
135+
padding: EdgeInsets.all(6),
136+
backgroundColor: Colors.grey
137+
),
138+
"td": Style(
139+
padding: EdgeInsets.all(6),
140+
backgroundColor: Colors.transparent
141+
)
116142
},
117143
customRender: {
118144
"flutter": (RenderContext context, Widget child, attributes) {

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: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_html/html_parser.dart';
3+
import 'package:flutter_html/src/html_elements.dart';
34
import 'package:flutter_html/src/styled_element.dart';
45
import 'package:flutter_html/style.dart';
56
import 'package:html/dom.dart' as dom;
@@ -19,47 +20,154 @@ abstract class LayoutElement extends StyledElement {
1920

2021
class TableLayoutElement extends LayoutElement {
2122
TableLayoutElement({
23+
String name,
24+
Style style,
25+
@required List<StyledElement> children,
26+
dom.Element node,
27+
}) : super(name: name, style: style, children: children, node: node);
28+
29+
@override
30+
Widget toWidget(RenderContext context) {
31+
32+
final colWidths = children.where((c) => c.name == "colgroup").map((group) {
33+
return group.children.where((c) => c.name == "col").map((c) {
34+
final widthStr = c.attributes["width"] ?? "";
35+
if (widthStr.endsWith("%")) {
36+
final width = double.tryParse(widthStr.substring(0, widthStr.length - 1)) * 0.01;
37+
return FractionColumnWidth(width);
38+
} else {
39+
final width = double.tryParse(widthStr);
40+
return FixedColumnWidth(width);
41+
}
42+
});
43+
}).expand((i) => i).toList().asMap();
44+
45+
return Container(
46+
decoration: BoxDecoration(
47+
color: style.backgroundColor
48+
),
49+
child: Table(
50+
columnWidths: colWidths,
51+
children: children.map((c) {
52+
if (c is TableSectionLayoutElement) {
53+
return c.toTableRows(context);
54+
}
55+
return null;
56+
})
57+
.where((t) {
58+
return t != null;
59+
})
60+
.toList()
61+
.expand((i) => i)
62+
.toList(),
63+
));
64+
}
65+
}
66+
67+
class TableSectionLayoutElement extends LayoutElement {
68+
TableSectionLayoutElement({
69+
String name,
2270
@required List<StyledElement> children,
23-
}) : super(children: children);
71+
}) : super(name: name, children: children);
2472

2573
@override
2674
Widget toWidget(RenderContext context) {
27-
return Table(
28-
// children: children.where((e) => e.name == 'tr').map(),
29-
);
75+
return Container(child: Text("TABLE SECTION"));
76+
}
77+
78+
List<TableRow> toTableRows(RenderContext context) {
79+
return children.map((c) {
80+
if (c is TableRowLayoutElement) {
81+
return c.toTableRow(context);
82+
}
83+
return null;
84+
}).where((t) {
85+
return t != null;
86+
}).toList();
3087
}
3188
}
3289

3390
class TableRowLayoutElement extends LayoutElement {
3491
TableRowLayoutElement({
92+
String name,
3593
@required List<StyledElement> children,
36-
}) : super(children: children);
94+
dom.Element node,
95+
}) : super(name: name, children: children, node: node);
3796

3897
@override
3998
Widget toWidget(RenderContext context) {
4099
return Container(child: Text("TABLE ROW"));
41100
}
42101

43102
TableRow toTableRow(RenderContext context) {
44-
103+
return TableRow(
104+
decoration: BoxDecoration(
105+
border: style.border,
106+
),
107+
children: children.map((c) {
108+
if (c is StyledElement && c.name == 'td' || c.name == 'th') {
109+
return TableCell(
110+
child: Container(
111+
padding: c.style.padding,
112+
decoration: BoxDecoration(
113+
color: c.style.backgroundColor
114+
),
115+
child: RichText(text: context.parser.parseTree(context, c))));
116+
}
117+
return null;
118+
}).where((c) => c != null).toList());
45119
}
46120
}
47121

48-
LayoutElement parseLayoutElement(dom.Element element, List<StyledElement> children) {
122+
class TableStyleElement extends StyledElement {
123+
TableStyleElement({
124+
String name,
125+
List<StyledElement> children,
126+
Style style,
127+
dom.Element node,
128+
}) : super(name: name, children: children, style: style, node: node);
129+
}
130+
131+
TableStyleElement parseTableDefinitionElement(
132+
dom.Element element, List<StyledElement> children) {
133+
switch (element.localName) {
134+
case "colgroup":
135+
case "col":
136+
return TableStyleElement(
137+
name: element.localName,
138+
children: children,
139+
node: element
140+
);
141+
default:
142+
return TableStyleElement();
143+
}
144+
}
145+
LayoutElement parseLayoutElement(
146+
dom.Element element, List<StyledElement> children) {
49147
switch (element.localName) {
50148
case "table":
51149
return TableLayoutElement(
150+
name: element.localName,
151+
children: children,
152+
node: element,
153+
);
154+
break;
155+
case "thead":
156+
case "tbody":
157+
case "tfoot":
158+
return TableSectionLayoutElement(
159+
name: element.localName,
52160
children: children,
53161
);
54162
break;
55163
case "tr":
56-
return TableLayoutElement(
164+
return TableRowLayoutElement(
165+
name: element.localName,
57166
children: children,
167+
node: element
58168
);
59169
break;
60170
default:
61-
return TableLayoutElement(
62-
children: children
63-
);
171+
return TableLayoutElement(children: children);
64172
}
65173
}

0 commit comments

Comments
 (0)