Skip to content

Commit 8200613

Browse files
authored
Merge pull request Sub6Resources#546 from tneotia/feature/html-from-dom
Support creating Html widget from dom.Document
2 parents e6032bb + d39ca16 commit 8200613

File tree

3 files changed

+89
-12
lines changed

3 files changed

+89
-12
lines changed

README.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ A Flutter widget for rendering HTML and CSS as Flutter widgets.
3333

3434
- [API Reference](#api-reference)
3535

36+
- [Constructors](#constructors)
37+
3638
- [Parameters Table](#parameters)
3739

3840
- [Data](#data)
41+
42+
- [Document](#document)
3943

4044
- [onLinkTap](#onlinktap)
4145

@@ -131,11 +135,20 @@ For a full example, see [here](https://github.com/Sub6Resources/flutter_html/tre
131135

132136
Below, you will find brief descriptions of the parameters the`Html` widget accepts and some code snippets to help you use this package.
133137

138+
## Constructors:
139+
140+
The package currently has two different constructors - `Html()` and `Html.fromDom()`.
141+
142+
The `Html()` constructor is for those who would like to directly pass HTML from the source to the package to be rendered.
143+
144+
If you would like to modify or sanitize the HTML before rendering it, then `Html.fromDom()` is for you - you can convert the HTML string to a `Document` and use its methods to modify the HTML as you wish. Then, you can directly pass the modified `Document` to the package. This eliminates the need to parse the modified `Document` back to a string, pass to `Html()`, and convert back to a `Document`, thus cutting down on load times.
145+
134146
### Parameters:
135147

136148
| Parameters | Description |
137149
|--------------|-----------------|
138-
| `data` | The HTML data passed to the `Html` widget. This is required and cannot be null. |
150+
| `data` | The HTML data passed to the `Html` widget. This is required and cannot be null when using `Html()`. |
151+
| `document` | The DOM document passed to the `Html` widget. This is required and cannot be null when using `Html.fromDom()`. |
139152
| `onLinkTap` | A function that defines what the widget should do when a link is tapped. The function exposes the `src` of the link as a `String` to use in your implementation. |
140153
| `customRender` | A powerful API that allows you to customize everything when rendering a specific HTML tag. |
141154
| `onImageError` | A function that defines what the widget should do when an image fails to load. The function exposes the exception `Object` and `StackTrace` to use in your implementation. |
@@ -148,7 +161,7 @@ Below, you will find brief descriptions of the parameters the`Html` widget accep
148161

149162
### Data:
150163

151-
The HTML data passed to the `Html` widget as a `String`. This is required and cannot be null.
164+
The HTML data passed to the `Html` widget as a `String`. This is required and cannot be null when using `Html`.
152165
Any HTML tags in the `String` that are not supported by the package will not be rendered.
153166

154167
#### Example Usage - Data:
@@ -169,6 +182,36 @@ Widget html = Html(
169182
);
170183
```
171184

185+
### Document:
186+
187+
The DOM document passed to the `Html` widget as a `Document`. This is required and cannot be null when using `Html.fromDom()`.
188+
Any HTML tags in the document that are not supported by the package will not be rendered.
189+
Using the `Html.fromDom()` constructor can be useful when you would like to sanitize the HTML string yourself before passing it to the package.
190+
191+
#### Example Usage - Document:
192+
193+
```dart
194+
import 'package:html/parser.dart' as htmlparser;
195+
import 'package:html/dom.dart' as dom;
196+
...
197+
String htmlData = """<div>
198+
<h1>Demo Page</h1>
199+
<p>This is a fantastic product that you should buy!</p>
200+
<h3>Features</h3>
201+
<ul>
202+
<li>It actually works</li>
203+
<li>It exists</li>
204+
<li>It doesn't cost much!</li>
205+
</ul>
206+
<!--You can pretty much put any html in here!-->
207+
</div>""";
208+
dom.Document document = htmlparser.parse(htmlData);
209+
/// sanitize or query document here
210+
Widget html = Html(
211+
document: document,
212+
);
213+
```
214+
172215
### onLinkTap:
173216

174217
A function that defines what the widget should do when a link is tapped.

lib/flutter_html.dart

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import 'package:flutter_html/html_parser.dart';
55
import 'package:flutter_html/image_render.dart';
66
import 'package:flutter_html/style.dart';
77
import 'package:webview_flutter/webview_flutter.dart';
8+
import 'package:html/dom.dart' as dom;
89

910
class Html extends StatelessWidget {
1011
/// The `Html` widget takes HTML as input and displays a RichText
1112
/// tree of the parsed HTML content.
1213
///
1314
/// **Attributes**
14-
/// **data** *required* takes in a String of HTML data.
15-
///
15+
/// **data** *required* takes in a String of HTML data (required only for `Html` constructor).
16+
/// **document** *required* takes in a Document of HTML data (required only for `Html.fromDom` constructor).
1617
///
1718
/// **onLinkTap** This function is called whenever a link (`<a href>`)
1819
/// is tapped.
@@ -44,24 +45,57 @@ class Html extends StatelessWidget {
4445
this.blacklistedElements = const [],
4546
this.style = const {},
4647
this.navigationDelegateForIframe,
47-
}) : super(key: key);
48+
}) : document = null,
49+
assert (data != null),
50+
super(key: key);
4851

49-
final String data;
52+
Html.fromDom({
53+
Key? key,
54+
@required this.document,
55+
this.onLinkTap,
56+
this.customRender = const {},
57+
this.customImageRenders = const {},
58+
this.onImageError,
59+
this.shrinkWrap = false,
60+
this.onImageTap,
61+
this.blacklistedElements = const [],
62+
this.style = const {},
63+
this.navigationDelegateForIframe,
64+
}) : data = null,
65+
assert(document != null),
66+
super(key: key);
67+
68+
/// The HTML data passed to the widget as a String
69+
final String? data;
70+
71+
/// The HTML data passed to the widget as a pre-processed [dom.Document]
72+
final dom.Document? document;
73+
74+
/// A function that defines what to do when a link is tapped
5075
final OnTap? onLinkTap;
76+
77+
/// An API that allows you to customize the entire process of image rendering.
78+
/// See the README for more details.
5179
final Map<ImageSourceMatcher, ImageRender> customImageRenders;
80+
81+
/// A function that defines what to do when an image errors
5282
final ImageErrorListener? onImageError;
83+
84+
/// A parameter that should be set when the HTML widget is expected to be
85+
/// flexible
5386
final bool shrinkWrap;
5487

55-
/// Properties for the Image widget that gets rendered by the rich text parser
88+
/// A function that defines what to do when an image is tapped
5689
final OnTap? onImageTap;
5790

91+
/// A list of HTML tags that defines what elements are not rendered
5892
final List<String> blacklistedElements;
5993

6094
/// Either return a custom widget for specific node types or return null to
6195
/// fallback to the default rendering.
6296
final Map<String, CustomRender> customRender;
6397

64-
/// Fancy New Parser parameters
98+
/// An API that allows you to override the default style for any HTML element
6599
final Map<String, Style> style;
66100

67101
/// Decides how to handle a specific navigation request in the WebView of an
@@ -71,12 +105,13 @@ class Html extends StatelessWidget {
71105

72106
@override
73107
Widget build(BuildContext context) {
108+
final dom.Document doc = data != null ? HtmlParser.parseHTML(data!) : document!;
74109
final double? width = shrinkWrap ? null : MediaQuery.of(context).size.width;
75110

76111
return Container(
77112
width: width,
78113
child: HtmlParser(
79-
htmlData: data,
114+
htmlData: doc,
80115
onLinkTap: onLinkTap,
81116
onImageTap: onImageTap,
82117
onImageError: onImageError,

lib/html_parser.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ typedef CustomRender = dynamic Function(
3030
);
3131

3232
class HtmlParser extends StatelessWidget {
33-
final String htmlData;
33+
final dom.Document htmlData;
3434
final OnTap? onLinkTap;
3535
final OnTap? onImageTap;
3636
final ImageErrorListener? onImageError;
@@ -57,9 +57,8 @@ class HtmlParser extends StatelessWidget {
5757

5858
@override
5959
Widget build(BuildContext context) {
60-
dom.Document document = parseHTML(htmlData);
6160
StyledElement lexedTree = lexDomTree(
62-
document,
61+
htmlData,
6362
customRender.keys.toList(),
6463
blacklistedElements,
6564
navigationDelegateForIframe,

0 commit comments

Comments
 (0)