Skip to content

Commit

Permalink
Version 0.5.6
Browse files Browse the repository at this point in the history
  • Loading branch information
Sub6Resources committed Sep 5, 2018
1 parent 6f684ac commit f1e5607
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 307 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [0.5.6] - September 4, 2018:

* Adds partial support for `center` and a `renderNewlines` property on the `Html` widget.

## [0.5.5] - September 4, 2018:

* Adds support for `acronym`, and `big`.
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# flutter_html
[![pub package](https://img.shields.io/pub/v/flutter_html.svg)](https://pub.dartlang.org/packages/flutter_html)

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

## Installing:

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

dependencies:
flutter_html: ^0.5.5
flutter_html: ^0.5.6

## Currently Supported HTML Tags:

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

Expand Down
144 changes: 122 additions & 22 deletions example/main.dart
Original file line number Diff line number Diff line change
@@ -1,29 +1,129 @@
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';

void main() {
runApp(
MaterialApp(
home: Scaffold(
body: Html(
data: """
<div>
<h1>Demo Page</h1>
<p>This is a fantastic nonexistent product that you should buy!</p>
<h2>Pricing</h2>
<p>Lorem ipsum <b>dolor</b> sit amet.</p>
<h2>The Team</h2>
<p>There isn't <i>really</i> a team...</p>
<h2>Installation</h2>
<p>You <u>cannot</u> install a nonexistent product!</p>
void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: SingleChildScrollView(
child: Html(
data: """
<div>
<div id="header_set">
<h1>Header 1</h1>
<h2>Header 2</h2>
<h3>Header 3</h3>
<h4>Header 4</h4>
<h5>Header 5</h5>
<h6>Header 6</h6>
<hr />
Below hr
<b>Bold</b>
</div>
<h1>Demo Page</h1>
<p>This is a <u>fantastic</u> nonexistent product that you should really really really consider buying!</p>
<a href="https://github.com">https://github.com</a><br />
<br />
<h2>Pricing</h2>
<p>Lorem ipsum <b>dolor</b> sit amet.</p>
<center>
This is some center text... <abbr>ABBR</abbr> and <acronym>ACRONYM</acronym>
</center>
<h2>The Team</h2>
<p>There isn't <i>really</i> a team...</p>
<h2>Installation</h2>
<p>You <u>cannot</u> install a nonexistent product!</p>
<div id="bdi_test">
<h3><code>bdi</code> and <code>bdo</code> Test:</h3>
<p>
In the example below, usernames are shown along with the number of points in a contest.
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").
</p>
<ul>
<li>User <bdi>hrefs</bdi>: 60 points</li>
<li>User <bdi>jdoe</bdi>: 80 points</li>
<li>User <bdi>إيان</bdi>: 90 points</li>
<bdo dir="rtl">Swapped!</bdo>
<bdo dir="ltr">This text will go left to right!</bdo>
<bdo dir="rtl">With bdi: User <bdi>إيان</bdi>: 90 points</bdo>
<bdo dir="rtl">Without bdi: User إيان: 90 points</bdo>
<bdo dir="ltr">ltr w/ bdi: User <bdi>إيان</bdi>: 90 points</bdo>
<bdo dir="ltr">ltr w/o bdi: User إيان: 90 points</bdo>
</ul>
</div>
<div>
<table>
<caption>This is the table's caption</caption>
<tr><th>Head 1</th><th>Head 2</th><th>Head 3</th></tr>
<tr><td>Data 1</td><td>Long Data 2</td><td>Really, realllllly, long data 3</td></tr>
<tr><td>Data 1</td><td>Long <b>Data</b> 2</td><td>Really, realllllly, long data 3</td></tr>
<tr><td>Data 1</td><td>Long Data 2</td><td>Really, realllllly, long data 3</td></tr>
<tr><td>Different 1</td><td>Different reallllllly long 2</td><td>Diff 3</td></tr>
<tr><td colspan="2">This spans 2 columns</td><td>Normal td</td></tr>
<tfoot>
<tr><td>In foot 1</td><td>In foot 2</td><td>In foot long 2</td></tr>
</tfoot>
</table>
</div>
<div>Nested div</div>
<div>
<pre>
jQuery("#monkey");
</pre>
<br />
<p><q>This is a fancy quote</q></p>
<br />
<br />
Second nested div<br />
<figure>
<img src="https://assets-cdn.github.com/images/modules/logos_page/GitHub-Mark.png" />
<figcaption>Available on GitHub</figcaption>
</figure>
</div>
<div>Third nested div</div>
</div>
""",
//Optional parameters:
padding: EdgeInsets.all(8.0),
backgroundColor: Colors.white70,
defaultTextStyle: TextStyle(fontFamily: 'serif'),
<h1>Second header</h1>
<h1>Third header</h1>
<div>Fourth div</div>
""",
//Optional parameters:
padding: EdgeInsets.all(8.0),
onLinkTap: (url) {
print("Opening $url...");
},
),
),
),
),
);
);
}
}
8 changes: 7 additions & 1 deletion lib/flutter_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ class Html extends StatelessWidget {
this.backgroundColor,
this.defaultTextStyle = const TextStyle(color: Colors.black),
this.onLinkTap,
this.renderNewlines = false,
}) : super(key: key);

final String data;
final EdgeInsetsGeometry padding;
final Color backgroundColor;
final TextStyle defaultTextStyle;
final Function onLinkTap;
final bool renderNewlines;

@override
Widget build(BuildContext context) {
Expand All @@ -31,7 +33,11 @@ class Html extends StatelessWidget {
style: defaultTextStyle,
child: Wrap(
alignment: WrapAlignment.start,
children: HtmlParser(width: width, onLinkTap: onLinkTap).parse(data),
children: HtmlParser(
width: width,
onLinkTap: onLinkTap,
renderNewlines: renderNewlines,
).parse(data),
),
),
);
Expand Down
40 changes: 38 additions & 2 deletions lib/html_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ class HtmlParser {
HtmlParser({
@required this.width,
this.onLinkTap,
this.renderNewlines,
});

final double width;
final Function onLinkTap;
final bool renderNewlines;

static const _supportedElements = [
"a",
Expand All @@ -27,6 +29,7 @@ class HtmlParser {
"br",
"caption",
"cite",
"center",
"code",
"data",
"dd",
Expand Down Expand Up @@ -89,6 +92,11 @@ class HtmlParser {
List<Widget> parse(String data) {
List<Widget> widgetList = new List<Widget>();

if (renderNewlines) {
print("Before: $data");
data = data.replaceAll("\n", "<br />");
print("After: $data");
}
dom.Document document = parser.parse(data);
widgetList.add(_parseNode(document.body));
return widgetList;
Expand Down Expand Up @@ -216,8 +224,7 @@ class HtmlParser {
),
);
case "br":
if (node.previousElementSibling != null &&
node.previousElementSibling.localName == "br") {
if (_isNotFirstBreakTag(node)) {
return Container(width: width, height: 14.0);
}
return Container(width: width);
Expand All @@ -229,6 +236,13 @@ class HtmlParser {
children: _parseNodeList(node.nodes),
),
);
case "center":
return Container(
width: width,
child: Wrap(
children: _parseNodeList(node.nodes),
alignment: WrapAlignment.center,
));
case "cite":
return DefaultTextStyle.merge(
child: Wrap(
Expand Down Expand Up @@ -720,4 +734,26 @@ class HtmlParser {
}
return stringToTrim;
}

bool _isNotFirstBreakTag(dom.Node node) {
int index = node.parentNode.nodes.indexOf(node);
if (index == 0) {
if (node.parentNode == null) {
return false;
}
return _isNotFirstBreakTag(node.parentNode);
} else if (node.parentNode.nodes[index - 1] is dom.Element) {
if ((node.parentNode.nodes[index - 1] as dom.Element).localName == "br") {
return true;
}
return false;
} else if (node.parentNode.nodes[index - 1] is dom.Text) {
if ((node.parentNode.nodes[index - 1] as dom.Text).text.trim() == "") {
return _isNotFirstBreakTag(node.parentNode.nodes[index - 1]);
} else {
return false;
}
}
return false;
}
}
Loading

0 comments on commit f1e5607

Please sign in to comment.