Skip to content

Commit 6962f11

Browse files
author
Andrei
committed
Added support for 'width' and 'height' for img element, and showImages
1 parent 446cb74 commit 6962f11

File tree

2 files changed

+132
-120
lines changed

2 files changed

+132
-120
lines changed

lib/flutter_html.dart

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,28 @@ import 'package:flutter_html/html_parser.dart';
55
import 'image_properties.dart';
66

77
class Html extends StatelessWidget {
8-
Html(
9-
{Key key,
10-
@required this.data,
11-
this.padding,
12-
this.backgroundColor,
13-
this.defaultTextStyle,
14-
this.onLinkTap,
15-
this.renderNewlines = false,
16-
this.customRender,
17-
this.customEdgeInsets,
18-
this.customTextStyle,
19-
this.blockSpacing = 14.0,
20-
this.useRichText = false,
21-
this.onImageError,
22-
this.linkStyle = const TextStyle(
23-
decoration: TextDecoration.underline,
24-
color: Colors.blueAccent,
25-
decorationColor: Colors.blueAccent),
26-
this.imageProperties,
27-
this.onImageTap})
28-
: super(key: key);
8+
Html({
9+
Key key,
10+
@required this.data,
11+
this.padding,
12+
this.backgroundColor,
13+
this.defaultTextStyle,
14+
this.onLinkTap,
15+
this.renderNewlines = false,
16+
this.customRender,
17+
this.customEdgeInsets,
18+
this.customTextStyle,
19+
this.blockSpacing = 14.0,
20+
this.useRichText = false,
21+
this.onImageError,
22+
this.linkStyle = const TextStyle(
23+
decoration: TextDecoration.underline,
24+
color: Colors.blueAccent,
25+
decorationColor: Colors.blueAccent),
26+
this.imageProperties,
27+
this.onImageTap,
28+
this.showImages = true,
29+
}) : super(key: key);
2930

3031
final String data;
3132
final EdgeInsetsGeometry padding;
@@ -41,6 +42,7 @@ class Html extends StatelessWidget {
4142
/// Properties for the Image widget that gets rendered by the rich text parser
4243
final ImageProperties imageProperties;
4344
final OnImageTap onImageTap;
45+
final bool showImages;
4446

4547
/// Either return a custom widget for specific node types or return null to
4648
/// fallback to the default rendering.
@@ -70,6 +72,7 @@ class Html extends StatelessWidget {
7072
linkStyle: linkStyle,
7173
imageProperties: imageProperties,
7274
onImageTap: onImageTap,
75+
showImages: showImages,
7376
)
7477
: HtmlOldParser(
7578
width: width,
@@ -80,6 +83,7 @@ class Html extends StatelessWidget {
8083
blockSpacing: blockSpacing,
8184
onImageError: onImageError,
8285
linkStyle: linkStyle,
86+
showImages: showImages,
8387
),
8488
),
8589
);

lib/html_parser.dart

Lines changed: 107 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class HtmlRichTextParser extends StatelessWidget {
151151
),
152152
this.imageProperties,
153153
this.onImageTap,
154+
this.showImages = true,
154155
});
155156

156157
final double indentSize = 10.0;
@@ -165,6 +166,7 @@ class HtmlRichTextParser extends StatelessWidget {
165166
final TextStyle linkStyle;
166167
final ImageProperties imageProperties;
167168
final OnImageTap onImageTap;
169+
final bool showImages;
168170

169171
// style elements set a default style
170172
// for all child nodes
@@ -615,86 +617,88 @@ class HtmlRichTextParser extends StatelessWidget {
615617
parseContext.rootWidgetList.add(Divider(height: 1.0, color: Colors.black38));
616618
break;
617619
case "img":
618-
if (node.attributes['src'] != null) {
619-
if (node.attributes['src'].startsWith("data:image") &&
620-
node.attributes['src'].contains("base64,")) {
621-
precacheImage(
622-
MemoryImage(
623-
base64.decode(
624-
node.attributes['src'].split("base64,")[1].trim(),
620+
if (showImages) {
621+
if (node.attributes['src'] != null) {
622+
if (node.attributes['src'].startsWith("data:image") &&
623+
node.attributes['src'].contains("base64,")) {
624+
precacheImage(
625+
MemoryImage(
626+
base64.decode(
627+
node.attributes['src'].split("base64,")[1].trim(),
628+
),
625629
),
626-
),
627-
buildContext,
628-
onError: onImageError,
629-
);
630-
parseContext.rootWidgetList.add(GestureDetector(
631-
child: Image.memory(
632-
base64.decode(node.attributes['src'].split("base64,")[1].trim()),
633-
width: imageProperties?.width ??
634-
((node.attributes['width'] != null)
635-
? double.parse(node.attributes['width'])
636-
: null),
637-
height: imageProperties?.height ??
638-
((node.attributes['height'] != null)
639-
? double.parse(node.attributes['height'])
640-
: null),
641-
scale: imageProperties?.scale ?? 1.0,
642-
matchTextDirection: imageProperties?.matchTextDirection ?? false,
643-
centerSlice: imageProperties?.centerSlice,
644-
filterQuality: imageProperties?.filterQuality ?? FilterQuality.low,
645-
alignment: imageProperties?.alignment ?? Alignment.center,
646-
colorBlendMode: imageProperties?.colorBlendMode,
647-
fit: imageProperties?.fit,
648-
color: imageProperties?.color,
649-
repeat: imageProperties?.repeat ?? ImageRepeat.noRepeat,
650-
semanticLabel: imageProperties?.semanticLabel,
651-
excludeFromSemantics: (imageProperties?.semanticLabel == null) ? true : false,
652-
),
653-
onTap: onImageTap,
654-
));
655-
} else {
656-
precacheImage(
657-
NetworkImage(node.attributes['src']),
658-
buildContext,
659-
onError: onImageError,
660-
);
661-
parseContext.rootWidgetList.add(GestureDetector(
662-
child: Image.network(
663-
node.attributes['src'],
664-
width: imageProperties?.width ??
665-
((node.attributes['width'] != null)
666-
? double.parse(node.attributes['width'])
667-
: null),
668-
height: imageProperties?.height ??
669-
((node.attributes['height'] != null)
670-
? double.parse(node.attributes['height'])
671-
: null),
672-
scale: imageProperties?.scale ?? 1.0,
673-
matchTextDirection: imageProperties?.matchTextDirection ?? false,
674-
centerSlice: imageProperties?.centerSlice,
675-
filterQuality: imageProperties?.filterQuality ?? FilterQuality.low,
676-
alignment: imageProperties?.alignment ?? Alignment.center,
677-
colorBlendMode: imageProperties?.colorBlendMode,
678-
fit: imageProperties?.fit,
679-
color: imageProperties?.color,
680-
repeat: imageProperties?.repeat ?? ImageRepeat.noRepeat,
681-
semanticLabel: imageProperties?.semanticLabel,
682-
excludeFromSemantics: (imageProperties?.semanticLabel == null) ? true : false,
683-
),
684-
onTap: onImageTap,
685-
));
686-
}
687-
if (node.attributes['alt'] != null) {
688-
parseContext.rootWidgetList.add(BlockText(
689-
margin: EdgeInsets.symmetric(horizontal: 0.0, vertical: 10.0),
690-
padding: EdgeInsets.all(0.0),
691-
child: RichText(
692-
textAlign: TextAlign.center,
693-
text: TextSpan(
694-
text: node.attributes['alt'],
695-
style: nextContext.childStyle,
696-
children: <TextSpan>[],
697-
))));
630+
buildContext,
631+
onError: onImageError,
632+
);
633+
parseContext.rootWidgetList.add(GestureDetector(
634+
child: Image.memory(
635+
base64.decode(node.attributes['src'].split("base64,")[1].trim()),
636+
width: imageProperties?.width ??
637+
((node.attributes['width'] != null)
638+
? double.parse(node.attributes['width'])
639+
: null),
640+
height: imageProperties?.height ??
641+
((node.attributes['height'] != null)
642+
? double.parse(node.attributes['height'])
643+
: null),
644+
scale: imageProperties?.scale ?? 1.0,
645+
matchTextDirection: imageProperties?.matchTextDirection ?? false,
646+
centerSlice: imageProperties?.centerSlice,
647+
filterQuality: imageProperties?.filterQuality ?? FilterQuality.low,
648+
alignment: imageProperties?.alignment ?? Alignment.center,
649+
colorBlendMode: imageProperties?.colorBlendMode,
650+
fit: imageProperties?.fit,
651+
color: imageProperties?.color,
652+
repeat: imageProperties?.repeat ?? ImageRepeat.noRepeat,
653+
semanticLabel: imageProperties?.semanticLabel,
654+
excludeFromSemantics: (imageProperties?.semanticLabel == null) ? true : false,
655+
),
656+
onTap: onImageTap,
657+
));
658+
} else {
659+
precacheImage(
660+
NetworkImage(node.attributes['src']),
661+
buildContext,
662+
onError: onImageError,
663+
);
664+
parseContext.rootWidgetList.add(GestureDetector(
665+
child: Image.network(
666+
node.attributes['src'],
667+
width: imageProperties?.width ??
668+
((node.attributes['width'] != null)
669+
? double.parse(node.attributes['width'])
670+
: null),
671+
height: imageProperties?.height ??
672+
((node.attributes['height'] != null)
673+
? double.parse(node.attributes['height'])
674+
: null),
675+
scale: imageProperties?.scale ?? 1.0,
676+
matchTextDirection: imageProperties?.matchTextDirection ?? false,
677+
centerSlice: imageProperties?.centerSlice,
678+
filterQuality: imageProperties?.filterQuality ?? FilterQuality.low,
679+
alignment: imageProperties?.alignment ?? Alignment.center,
680+
colorBlendMode: imageProperties?.colorBlendMode,
681+
fit: imageProperties?.fit,
682+
color: imageProperties?.color,
683+
repeat: imageProperties?.repeat ?? ImageRepeat.noRepeat,
684+
semanticLabel: imageProperties?.semanticLabel,
685+
excludeFromSemantics: (imageProperties?.semanticLabel == null) ? true : false,
686+
),
687+
onTap: onImageTap,
688+
));
689+
}
690+
if (node.attributes['alt'] != null) {
691+
parseContext.rootWidgetList.add(BlockText(
692+
margin: EdgeInsets.symmetric(horizontal: 0.0, vertical: 10.0),
693+
padding: EdgeInsets.all(0.0),
694+
child: RichText(
695+
textAlign: TextAlign.center,
696+
text: TextSpan(
697+
text: node.attributes['alt'],
698+
style: nextContext.childStyle,
699+
children: <TextSpan>[],
700+
))));
701+
}
698702
}
699703
}
700704
break;
@@ -876,6 +880,7 @@ class HtmlOldParser extends StatelessWidget {
876880
decoration: TextDecoration.underline,
877881
color: Colors.blueAccent,
878882
decorationColor: Colors.blueAccent),
883+
this.showImages = true,
879884
});
880885

881886
final double width;
@@ -886,6 +891,7 @@ class HtmlOldParser extends StatelessWidget {
886891
final String html;
887892
final ImageErrorListener onImageError;
888893
final TextStyle linkStyle;
894+
final bool showImages;
889895

890896
static const _supportedElements = [
891897
"a",
@@ -1345,30 +1351,32 @@ class HtmlOldParser extends StatelessWidget {
13451351
case "img":
13461352
return Builder(
13471353
builder: (BuildContext context) {
1348-
if (node.attributes['src'] != null) {
1349-
if (node.attributes['src'].startsWith("data:image") &&
1350-
node.attributes['src'].contains("base64,")) {
1354+
if (showImages) {
1355+
if (node.attributes['src'] != null) {
1356+
if (node.attributes['src'].startsWith("data:image") &&
1357+
node.attributes['src'].contains("base64,")) {
1358+
precacheImage(
1359+
MemoryImage(base64.decode(node.attributes['src'].split("base64,")[1].trim())),
1360+
context,
1361+
onError: onImageError,
1362+
);
1363+
return Image.memory(
1364+
base64.decode(node.attributes['src'].split("base64,")[1].trim()));
1365+
}
13511366
precacheImage(
1352-
MemoryImage(base64.decode(node.attributes['src'].split("base64,")[1].trim())),
1367+
NetworkImage(node.attributes['src']),
13531368
context,
13541369
onError: onImageError,
13551370
);
1356-
return Image.memory(
1357-
base64.decode(node.attributes['src'].split("base64,")[1].trim()));
1358-
}
1359-
precacheImage(
1360-
NetworkImage(node.attributes['src']),
1361-
context,
1362-
onError: onImageError,
1363-
);
1364-
return Image.network(node.attributes['src']);
1365-
} else if (node.attributes['alt'] != null) {
1366-
//Temp fix for https://github.com/flutter/flutter/issues/736
1367-
if (node.attributes['alt'].endsWith(" ")) {
1368-
return Container(
1369-
padding: EdgeInsets.only(right: 2.0), child: Text(node.attributes['alt']));
1370-
} else {
1371-
return Text(node.attributes['alt']);
1371+
return Image.network(node.attributes['src']);
1372+
} else if (node.attributes['alt'] != null) {
1373+
//Temp fix for https://github.com/flutter/flutter/issues/736
1374+
if (node.attributes['alt'].endsWith(" ")) {
1375+
return Container(
1376+
padding: EdgeInsets.only(right: 2.0), child: Text(node.attributes['alt']));
1377+
} else {
1378+
return Text(node.attributes['alt']);
1379+
}
13721380
}
13731381
}
13741382
return Container();

0 commit comments

Comments
 (0)