1
1
import 'package:collection/collection.dart' ;
2
2
import 'package:flutter/foundation.dart' ;
3
+ import 'package:flutter/widgets.dart' ;
3
4
import 'package:html/dom.dart' as dom;
4
5
import 'package:html/parser.dart' ;
5
6
6
7
import '../api/model/model.dart' ;
7
8
import '../api/model/submessage.dart' ;
8
9
import 'code_block.dart' ;
10
+ import 'katex.dart' ;
9
11
10
12
/// A node in a parse tree for Zulip message-style content.
11
13
///
@@ -340,23 +342,46 @@ class CodeBlockSpanNode extends ContentNode {
340
342
}
341
343
}
342
344
343
- class MathBlockNode extends BlockContentNode {
344
- const MathBlockNode ({super .debugHtmlNode, required this .texSource});
345
+ class KatexSpan extends ContentNode {
346
+ const KatexSpan ({
347
+ required this .spanClasses,
348
+ required this .spanStyle,
349
+ required this .text,
350
+ this .spans = const [],
351
+ });
345
352
346
- final String texSource;
353
+ final List <String > spanClasses;
354
+ final KatexSpanStyle ? spanStyle;
355
+ final String ? text;
356
+ final List <KatexSpan > spans;
347
357
348
358
@override
349
- bool operator == (Object other) {
350
- return other is MathBlockNode && other.texSource == texSource;
359
+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
360
+ super .debugFillProperties (properties);
361
+ properties.add (StringProperty ('spanClass' , spanClasses.join (', ' )));
362
+ properties.add (KatexSpanStyleProperty ('spanStyle' , spanStyle));
363
+ properties.add (StringProperty ('text' , text));
351
364
}
352
365
353
366
@override
354
- int get hashCode => Object .hash ('MathBlockNode' , texSource);
367
+ List <DiagnosticsNode > debugDescribeChildren () {
368
+ return spans.map ((node) => node.toDiagnosticsNode ()).toList ();
369
+ }
370
+ }
371
+
372
+ class MathBlockNode extends BlockContentNode {
373
+ const MathBlockNode ({
374
+ super .debugHtmlNode,
375
+ required this .texSource,
376
+ required this .spans,
377
+ });
378
+
379
+ final String texSource;
380
+ final List <KatexSpan > spans;
355
381
356
382
@override
357
- void debugFillProperties (DiagnosticPropertiesBuilder properties) {
358
- super .debugFillProperties (properties);
359
- properties.add (StringProperty ('texSource' , texSource));
383
+ List <DiagnosticsNode > debugDescribeChildren () {
384
+ return spans.map ((node) => node.toDiagnosticsNode ()).toList ();
360
385
}
361
386
}
362
387
@@ -1113,6 +1138,13 @@ class _ZulipContentParser {
1113
1138
return inlineParser.parseBlockInline (nodes);
1114
1139
}
1115
1140
1141
+ // BlockContentNode parseMathBlock(dom.Element element) {
1142
+ // final debugHtmlNode = kDebugMode ? element : null;
1143
+ // final texSource = _parseMath(element, block: true);
1144
+ // if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
1145
+ // return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
1146
+ // }
1147
+
1116
1148
BlockContentNode parseListNode (dom.Element element) {
1117
1149
assert (element.localName == 'ol' || element.localName == 'ul' );
1118
1150
assert (element.className.isEmpty);
@@ -1624,11 +1656,9 @@ class _ZulipContentParser {
1624
1656
})());
1625
1657
1626
1658
final firstChild = nodes.first as dom.Element ;
1627
- final texSource = _parseMath (firstChild, block: true );
1628
- if (texSource != null ) {
1629
- result.add (MathBlockNode (
1630
- texSource: texSource,
1631
- debugHtmlNode: kDebugMode ? firstChild : null ));
1659
+ final block = parseKatexBlock (firstChild);
1660
+ if (block != null ) {
1661
+ result.add (block);
1632
1662
} else {
1633
1663
result.add (UnimplementedBlockContentNode (htmlNode: firstChild));
1634
1664
}
@@ -1649,7 +1679,6 @@ class _ZulipContentParser {
1649
1679
: nodes.length;
1650
1680
for (int i = 1 ; i < length; i++ ) {
1651
1681
final child = nodes[i];
1652
- final debugHtmlNode = kDebugMode ? child : null ;
1653
1682
1654
1683
// If there are multiple <span class="katex-display"> nodes in a <p>
1655
1684
// each node is interleaved by '\n\n'. Whitespaces are ignored in HTML
@@ -1659,11 +1688,9 @@ class _ZulipContentParser {
1659
1688
if (child case dom.Text (text: '\n\n ' )) continue ;
1660
1689
1661
1690
if (child case dom.Element (localName: 'span' , className: 'katex-display' )) {
1662
- final texSource = _parseMath (child, block: true );
1663
- if (texSource != null ) {
1664
- result.add (MathBlockNode (
1665
- texSource: texSource,
1666
- debugHtmlNode: debugHtmlNode));
1691
+ final block = parseKatexBlock (firstChild);
1692
+ if (block != null ) {
1693
+ result.add (block);
1667
1694
continue ;
1668
1695
}
1669
1696
}
@@ -1672,6 +1699,33 @@ class _ZulipContentParser {
1672
1699
}
1673
1700
}
1674
1701
1702
+ BlockContentNode ? parseKatexBlock (dom.Element element) {
1703
+ assert (element.localName == 'span' && element.className == 'katex-display' );
1704
+ if (element.nodes.length != 1 ) return null ;
1705
+ final child = element.nodes.single;
1706
+ if (child is ! dom.Element ) return null ;
1707
+ if (child.localName != 'span' ) return null ;
1708
+ if (child.className != 'katex' ) return null ;
1709
+
1710
+ if (child.nodes.length != 2 ) return null ;
1711
+ final grandchild = child.nodes.last;
1712
+ if (grandchild is ! dom.Element ) return null ;
1713
+ if (grandchild.localName != 'span' ) return null ;
1714
+ if (grandchild.className != 'katex-html' ) return null ;
1715
+
1716
+ try {
1717
+ final debugHtmlNode = kDebugMode ? element : null ;
1718
+ final spans = parseKatexSpans (grandchild);
1719
+ return MathBlockNode (
1720
+ texSource: '' ,
1721
+ spans: spans,
1722
+ debugHtmlNode: debugHtmlNode);
1723
+ } on KatexHtmlParseError catch (e, st) {
1724
+ print ('$e \n $st ' );
1725
+ return null ;
1726
+ }
1727
+ }
1728
+
1675
1729
BlockContentNode parseBlockContent (dom.Node node) {
1676
1730
final debugHtmlNode = kDebugMode ? node : null ;
1677
1731
if (node is ! dom.Element ) {
0 commit comments