|
|
|
@ -83,21 +83,25 @@ class HtmlMessage extends StatelessWidget {
|
|
|
|
|
/// We add line breaks before these tags:
|
|
|
|
|
static const Set<String> blockHtmlTags = {
|
|
|
|
|
'p',
|
|
|
|
|
'h1',
|
|
|
|
|
'h2',
|
|
|
|
|
'h3',
|
|
|
|
|
'h4',
|
|
|
|
|
'h5',
|
|
|
|
|
'h6',
|
|
|
|
|
'ul',
|
|
|
|
|
'ol',
|
|
|
|
|
'li',
|
|
|
|
|
'pre',
|
|
|
|
|
'br',
|
|
|
|
|
'div',
|
|
|
|
|
'table',
|
|
|
|
|
'blockquote',
|
|
|
|
|
'details',
|
|
|
|
|
'blockquote',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// We add line breaks before these tags:
|
|
|
|
|
static const Set<String> fullLineHtmlTag = {
|
|
|
|
|
'h1',
|
|
|
|
|
'h2',
|
|
|
|
|
'h3',
|
|
|
|
|
'h4',
|
|
|
|
|
'h5',
|
|
|
|
|
'h6',
|
|
|
|
|
'li',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Adding line breaks before block elements.
|
|
|
|
@ -105,17 +109,24 @@ class HtmlMessage extends StatelessWidget {
|
|
|
|
|
dom.NodeList nodes,
|
|
|
|
|
BuildContext context, {
|
|
|
|
|
int depth = 1,
|
|
|
|
|
}) =>
|
|
|
|
|
[
|
|
|
|
|
for (var i = 0; i < nodes.length; i++) ...[
|
|
|
|
|
if (i > 0 &&
|
|
|
|
|
nodes[i] is dom.Element &&
|
|
|
|
|
blockHtmlTags.contains((nodes[i] as dom.Element).localName))
|
|
|
|
|
const TextSpan(text: '\n'), // Add linebreak
|
|
|
|
|
// Actually render the node child:
|
|
|
|
|
_renderHtml(nodes[i], context, depth: depth + 1),
|
|
|
|
|
}) {
|
|
|
|
|
final onlyElements = nodes.whereType<dom.Element>().toList();
|
|
|
|
|
return [
|
|
|
|
|
for (var i = 0; i < nodes.length; i++) ...[
|
|
|
|
|
// Actually render the node child:
|
|
|
|
|
_renderHtml(nodes[i], context, depth: depth + 1),
|
|
|
|
|
// Add linebreaks between blocks:
|
|
|
|
|
if (nodes[i] is dom.Element &&
|
|
|
|
|
onlyElements.indexOf(nodes[i] as dom.Element) <
|
|
|
|
|
onlyElements.length - 1) ...[
|
|
|
|
|
if (blockHtmlTags.contains((nodes[i] as dom.Element).localName))
|
|
|
|
|
const TextSpan(text: '\n\n'),
|
|
|
|
|
if (fullLineHtmlTag.contains((nodes[i] as dom.Element).localName))
|
|
|
|
|
const TextSpan(text: '\n'),
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transforms a Node to an InlineSpan.
|
|
|
|
|
InlineSpan _renderHtml(
|
|
|
|
@ -144,6 +155,8 @@ class HtmlMessage extends StatelessWidget {
|
|
|
|
|
if (!allowedHtmlTags.contains(node.localName)) return const TextSpan();
|
|
|
|
|
|
|
|
|
|
switch (node.localName) {
|
|
|
|
|
case 'br':
|
|
|
|
|
return const TextSpan(text: '\n');
|
|
|
|
|
case 'a':
|
|
|
|
|
final href = node.attributes['href'];
|
|
|
|
|
if (href == null) continue block;
|
|
|
|
|