Skip to content

Instantly share code, notes, and snippets.

@Loong-T
Created March 13, 2020 09:02
Show Gist options
  • Save Loong-T/5da59b881ccbab0937678fa0bb2a5f4c to your computer and use it in GitHub Desktop.
Save Loong-T/5da59b881ccbab0937678fa0bb2a5f4c to your computer and use it in GitHub Desktop.
A Widget to show effects of some simple html tags
import 'package:flutter/material.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart';
class HtmlSpanView extends StatefulWidget {
final String content;
const HtmlSpanView(this.content);
@override
State<StatefulWidget> createState() => _HtmlSpanState();
}
class _HtmlSpanState extends State<HtmlSpanView> {
bool _didFailToParse = false;
dom.Node _document;
@override
void initState() {
super.initState();
_parseContent();
}
@override
void didUpdateWidget(HtmlSpanView oldWidget) {
_parseContent();
}
@override
Widget build(BuildContext context) {
if (_didFailToParse) {
return Text(widget.content);
}
return SpanViewBuilder(_document.nodes);
}
void _parseContent() {
try {
var document = parse(widget.content);
setState(() {
_document = document.body;
});
} on Exception catch (_) {
setState(() {
_didFailToParse = true;
});
}
}
}
class SpanViewBuilder extends StatelessWidget {
final List<dom.Node> nodes;
const SpanViewBuilder(this.nodes);
@override
Widget build(BuildContext context) {
if (nodes.isEmpty) {
return SizedBox.shrink();
}
if (nodes.length == 1) {
return Text.rich(nodeToSpan(nodes.single));
}
return Text.rich(
TextSpan(children: nodesToSpan(nodes)),
);
}
}
@visibleForTesting
List<TextSpan> nodesToSpan(List<dom.Node> nodes) {
return nodes.map((node) => nodeToSpan(node)).toList();
}
@visibleForTesting
TextSpan nodeToSpan(dom.Node node) {
if (node is dom.Text) {
return TextSpan(text: node.data);
}
if (node is dom.Element) {
var name = node.localName;
switch (name) {
case 'b':
return BoldSpan(node.nodes);
case 'font':
var color;
try {
var str = node.attributes['color'];
if (str == null) {
throw FormatException();
}
var raw = int.parse(str, radix: 16);
color = Color.fromRGBO(raw >> 16, (raw >> 8) & 0xFF, raw & 0xFF, 1.0);
} on FormatException {
color = Colors.black;
}
return FontSpan(color, node.nodes);
default:
return TextSpan(children: nodesToSpan(node.nodes));
}
}
return TextSpan(text: node.toString());
}
class BoldSpan extends TextSpan {
BoldSpan(dom.NodeList nodes)
: super(
children: nodesToSpan(nodes),
style: TextStyle(fontWeight: FontWeight.bold),
);
}
class FontSpan extends TextSpan {
final Color color;
FontSpan(this.color, dom.NodeList nodes)
: super(
children: nodesToSpan(nodes),
style: TextStyle(color: color),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment