Skip to content

Commit 816e814

Browse files
authored
Merge pull request Sub6Resources#909 from vrtdev/feature/release-216
Release 2.2.0
2 parents 68033b6 + aec5e5e commit 816e814

12 files changed

+87
-34
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## [2.2.0] - November 29, 2021:
2+
* Explicitly declare multiplatform support
3+
* Extended and fixed list-style (marker) support
4+
* Basic support for height/width css properties
5+
* Support changing scroll physics of SelectableText.rich
6+
* Support text transform css property
7+
* Bumped minimum flutter_math_fork version for Flutter 2.5 compatibility
8+
* Fix styling of iframes
9+
* Fix nested font tag application
10+
* Fix whitespace rendering between list items
11+
* Prevent crash on empty <table> tag and tables with both colspan/rowspan
12+
* Prevent crash on use of negative margins in css
13+
114
## [2.1.5] - October 7, 2021:
215
* Ignore unsupported custom style selectors when using fromCss
316
* Fix SVG tag usage inside tables

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ A Flutter widget for rendering HTML and CSS as Flutter widgets.
9898
Add the following to your `pubspec.yaml` file:
9999

100100
dependencies:
101-
flutter_html: ^2.1.5
101+
flutter_html: ^2.2.0
102102

103103
## Currently Supported HTML Tags:
104104
| | | | | | | | | | | |

lib/flutter_html.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'package:flutter_html/image_render.dart';
77
import 'package:flutter_html/src/html_elements.dart';
88
import 'package:flutter_html/style.dart';
99
import 'package:html/dom.dart' as dom;
10-
import 'package:webview_flutter/webview_flutter.dart';
10+
import 'package:flutter_html/src/navigation_delegate.dart';
1111

1212
//export render context api
1313
export 'package:flutter_html/html_parser.dart';
@@ -18,6 +18,7 @@ export 'package:flutter_html/src/interactable_element.dart';
1818
export 'package:flutter_html/src/layout_element.dart';
1919
export 'package:flutter_html/src/replaced_element.dart';
2020
export 'package:flutter_html/src/styled_element.dart';
21+
export 'package:flutter_html/src/navigation_delegate.dart';
2122
//export style api
2223
export 'package:flutter_html/style.dart';
2324

lib/html_parser.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ import 'package:flutter_html/src/anchor.dart';
1313
import 'package:flutter_html/src/css_parser.dart';
1414
import 'package:flutter_html/src/html_elements.dart';
1515
import 'package:flutter_html/src/layout_element.dart';
16+
import 'package:flutter_html/src/navigation_delegate.dart';
1617
import 'package:flutter_html/src/utils.dart';
1718
import 'package:flutter_html/style.dart';
1819
import 'package:html/dom.dart' as dom;
1920
import 'package:html/parser.dart' as htmlparser;
2021
import 'package:numerus/numerus.dart';
21-
import 'package:webview_flutter/webview_flutter.dart';
2222

2323
typedef OnTap = void Function(
2424
String? url,
@@ -737,7 +737,6 @@ class HtmlParser extends StatelessWidget {
737737
String marker = "";
738738
switch (tree.style.listStyleType!) {
739739
case ListStyleType.NONE:
740-
tree.style.markerContent = '';
741740
break;
742741
case ListStyleType.CIRCLE:
743742
marker = '○';
@@ -959,7 +958,7 @@ class HtmlParser extends StatelessWidget {
959958
if (child is EmptyContentElement || child is EmptyLayoutElement) {
960959
toRemove.add(child);
961960
} else if (child is TextContentElement
962-
&& tree.name == "body"
961+
&& (tree.name == "body" || tree.name == "ul")
963962
&& child.text!.replaceAll(' ', '').isEmpty) {
964963
toRemove.add(child);
965964
} else if (child is TextContentElement
@@ -1054,7 +1053,7 @@ class ContainerSpan extends StatelessWidget {
10541053
height: style.height,
10551054
width: style.width,
10561055
padding: style.padding,
1057-
margin: style.margin,
1056+
margin: style.margin?.clamp(EdgeInsets.zero, const EdgeInsets.all(double.infinity)),
10581057
alignment: shrinkWrap ? null : style.alignment,
10591058
child: child ??
10601059
StyledText(

lib/src/layout_element.dart

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,18 +100,19 @@ class TableLayoutElement extends LayoutElement {
100100
// Place the cells in the rows/columns
101101
final cells = <GridPlacement>[];
102102
final columnRowOffset = List.generate(columnMax, (_) => 0);
103+
final columnColspanOffset = List.generate(columnMax, (_) => 0);
103104
int rowi = 0;
104105
for (var row in rows) {
105106
int columni = 0;
106107
for (var child in row.children) {
107108
if (columni > columnMax - 1 ) {
108109
break;
109110
}
110-
while (columnRowOffset[columni] > 0) {
111-
columnRowOffset[columni] = columnRowOffset[columni] - 1;
112-
columni++;
113-
}
114111
if (child is TableCellElement) {
112+
while (columnRowOffset[columni] > 0) {
113+
columnRowOffset[columni] = columnRowOffset[columni] - 1;
114+
columni += columnColspanOffset[columni].clamp(1, columnMax - columni - 1);
115+
}
115116
cells.add(GridPlacement(
116117
child: Container(
117118
width: double.infinity,
@@ -139,6 +140,7 @@ class TableLayoutElement extends LayoutElement {
139140
rowSpan: min(child.rowspan, rows.length - rowi),
140141
));
141142
columnRowOffset[columni] = child.rowspan - 1;
143+
columnColspanOffset[columni] = child.colspan;
142144
columni += child.colspan;
143145
}
144146
}
@@ -155,6 +157,11 @@ class TableLayoutElement extends LayoutElement {
155157
max(0, columnMax - finalColumnSizes.length),
156158
(_) => IntrinsicContentTrackSize());
157159

160+
if (finalColumnSizes.isEmpty || rowSizes.isEmpty) {
161+
// No actual cells to show
162+
return SizedBox();
163+
}
164+
158165
return LayoutGrid(
159166
gridFit: GridFit.loose,
160167
columnSizes: finalColumnSizes,

lib/src/navigation_delegate.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import 'dart:async';
2+
3+
/// Information about a navigation action that is about to be executed.
4+
class NavigationRequest {
5+
NavigationRequest({required this.url, required this.isForMainFrame});
6+
7+
/// The URL that will be loaded if the navigation is executed.
8+
final String url;
9+
10+
/// Whether the navigation request is to be loaded as the main frame.
11+
final bool isForMainFrame;
12+
13+
@override
14+
String toString() {
15+
return '$runtimeType(url: $url, isForMainFrame: $isForMainFrame)';
16+
}
17+
}
18+
19+
/// A decision on how to handle a navigation request.
20+
enum NavigationDecision {
21+
/// Prevent the navigation from taking place.
22+
prevent,
23+
24+
/// Allow the navigation to take place.
25+
navigate,
26+
}
27+
28+
/// Decides how to handle a specific navigation request.
29+
///
30+
/// The returned [NavigationDecision] determines how the navigation described by
31+
/// `navigation` should be handled.
32+
///
33+
/// See also: [WebView.navigationDelegate].
34+
typedef FutureOr<NavigationDecision> NavigationDelegate(
35+
NavigationRequest navigation);

lib/src/replaced_element.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
77
import 'package:flutter_html/html_parser.dart';
88
import 'package:flutter_html/src/anchor.dart';
99
import 'package:flutter_html/src/html_elements.dart';
10+
import 'package:flutter_html/src/navigation_delegate.dart';
1011
import 'package:flutter_html/src/utils.dart';
1112
import 'package:flutter_html/src/widgets/iframe_unsupported.dart'
1213
if (dart.library.io) 'package:flutter_html/src/widgets/iframe_mobile.dart'
@@ -16,7 +17,6 @@ import 'package:flutter_math_fork/flutter_math.dart';
1617
import 'package:flutter_svg/flutter_svg.dart';
1718
import 'package:html/dom.dart' as dom;
1819
import 'package:video_player/video_player.dart';
19-
import 'package:webview_flutter/webview_flutter.dart';
2020

2121
/// A [ReplacedElement] is a type of [StyledElement] that does not require its [children] to be rendered.
2222
///

lib/src/widgets/iframe_mobile.dart

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import 'package:flutter/foundation.dart';
22
import 'package:flutter/gestures.dart';
33
import 'package:flutter/material.dart';
44
import 'package:flutter_html/html_parser.dart';
5+
import 'package:flutter_html/src/navigation_delegate.dart';
56
import 'package:flutter_html/src/replaced_element.dart';
67
import 'package:flutter_html/style.dart';
7-
import 'package:webview_flutter/webview_flutter.dart';
8+
import 'package:webview_flutter/webview_flutter.dart' as webview;
89
import 'package:html/dom.dart' as dom;
910

1011
/// [IframeContentElement is a [ReplacedElement] with web content.
@@ -33,13 +34,23 @@ class IframeContentElement extends ReplacedElement {
3334
child: ContainerSpan(
3435
style: context.style,
3536
newContext: context,
36-
child: WebView(
37+
child: webview.WebView(
3738
initialUrl: src,
3839
key: key,
3940
javascriptMode: sandboxMode == null || sandboxMode == "allow-scripts"
40-
? JavascriptMode.unrestricted
41-
: JavascriptMode.disabled,
42-
navigationDelegate: navigationDelegate,
41+
? webview.JavascriptMode.unrestricted
42+
: webview.JavascriptMode.disabled,
43+
navigationDelegate: (request) async {
44+
final result = await navigationDelegate!(NavigationRequest(
45+
url: request.url,
46+
isForMainFrame: request.isForMainFrame,
47+
));
48+
if (result == NavigationDecision.prevent) {
49+
return webview.NavigationDecision.prevent;
50+
} else {
51+
return webview.NavigationDecision.navigate;
52+
}
53+
},
4354
gestureRecognizers: {
4455
Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer())
4556
},

lib/src/widgets/iframe_unsupported.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_html/html_parser.dart';
3+
import 'package:flutter_html/src/navigation_delegate.dart';
34
import 'package:flutter_html/src/replaced_element.dart';
45
import 'package:flutter_html/style.dart';
5-
import 'package:webview_flutter/webview_flutter.dart';
66
import 'package:html/dom.dart' as dom;
77

88
/// [IframeContentElement is a [ReplacedElement] with web content.
@@ -30,4 +30,4 @@ class IframeContentElement extends ReplacedElement {
3030
child: Text("Iframes are currently not supported in this environment"),
3131
);
3232
}
33-
}
33+
}

lib/src/widgets/iframe_web.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_html/html_parser.dart';
33
import 'package:flutter_html/shims/dart_ui.dart' as ui;
4+
import 'package:flutter_html/src/navigation_delegate.dart';
45
import 'package:flutter_html/src/replaced_element.dart';
56
import 'package:flutter_html/src/utils.dart';
67
import 'package:flutter_html/style.dart';
7-
import 'package:webview_flutter/webview_flutter.dart';
88
import 'package:html/dom.dart' as dom;
99
// ignore: avoid_web_libraries_in_flutter
1010
import 'dart:html' as html;

lib/style.dart

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -548,20 +548,7 @@ class ListStyleType {
548548
static const LOWER_ROMAN = ListStyleType("LOWER_ROMAN");
549549
static const UPPER_ROMAN = ListStyleType("UPPER_ROMAN");
550550
static const SQUARE = ListStyleType("SQUARE");
551-
}
552-
553-
enum ListStyleType {
554-
LOWER_ALPHA,
555-
UPPER_ALPHA,
556-
LOWER_LATIN,
557-
UPPER_LATIN,
558-
CIRCLE,
559-
DISC,
560-
DECIMAL,
561-
LOWER_ROMAN,
562-
UPPER_ROMAN,
563-
SQUARE,
564-
NONE,
551+
static const NONE = ListStyleType("NONE");
565552
}
566553

567554
enum ListStylePosition {

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_html
22
description: A Flutter widget rendering static HTML and CSS as Flutter widgets.
3-
version: 2.1.5
3+
version: 2.2.0
44
homepage: https://github.com/Sub6Resources/flutter_html
55

66
environment:

0 commit comments

Comments
 (0)