Skip to content

Prepare 2.0.0 non-preview release #603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## [2.0.0] - April 29, 2021:
* Stable release with all 2.0.0-nullsafety.X changes

## [2.0.0-nullsafety.1] - April 29, 2021:
* Support basic MathML
* Support inner links
* Supply full context tree to custom render
* Include or exclude specific tags via `tagsList` parameter
* Fixed lists not rendering correctly
* Fixes for colspans in tables
* Fixed various exceptions when using inline styles
* Fixed text decoration not cascading between parent and child
* [BREAKING] support whitelisting tags
* See the README for details on how to migrate `blacklistedElements` (deprecated) to `tagsList`
* Fixed `failed assertion` error when tap-scrolling on any link
* Updated dependencies

## [2.0.0-nullsafety.0] - March 5, 2021:
* Nullsafety support
* Official Flutter Web support
Expand Down
62 changes: 44 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ A Flutter widget for rendering HTML and CSS as Flutter widgets.
Add the following to your `pubspec.yaml` file:

dependencies:
flutter_html: ^1.3.0
flutter_html: ^2.0.0

## Currently Supported HTML Tags:
| | | | | | | | | | | |
Expand Down Expand Up @@ -242,17 +242,18 @@ Widget html = Html(
);
```

Inner links (such as `<a href="#top">Back to the top</a>` will work out of the box by scrolling the viewport, as long as your `Html` widget is wrapped in a scroll container such as a `SingleChildScrollView`.

### customRender:

A powerful API that allows you to customize everything when rendering a specific HTML tag. This means you can add support for HTML elements that aren't supported natively. You can also make up your own custom tags in your HTML!
A powerful API that allows you to customize everything when rendering a specific HTML tag. This means you can change the default behaviour or add support for HTML elements that aren't supported natively. You can also make up your own custom tags in your HTML!

`customRender` accepts a `Map<String, CustomRender>`. The `CustomRender` type is a function that requires a `Widget` to be returned. It exposes `RenderContext`, the `Widget` that would have been rendered by `Html` without a `customRender` defined, the `attributes` of the HTML element as a `Map<String, String>`, and the HTML element itself as `Element`.
`customRender` accepts a `Map<String, CustomRender>`. The `CustomRender` type is a function that requires a `Widget` or `InlineSpan` to be returned. It exposes `RenderContext` and the `Widget` that would have been rendered by `Html` without a `customRender` defined. The `RenderContext` contains the build context, styling and the HTML element, with attrributes and its subtree,.

To use this API, set the key as the tag of the HTML element you wish to provide a custom implementation for, and create a function with the above parameters that returns a `Widget`.
To use this API, set the key as the tag of the HTML element you wish to provide a custom implementation for, and create a function with the above parameters that returns a `Widget` or `InlineSpan`.

#### Example Usages - customRender:
1. Simple example - rendering custom HTML tags
<details><summary>View code</summary>

```dart
Widget html = Html(
Expand All @@ -262,24 +263,48 @@ Widget html = Html(
<flutter horizontal></flutter>
""",
customRender: {
"bird": (RenderContext context, Widget child, Map<String, String> attributes, dom.Element? element) {
"bird": (RenderContext context, Widget child) {
return TextSpan(text: "🐦");
},
"flutter": (RenderContext context, Widget child, Map<String, String> attributes, dom.Element? element) {
"flutter": (RenderContext context, Widget child) {
return FlutterLogo(
style: (attributes['horizontal'] != null)
style: (context.tree.element!.attributes['horizontal'] != null)
? FlutterLogoStyle.horizontal
: FlutterLogoStyle.markOnly,
textColor: context.style.color,
size: context.style.fontSize.size * 5,
size: context.style.fontSize!.size! * 5,
);
},
},
);
```
</details>

2. Complex example - rendering an `iframe` differently based on whether it is an embedded youtube video or some other embedded content
2. Complex example - wrapping the default widget with your own, in this case placing a horizontal scroll around a (potentially too wide) table.

<details><summary>View code</summary>

```dart
Widget html = Html(
data: """
<table style="width:100%">
<caption>Monthly savings</caption>
<tr> <th>January</th> <th>February</th> <th>March</th> <th>April</th> <th>May</th> <th>June</th> <th>July</th> <th>August</th> <th>September</th> <th>October</th> <th>November</th> <th>December</th> </tr>
<tr> <td>\$100</td> <td>\$50</td> <td>\$80</td> <td>\$60</td> <td>\$90</td> <td>\$140</td> <td>\$110</td> <td>\$80</td> <td>\$90</td> <td>\$60</td> <td>\$40</td> <td>\$70</td> </tr>
<tr> <td>\90</td> <td>\$60</td> <td>\$80</td> <td>\$80</td> <td>\$100</td> <td>\$160</td> <td>\$150</td> <td>\$110</td> <td>\$100</td> <td>\$60</td> <td>\$30</td> <td>\$80</td> </tr>
</table>
""",
customRender: {
"table": (context, child) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: (context.tree as TableLayoutElement).toWidget(context),
);
}
},
);
```

3. Complex example - rendering an `iframe` differently based on whether it is an embedded youtube video or some other embedded content.

<details><summary>View code</summary>

Expand All @@ -292,25 +317,26 @@ Widget html = Html(
<iframe src="https://www.youtube.com/embed/tgbNymZ7vqY"></iframe>
""",
customRender: {
"iframe": (RenderContext context, Widget child, Map<String, String> attributes, dom.Element? element) {
if (attributes != null) {
double width = double.tryParse(attributes['width'] ?? "");
double height = double.tryParse(attributes['height'] ?? "");
"iframe": (RenderContext context, Widget child) {
final attrs = context.tree.element?.attributes;
if (attrs != null) {
double? width = double.tryParse(attrs['width'] ?? "");
double? height = double.tryParse(attrs['height'] ?? "");
return Container(
width: width ?? (height ?? 150) * 2,
height: height ?? (width ?? 300) / 2,
child: WebView(
initialUrl: attributes['src'] ?? "about:blank",
initialUrl: attrs['src'] ?? "about:blank",
javascriptMode: JavascriptMode.unrestricted,
//no need for scrolling gesture recognizers on embedded youtube, so set gestureRecognizers null
//on other iframe content scrolling might be necessary, so use VerticalDragGestureRecognizer
gestureRecognizers: attributes['src'] != null && attributes['src']!.contains("youtube.com/embed") ? null : [
gestureRecognizers: attrs['src'] != null && attrs['src']!.contains("youtube.com/embed") ? null : [
Factory(() => VerticalDragGestureRecognizer())
].toSet(),
navigationDelegate: (NavigationRequest request) async {
//no need to load any url besides the embedded youtube url when displaying embedded youtube, so prevent url loading
//on other iframe content allow all url loading
if (attributes['src'] != null && attributes['src']!.contains("youtube.com/embed")) {
if (attrs['src'] != null && attrs['src']!.contains("youtube.com/embed")) {
if (!request.url.contains("youtube.com/embed")) {
return NavigationDecision.prevent;
} else {
Expand Down
14 changes: 13 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,19 @@ class _MyHomePageState extends State<MyHomePage> {
scrollDirection: Axis.horizontal,
child: (context.tree as TableLayoutElement).toWidget(context),
);
}
},
"bird": (RenderContext context, Widget child) {
return TextSpan(text: "🐦");
},
"flutter": (RenderContext context, Widget child) {
return FlutterLogo(
style: (context.tree.element!.attributes['horizontal'] != null)
? FlutterLogoStyle.horizontal
: FlutterLogoStyle.markOnly,
textColor: context.style.color!,
size: context.style.fontSize!.size! * 5,
);
},
},
customImageRenders: {
networkSourceMatcher(domains: ["flutter.dev"]): (context, attributes, element) {
Expand Down
3 changes: 1 addition & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_html
description: A Flutter widget rendering static HTML and CSS as Flutter widgets.
version: 2.0.0-nullsafety.0
version: 2.0.0-nullsafety.1
homepage: https://github.com/Sub6Resources/flutter_html

environment:
Expand Down Expand Up @@ -44,4 +44,3 @@ dev_dependencies:
sdk: flutter

flutter: