Skip to content

Commit f1e5607

Browse files
committed
Version 0.5.6
1 parent 6f684ac commit f1e5607

File tree

7 files changed

+176
-307
lines changed

7 files changed

+176
-307
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [0.5.6] - September 4, 2018:
2+
3+
* Adds partial support for `center` and a `renderNewlines` property on the `Html` widget.
4+
15
## [0.5.5] - September 4, 2018:
26

37
* Adds support for `acronym`, and `big`.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# flutter_html
22
[![pub package](https://img.shields.io/pub/v/flutter_html.svg)](https://pub.dartlang.org/packages/flutter_html)
33

4-
A Flutter widget for rendering static html tags as Flutter widgets. (Will render over 60 different html tags!)
4+
A Flutter widget for rendering static html tags as Flutter widgets. (Will render 70 different html tags!)
55

66
## Installing:
77

88
Add the following to your `pubspec.yaml` file:
99

1010
dependencies:
11-
flutter_html: ^0.5.5
11+
flutter_html: ^0.5.6
1212

1313
## Currently Supported HTML Tags:
1414

@@ -85,6 +85,7 @@ Add the following to your `pubspec.yaml` file:
8585
### Partially supported elements:
8686
> These are common elements that aren't yet fully supported, but won't be ignored and will still render.
8787
88+
* `center`
8889
* `ol`
8990
* `ul`
9091

example/main.dart

Lines changed: 122 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,129 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_html/flutter_html.dart';
33

4-
void main() {
5-
runApp(
6-
MaterialApp(
7-
home: Scaffold(
8-
body: Html(
9-
data: """
10-
<div>
11-
<h1>Demo Page</h1>
12-
<p>This is a fantastic nonexistent product that you should buy!</p>
13-
<h2>Pricing</h2>
14-
<p>Lorem ipsum <b>dolor</b> sit amet.</p>
15-
<h2>The Team</h2>
16-
<p>There isn't <i>really</i> a team...</p>
17-
<h2>Installation</h2>
18-
<p>You <u>cannot</u> install a nonexistent product!</p>
4+
void main() => runApp(new MyApp());
5+
6+
class MyApp extends StatelessWidget {
7+
// This widget is the root of your application.
8+
@override
9+
Widget build(BuildContext context) {
10+
return new MaterialApp(
11+
title: 'Flutter Demo',
12+
theme: new ThemeData(
13+
primarySwatch: Colors.blue,
14+
),
15+
home: new MyHomePage(title: 'Flutter Demo Home Page'),
16+
);
17+
}
18+
}
19+
20+
class MyHomePage extends StatefulWidget {
21+
MyHomePage({Key key, this.title}) : super(key: key);
22+
23+
final String title;
24+
25+
@override
26+
_MyHomePageState createState() => new _MyHomePageState();
27+
}
28+
29+
class _MyHomePageState extends State<MyHomePage> {
30+
@override
31+
Widget build(BuildContext context) {
32+
return new Scaffold(
33+
appBar: new AppBar(
34+
title: new Text(widget.title),
35+
),
36+
body: new Center(
37+
child: SingleChildScrollView(
38+
child: Html(
39+
data: """
40+
<div>
41+
<div id="header_set">
42+
<h1>Header 1</h1>
43+
<h2>Header 2</h2>
44+
<h3>Header 3</h3>
45+
<h4>Header 4</h4>
46+
<h5>Header 5</h5>
47+
<h6>Header 6</h6>
48+
<hr />
49+
Below hr
50+
<b>Bold</b>
51+
</div>
52+
<h1>Demo Page</h1>
53+
<p>This is a <u>fantastic</u> nonexistent product that you should really really really consider buying!</p>
54+
<a href="https://github.com">https://github.com</a><br />
55+
<br />
56+
<h2>Pricing</h2>
57+
<p>Lorem ipsum <b>dolor</b> sit amet.</p>
58+
<center>
59+
This is some center text... <abbr>ABBR</abbr> and <acronym>ACRONYM</acronym>
60+
</center>
61+
<h2>The Team</h2>
62+
<p>There isn't <i>really</i> a team...</p>
63+
<h2>Installation</h2>
64+
<p>You <u>cannot</u> install a nonexistent product!</p>
65+
<div id="bdi_test">
66+
<h3><code>bdi</code> and <code>bdo</code> Test:</h3>
67+
<p>
68+
In the example below, usernames are shown along with the number of points in a contest.
69+
If the bdi element is not supported in the browser, the username of the Arabic user would confuse the text (the bidirectional algorithm would put the colon and the number "90" next to the word "User" rather than next to the word "points").
70+
</p>
71+
72+
<ul>
73+
<li>User <bdi>hrefs</bdi>: 60 points</li>
74+
<li>User <bdi>jdoe</bdi>: 80 points</li>
75+
<li>User <bdi>إيان</bdi>: 90 points</li>
76+
<bdo dir="rtl">Swapped!</bdo>
77+
<bdo dir="ltr">This text will go left to right!</bdo>
78+
<bdo dir="rtl">With bdi: User <bdi>إيان</bdi>: 90 points</bdo>
79+
<bdo dir="rtl">Without bdi: User إيان: 90 points</bdo>
80+
<bdo dir="ltr">ltr w/ bdi: User <bdi>إيان</bdi>: 90 points</bdo>
81+
<bdo dir="ltr">ltr w/o bdi: User إيان: 90 points</bdo>
82+
</ul>
83+
</div>
84+
<div>
85+
<table>
86+
<caption>This is the table's caption</caption>
87+
<tr><th>Head 1</th><th>Head 2</th><th>Head 3</th></tr>
88+
<tr><td>Data 1</td><td>Long Data 2</td><td>Really, realllllly, long data 3</td></tr>
89+
<tr><td>Data 1</td><td>Long <b>Data</b> 2</td><td>Really, realllllly, long data 3</td></tr>
90+
<tr><td>Data 1</td><td>Long Data 2</td><td>Really, realllllly, long data 3</td></tr>
91+
<tr><td>Different 1</td><td>Different reallllllly long 2</td><td>Diff 3</td></tr>
92+
<tr><td colspan="2">This spans 2 columns</td><td>Normal td</td></tr>
93+
<tfoot>
94+
<tr><td>In foot 1</td><td>In foot 2</td><td>In foot long 2</td></tr>
95+
</tfoot>
96+
</table>
97+
</div>
98+
<div>Nested div</div>
99+
<div>
100+
<pre>
101+
jQuery("#monkey");
102+
</pre>
103+
<br />
104+
<p><q>This is a fancy quote</q></p>
105+
<br />
106+
<br />
107+
Second nested div<br />
108+
<figure>
109+
<img src="https://assets-cdn.github.com/images/modules/logos_page/GitHub-Mark.png" />
110+
<figcaption>Available on GitHub</figcaption>
111+
</figure>
112+
</div>
113+
<div>Third nested div</div>
19114
</div>
20-
""",
21-
//Optional parameters:
22-
padding: EdgeInsets.all(8.0),
23-
backgroundColor: Colors.white70,
24-
defaultTextStyle: TextStyle(fontFamily: 'serif'),
115+
<h1>Second header</h1>
116+
<h1>Third header</h1>
117+
<div>Fourth div</div>
118+
""",
119+
//Optional parameters:
120+
padding: EdgeInsets.all(8.0),
121+
onLinkTap: (url) {
122+
print("Opening $url...");
123+
},
124+
),
25125
),
26126
),
27-
),
28-
);
127+
);
128+
}
29129
}

lib/flutter_html.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ class Html extends StatelessWidget {
1111
this.backgroundColor,
1212
this.defaultTextStyle = const TextStyle(color: Colors.black),
1313
this.onLinkTap,
14+
this.renderNewlines = false,
1415
}) : super(key: key);
1516

1617
final String data;
1718
final EdgeInsetsGeometry padding;
1819
final Color backgroundColor;
1920
final TextStyle defaultTextStyle;
2021
final Function onLinkTap;
22+
final bool renderNewlines;
2123

2224
@override
2325
Widget build(BuildContext context) {
@@ -31,7 +33,11 @@ class Html extends StatelessWidget {
3133
style: defaultTextStyle,
3234
child: Wrap(
3335
alignment: WrapAlignment.start,
34-
children: HtmlParser(width: width, onLinkTap: onLinkTap).parse(data),
36+
children: HtmlParser(
37+
width: width,
38+
onLinkTap: onLinkTap,
39+
renderNewlines: renderNewlines,
40+
).parse(data),
3541
),
3642
),
3743
);

lib/html_parser.dart

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ class HtmlParser {
66
HtmlParser({
77
@required this.width,
88
this.onLinkTap,
9+
this.renderNewlines,
910
});
1011

1112
final double width;
1213
final Function onLinkTap;
14+
final bool renderNewlines;
1315

1416
static const _supportedElements = [
1517
"a",
@@ -27,6 +29,7 @@ class HtmlParser {
2729
"br",
2830
"caption",
2931
"cite",
32+
"center",
3033
"code",
3134
"data",
3235
"dd",
@@ -89,6 +92,11 @@ class HtmlParser {
8992
List<Widget> parse(String data) {
9093
List<Widget> widgetList = new List<Widget>();
9194

95+
if (renderNewlines) {
96+
print("Before: $data");
97+
data = data.replaceAll("\n", "<br />");
98+
print("After: $data");
99+
}
92100
dom.Document document = parser.parse(data);
93101
widgetList.add(_parseNode(document.body));
94102
return widgetList;
@@ -216,8 +224,7 @@ class HtmlParser {
216224
),
217225
);
218226
case "br":
219-
if (node.previousElementSibling != null &&
220-
node.previousElementSibling.localName == "br") {
227+
if (_isNotFirstBreakTag(node)) {
221228
return Container(width: width, height: 14.0);
222229
}
223230
return Container(width: width);
@@ -229,6 +236,13 @@ class HtmlParser {
229236
children: _parseNodeList(node.nodes),
230237
),
231238
);
239+
case "center":
240+
return Container(
241+
width: width,
242+
child: Wrap(
243+
children: _parseNodeList(node.nodes),
244+
alignment: WrapAlignment.center,
245+
));
232246
case "cite":
233247
return DefaultTextStyle.merge(
234248
child: Wrap(
@@ -720,4 +734,26 @@ class HtmlParser {
720734
}
721735
return stringToTrim;
722736
}
737+
738+
bool _isNotFirstBreakTag(dom.Node node) {
739+
int index = node.parentNode.nodes.indexOf(node);
740+
if (index == 0) {
741+
if (node.parentNode == null) {
742+
return false;
743+
}
744+
return _isNotFirstBreakTag(node.parentNode);
745+
} else if (node.parentNode.nodes[index - 1] is dom.Element) {
746+
if ((node.parentNode.nodes[index - 1] as dom.Element).localName == "br") {
747+
return true;
748+
}
749+
return false;
750+
} else if (node.parentNode.nodes[index - 1] is dom.Text) {
751+
if ((node.parentNode.nodes[index - 1] as dom.Text).text.trim() == "") {
752+
return _isNotFirstBreakTag(node.parentNode.nodes[index - 1]);
753+
} else {
754+
return false;
755+
}
756+
}
757+
return false;
758+
}
723759
}

0 commit comments

Comments
 (0)