From d9f04b1928ba1f7f041817b320730cbda0fcfa08 Mon Sep 17 00:00:00 2001 From: tanay Date: Wed, 17 Feb 2021 16:39:39 -0500 Subject: [PATCH 01/11] Pre-nullsafety changes --- lib/flutter_html.dart | 4 +- lib/html_parser.dart | 43 ++++++------ lib/src/css_parser.dart | 2 +- lib/src/interactable_element.dart | 41 +++++++----- lib/src/layout_element.dart | 72 +++++++++++--------- lib/src/replaced_element.dart | 105 ++++++++++++++---------------- lib/src/styled_element.dart | 13 ++-- pubspec.yaml | 26 +++++--- test/golden_test.dart | 2 - 9 files changed, 162 insertions(+), 146 deletions(-) diff --git a/lib/flutter_html.dart b/lib/flutter_html.dart index faf8468d3a..7e51453658 100644 --- a/lib/flutter_html.dart +++ b/lib/flutter_html.dart @@ -36,13 +36,13 @@ class Html extends StatelessWidget { Key key, @required this.data, this.onLinkTap, - this.customRender, + this.customRender = const {}, this.customImageRenders = const {}, this.onImageError, this.shrinkWrap = false, this.onImageTap, this.blacklistedElements = const [], - this.style, + this.style = const {}, this.navigationDelegateForIframe, }) : super(key: key); diff --git a/lib/html_parser.dart b/lib/html_parser.dart index 60732287d4..c762c29d66 100644 --- a/lib/html_parser.dart +++ b/lib/html_parser.dart @@ -39,15 +39,15 @@ class HtmlParser extends StatelessWidget { HtmlParser({ @required this.htmlData, - this.onLinkTap, - this.onImageTap, - this.onImageError, - this.shrinkWrap, - this.style, - this.customRender, - this.imageRenders, - this.blacklistedElements, - this.navigationDelegateForIframe, + @required this.onLinkTap, + @required this.onImageTap, + @required this.onImageError, + @required this.shrinkWrap, + @required this.style, + @required this.customRender, + @required this.imageRenders, + @required this.blacklistedElements, + @required this.navigationDelegateForIframe, }); @override @@ -108,8 +108,9 @@ class HtmlParser extends StatelessWidget { ) { StyledElement tree = StyledElement( name: "[Tree Root]", - children: new List(), + children: [], node: html.documentElement, + style: Style(), ); html.nodes.forEach((node) { @@ -134,7 +135,7 @@ class HtmlParser extends StatelessWidget { List blacklistedElements, NavigationDelegate navigationDelegateForIframe, ) { - List children = List(); + List children = []; node.nodes.forEach((childNode) { children.add(_recursiveLexer( @@ -168,7 +169,7 @@ class HtmlParser extends StatelessWidget { return EmptyContentElement(); } } else if (node is dom.Text) { - return TextContentElement(text: node.text); + return TextContentElement(text: node.text, style: Style()); } else { return EmptyContentElement(); } @@ -667,7 +668,7 @@ class HtmlParser extends StatelessWidget { /// or any block-level [TextContentElement] that contains only whitespace and doesn't follow /// a block element or a line break. static StyledElement _removeEmptyElements(StyledElement tree) { - List toRemove = new List(); + List toRemove = []; bool lastChildBlock = true; tree.children?.forEach((child) { if (child is EmptyContentElement || child is EmptyLayoutElement) { @@ -723,9 +724,9 @@ class RenderContext { final Style style; RenderContext({ - this.buildContext, - this.parser, - this.style, + @required this.buildContext, + @required this.parser, + @required this.style, }); } @@ -743,8 +744,8 @@ class ContainerSpan extends StatelessWidget { ContainerSpan({ this.child, this.children, - this.style, - this.newContext, + @required this.style, + @required this.newContext, this.shrinkWrap = false, }); @@ -780,10 +781,10 @@ class StyledText extends StatelessWidget { final RenderContext renderContext; const StyledText({ - this.textSpan, - this.style, + @required this.textSpan, + @required this.style, this.textScaleFactor = 1.0, - this.renderContext, + @required this.renderContext, }); @override diff --git a/lib/src/css_parser.dart b/lib/src/css_parser.dart index dd5e08c034..90a9f4bfbb 100644 --- a/lib/src/css_parser.dart +++ b/lib/src/css_parser.dart @@ -91,7 +91,7 @@ class DeclarationVisitor extends css.Visitor { @override void visitDeclaration(css.Declaration node) { _currentProperty = node.property; - _result[_currentProperty] = new List(); + _result[_currentProperty] = []; node.expression.visit(this); } diff --git a/lib/src/interactable_element.dart b/lib/src/interactable_element.dart index 98bdd3df41..6fbcf03918 100644 --- a/lib/src/interactable_element.dart +++ b/lib/src/interactable_element.dart @@ -8,11 +8,11 @@ class InteractableElement extends StyledElement { String href; InteractableElement({ - String name, - List children, - Style style, - this.href, - dom.Node node, + @required String name, + @required List children, + @required Style style, + @required this.href, + @required dom.Node node, }) : super(name: name, children: children, style: style, node: node); } @@ -23,21 +23,26 @@ enum Gesture { InteractableElement parseInteractableElement( dom.Element element, List children) { - InteractableElement interactableElement = InteractableElement( - name: element.localName, - children: children, - node: element, - ); - switch (element.localName) { case "a": - interactableElement.href = element.attributes['href']; - interactableElement.style = Style( - color: Colors.blue, - textDecoration: TextDecoration.underline, + return InteractableElement( + name: element.localName, + children: children, + href: element.attributes['href'], + style: Style( + color: Colors.blue, + textDecoration: TextDecoration.underline, + ), + node: element, + ); + /// will never be called, just to suppress missing return warning + default: + return InteractableElement( + name: element.localName, + children: children, + node: element, + href: '', + style: Style(), ); - break; } - - return interactableElement; } \ No newline at end of file diff --git a/lib/src/layout_element.dart b/lib/src/layout_element.dart index 0950b51c18..49e58bf424 100644 --- a/lib/src/layout_element.dart +++ b/lib/src/layout_element.dart @@ -12,22 +12,20 @@ import 'package:html/dom.dart' as dom; /// an html document with a more complex layout. LayoutElements handle abstract class LayoutElement extends StyledElement { LayoutElement({ - String name, - List children, - Style style, + String name = "[[No Name]]", + @required List children, dom.Element node, - }) : super(name: name, children: children, style: style, node: node); + }) : super(name: name, children: children, style: Style(), node: node); Widget toWidget(RenderContext context); } class TableLayoutElement extends LayoutElement { TableLayoutElement({ - String name, - Style style, + @required String name, @required List children, - dom.Element node, - }) : super(name: name, style: style, children: children, node: node); + @required dom.Element node, + }) : super(name: name, children: children, node: node); @override Widget toWidget(RenderContext context) { @@ -51,8 +49,7 @@ class TableLayoutElement extends LayoutElement { columnSizes = child.children .where((c) => c.name == "col") .map((c) { - final span = - int.parse(c.attributes["span"] ?? "1", onError: (_) => 1); + final span = int.tryParse(c.attributes["span"] ?? "1") ?? 1; final colWidth = c.attributes["width"]; return List.generate(span, (index) { if (colWidth != null && colWidth.endsWith("%")) { @@ -145,8 +142,8 @@ class TableLayoutElement extends LayoutElement { return LayoutGrid( gridFit: GridFit.loose, - templateColumnSizes: finalColumnSizes, - templateRowSizes: rowSizes, + columnSizes: finalColumnSizes, + rowSizes: rowSizes, children: cells, ); } @@ -154,7 +151,7 @@ class TableLayoutElement extends LayoutElement { class TableSectionLayoutElement extends LayoutElement { TableSectionLayoutElement({ - String name, + @required String name, @required List children, }) : super(name: name, children: children); @@ -167,9 +164,9 @@ class TableSectionLayoutElement extends LayoutElement { class TableRowLayoutElement extends LayoutElement { TableRowLayoutElement({ - String name, + @required String name, @required List children, - dom.Element node, + @required dom.Element node, }) : super(name: name, children: children, node: node); @override @@ -184,12 +181,12 @@ class TableCellElement extends StyledElement { int rowspan = 1; TableCellElement({ - String name, - String elementId, - List elementClasses, + @required String name, + @required String elementId, + @required List elementClasses, @required List children, - Style style, - dom.Element node, + @required Style style, + @required dom.Element node, }) : super( name: name, elementId: elementId, @@ -217,6 +214,7 @@ TableCellElement parseTableCellElement( elementClasses: element.classes.toList(), children: children, node: element, + style: Style(), ); if (element.localName == "th") { cell.style = Style( @@ -228,10 +226,10 @@ TableCellElement parseTableCellElement( class TableStyleElement extends StyledElement { TableStyleElement({ - String name, - List children, - Style style, - dom.Element node, + @required String name, + @required List children, + @required Style style, + @required dom.Element node, }) : super(name: name, children: children, style: style, node: node); } @@ -246,9 +244,15 @@ TableStyleElement parseTableDefinitionElement( name: element.localName, children: children, node: element, + style: Style(), ); default: - return TableStyleElement(); + return TableStyleElement( + name: "[[No Name]]", + children: children, + node: element, + style: Style(), + ); } } @@ -256,10 +260,10 @@ class DetailsContentElement extends LayoutElement { List elementList; DetailsContentElement({ - String name, - List children, - dom.Element node, - this.elementList, + @required String name, + @required List children, + @required dom.Element node, + @required this.elementList, }) : super(name: name, node: node, children: children); @override @@ -311,7 +315,7 @@ class DetailsContentElement extends LayoutElement { } class EmptyLayoutElement extends LayoutElement { - EmptyLayoutElement({String name = "empty"}) : super(name: name); + EmptyLayoutElement({@required String name}) : super(name: name, children: []); @override Widget toWidget(_) => null; @@ -324,7 +328,7 @@ LayoutElement parseLayoutElement( switch (element.localName) { case "details": if (children?.isEmpty ?? false) { - return EmptyLayoutElement(); + return EmptyLayoutElement(name: "empty"); } return DetailsContentElement( node: element, @@ -355,6 +359,10 @@ LayoutElement parseLayoutElement( ); break; default: - return TableLayoutElement(children: children); + return TableLayoutElement( + children: children, + name: "[[No Name]]", + node: element + ); } } diff --git a/lib/src/replaced_element.dart b/lib/src/replaced_element.dart index 7074060333..e6d92241f1 100644 --- a/lib/src/replaced_element.dart +++ b/lib/src/replaced_element.dart @@ -21,12 +21,12 @@ import 'package:webview_flutter/webview_flutter.dart'; abstract class ReplacedElement extends StyledElement { PlaceholderAlignment alignment; - ReplacedElement( - {String name, - Style style, - dom.Element node, - this.alignment = PlaceholderAlignment.aboveBaseline}) - : super(name: name, children: null, style: style, node: node); + ReplacedElement({ + @required String name, + @required Style style, + dom.Element node, + this.alignment = PlaceholderAlignment.aboveBaseline + }) : super(name: name, children: [], style: style, node: node); static List parseMediaSources(List elements) { return elements @@ -44,8 +44,8 @@ class TextContentElement extends ReplacedElement { String text; TextContentElement({ - Style style, - this.text, + @required Style style, + @required this.text, }) : super(name: "[text]", style: style); @override @@ -64,17 +64,11 @@ class ImageContentElement extends ReplacedElement { final String alt; ImageContentElement({ - String name, - Style style, - this.src, - this.alt, - dom.Element node, - }) : super( - name: name, - style: style, - node: node, - alignment: PlaceholderAlignment.middle, - ); + @required String name, + @required this.src, + @required this.alt, + @required dom.Element node, + }) : super(name: name, style: Style(), node: node, alignment: PlaceholderAlignment.middle); @override Widget toWidget(RenderContext context) { @@ -99,14 +93,13 @@ class IframeContentElement extends ReplacedElement { final UniqueKey key = UniqueKey(); IframeContentElement({ - String name, - Style style, - this.src, - this.width, - this.height, - dom.Element node, - this.navigationDelegate, - }) : super(name: name, style: style, node: node); + @required String name, + @required this.src, + @required this.width, + @required this.height, + @required dom.Element node, + @required this.navigationDelegate, + }) : super(name: name, style: Style(), node: node); @override Widget toWidget(RenderContext context) { @@ -138,15 +131,14 @@ class AudioContentElement extends ReplacedElement { final bool muted; AudioContentElement({ - String name, - Style style, - this.src, - this.showControls, - this.autoplay, - this.loop, - this.muted, - dom.Element node, - }) : super(name: name, style: style, node: node); + @required String name, + @required this.src, + @required this.showControls, + @required this.autoplay, + @required this.loop, + @required this.muted, + @required dom.Element node, + }) : super(name: name, style: Style(), node: node); @override Widget toWidget(RenderContext context) { @@ -179,18 +171,17 @@ class VideoContentElement extends ReplacedElement { final double height; VideoContentElement({ - String name, - Style style, - this.src, - this.poster, - this.showControls, - this.autoplay, - this.loop, - this.muted, - this.width, - this.height, - dom.Element node, - }) : super(name: name, style: style, node: node); + @required String name, + @required this.src, + @required this.poster, + @required this.showControls, + @required this.autoplay, + @required this.loop, + @required this.muted, + @required this.width, + @required this.height, + @required dom.Element node, + }) : super(name: name, style: Style(), node: node); @override Widget toWidget(RenderContext context) { @@ -226,10 +217,12 @@ class SvgContentElement extends ReplacedElement { final double height; SvgContentElement({ - this.data, - this.width, - this.height, - }); + @required String name, + @required this.data, + @required this.width, + @required this.height, + @required dom.Node node, + }) : super(name: name, style: Style(), node: node); @override Widget toWidget(RenderContext context) { @@ -242,7 +235,7 @@ class SvgContentElement extends ReplacedElement { } class EmptyContentElement extends ReplacedElement { - EmptyContentElement({String name = "empty"}) : super(name: name); + EmptyContentElement({String name = "empty"}) : super(name: name, style: Style()); @override Widget toWidget(_) => null; @@ -252,12 +245,12 @@ class RubyElement extends ReplacedElement { dom.Element element; RubyElement({@required this.element, String name = "ruby"}) - : super(name: name, alignment: PlaceholderAlignment.middle); + : super(name: name, alignment: PlaceholderAlignment.middle, style: Style()); @override Widget toWidget(RenderContext context) { dom.Node textNode; - List widgets = List(); + List widgets = []; //TODO calculate based off of parent font size. final rubySize = max(9.0, context.style.fontSize.size / 2); final rubyYPos = rubySize + rubySize / 2; @@ -362,9 +355,11 @@ ReplacedElement parseReplacedElement( ); case "svg": return SvgContentElement( + name: "svg", data: element.outerHtml, width: double.tryParse(element.attributes['width'] ?? ""), height: double.tryParse(element.attributes['height'] ?? ""), + node: element, ); case "ruby": return RubyElement( diff --git a/lib/src/styled_element.dart b/lib/src/styled_element.dart index 1d9ffb970e..569d16db39 100644 --- a/lib/src/styled_element.dart +++ b/lib/src/styled_element.dart @@ -15,11 +15,11 @@ class StyledElement { StyledElement({ this.name = "[[No name]]", - this.elementId, - this.elementClasses, - this.children, - this.style, - dom.Element node, + this.elementId = "[[No ID]]", + this.elementClasses = const [], + @required this.children, + @required this.style, + @required dom.Element node, }) : this._node = node; bool matchesSelector(String selector) => @@ -27,7 +27,7 @@ class StyledElement { Map get attributes => _node?.attributes?.map((key, value) { - return MapEntry(key, value); + return MapEntry(key.toString(), value); }) ?? Map(); @@ -53,6 +53,7 @@ StyledElement parseStyledElement( elementClasses: element.classes.toList(), children: children, node: element, + style: Style(), ); switch (element.localName) { diff --git a/pubspec.yaml b/pubspec.yaml index f41b5669e6..b60cc735c4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,29 +4,37 @@ version: 1.3.0 homepage: https://github.com/Sub6Resources/flutter_html environment: - sdk: '>=2.2.2 <3.0.0' + sdk: '>=2.11.0 <3.0.0' flutter: '>=1.17.0' dependencies: # Plugin for parsing html - html: ^0.14.0+4 + html: ^0.15.0 # Plugins for parsing css - csslib: ^0.16.2 - css_colors: ^1.0.2 + csslib: ^0.17.0 + css_colors: ^1.1.0 # Plugins for rendering the tag. - flutter_layout_grid: ^0.10.5 + flutter_layout_grid: ^1.0.0-nullsafety.5 # Plugins for rendering the