@@ -5,7 +5,9 @@ import 'package:html/parser.dart';
5
5
6
6
import '../api/model/model.dart' ;
7
7
import '../api/model/submessage.dart' ;
8
+ import '../log.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
///
@@ -341,22 +343,46 @@ class CodeBlockSpanNode extends ContentNode {
341
343
}
342
344
343
345
class MathBlockNode extends BlockContentNode {
344
- const MathBlockNode ({super .debugHtmlNode, required this .texSource});
346
+ const MathBlockNode ({
347
+ super .debugHtmlNode,
348
+ required this .texSource,
349
+ required this .nodes,
350
+ });
345
351
346
352
final String texSource;
353
+ final List <KatexSpanNode >? nodes;
347
354
348
355
@override
349
- bool operator == (Object other) {
350
- return other is MathBlockNode && other.texSource == texSource;
356
+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
357
+ super .debugFillProperties (properties);
358
+ properties.add (StringProperty ('texSource' , texSource));
351
359
}
352
360
353
361
@override
354
- int get hashCode => Object .hash ('MathBlockNode' , texSource);
362
+ List <DiagnosticsNode > debugDescribeChildren () {
363
+ return nodes? .map ((node) => node.toDiagnosticsNode ()).toList () ?? const [];
364
+ }
365
+ }
366
+
367
+ class KatexSpanNode extends ContentNode {
368
+ const KatexSpanNode ({
369
+ required this .text,
370
+ required this .nodes,
371
+ super .debugHtmlNode,
372
+ });
373
+
374
+ final String ? text;
375
+ final List <KatexSpanNode > nodes;
355
376
356
377
@override
357
378
void debugFillProperties (DiagnosticPropertiesBuilder properties) {
358
379
super .debugFillProperties (properties);
359
- properties.add (StringProperty ('texSource' , texSource));
380
+ properties.add (StringProperty ('text' , text));
381
+ }
382
+
383
+ @override
384
+ List <DiagnosticsNode > debugDescribeChildren () {
385
+ return nodes.map ((node) => node.toDiagnosticsNode ()).toList ();
360
386
}
361
387
}
362
388
@@ -822,23 +848,25 @@ class ImageEmojiNode extends EmojiNode {
822
848
}
823
849
824
850
class MathInlineNode extends InlineContentNode {
825
- const MathInlineNode ({super .debugHtmlNode, required this .texSource});
851
+ const MathInlineNode ({
852
+ super .debugHtmlNode,
853
+ required this .texSource,
854
+ required this .nodes,
855
+ });
826
856
827
857
final String texSource;
828
-
829
- @override
830
- bool operator == (Object other) {
831
- return other is MathInlineNode && other.texSource == texSource;
832
- }
833
-
834
- @override
835
- int get hashCode => Object .hash ('MathInlineNode' , texSource);
858
+ final List <KatexSpanNode >? nodes;
836
859
837
860
@override
838
861
void debugFillProperties (DiagnosticPropertiesBuilder properties) {
839
862
super .debugFillProperties (properties);
840
863
properties.add (StringProperty ('texSource' , texSource));
841
864
}
865
+
866
+ @override
867
+ List <DiagnosticsNode > debugDescribeChildren () {
868
+ return nodes? .map ((node) => node.toDiagnosticsNode ()).toList () ?? const [];
869
+ }
842
870
}
843
871
844
872
class GlobalTimeNode extends InlineContentNode {
@@ -864,7 +892,10 @@ class GlobalTimeNode extends InlineContentNode {
864
892
865
893
////////////////////////////////////////////////////////////////
866
894
867
- String ? _parseMath (dom.Element element, {required bool block}) {
895
+ ({List <KatexSpanNode >? spans, String texSource})? _parseMath (
896
+ dom.Element element, {
897
+ required bool block,
898
+ }) {
868
899
final dom.Element katexElement;
869
900
if (! block) {
870
901
assert (element.localName == 'span' && element.className == 'katex' );
@@ -882,16 +913,15 @@ String? _parseMath(dom.Element element, {required bool block}) {
882
913
}
883
914
}
884
915
885
- // Expect two children span.katex-mathml, span.katex-html .
886
- // For now we only care about the .katex-mathml .
887
916
if (katexElement.nodes case [
888
917
dom.Element (localName: 'span' , className: 'katex-mathml' , nodes: [
889
918
dom.Element (
890
919
localName: 'math' ,
891
920
namespaceUri: 'http://www.w3.org/1998/Math/MathML' )
892
921
&& final mathElement,
893
922
]),
894
- ...
923
+ dom.Element (localName: 'span' , className: 'katex-html' , nodes: [...])
924
+ && final katexHtmlElement,
895
925
]) {
896
926
if (mathElement.attributes['display' ] != (block ? 'block' : null )) {
897
927
return null ;
@@ -911,7 +941,15 @@ String? _parseMath(dom.Element element, {required bool block}) {
911
941
} else {
912
942
return null ;
913
943
}
914
- return texSource;
944
+
945
+ List <KatexSpanNode >? spans;
946
+ try {
947
+ spans = KatexParser ().parseKatexHTML (katexHtmlElement);
948
+ } on KatexHtmlParseError catch (e, st) {
949
+ assert (debugLog ('$e \n $st ' ));
950
+ }
951
+
952
+ return (spans: spans, texSource: texSource);
915
953
} else {
916
954
return null ;
917
955
}
@@ -927,9 +965,12 @@ String? _parseMath(dom.Element element, {required bool block}) {
927
965
class _ZulipInlineContentParser {
928
966
InlineContentNode ? parseInlineMath (dom.Element element) {
929
967
final debugHtmlNode = kDebugMode ? element : null ;
930
- final texSource = _parseMath (element, block: false );
931
- if (texSource == null ) return null ;
932
- return MathInlineNode (texSource: texSource, debugHtmlNode: debugHtmlNode);
968
+ final parsed = _parseMath (element, block: false );
969
+ if (parsed == null ) return null ;
970
+ return MathInlineNode (
971
+ texSource: parsed.texSource,
972
+ nodes: parsed.spans,
973
+ debugHtmlNode: debugHtmlNode);
933
974
}
934
975
935
976
UserMentionNode ? parseUserMention (dom.Element element) {
@@ -1631,10 +1672,11 @@ class _ZulipContentParser {
1631
1672
})());
1632
1673
1633
1674
final firstChild = nodes.first as dom.Element ;
1634
- final texSource = _parseMath (firstChild, block: true );
1635
- if (texSource != null ) {
1675
+ final parsed = _parseMath (firstChild, block: true );
1676
+ if (parsed != null ) {
1636
1677
result.add (MathBlockNode (
1637
- texSource: texSource,
1678
+ texSource: parsed.texSource,
1679
+ nodes: parsed.spans,
1638
1680
debugHtmlNode: kDebugMode ? firstChild : null ));
1639
1681
} else {
1640
1682
result.add (UnimplementedBlockContentNode (htmlNode: firstChild));
@@ -1666,10 +1708,11 @@ class _ZulipContentParser {
1666
1708
if (child case dom.Text (text: '\n\n ' )) continue ;
1667
1709
1668
1710
if (child case dom.Element (localName: 'span' , className: 'katex-display' )) {
1669
- final texSource = _parseMath (child, block: true );
1670
- if (texSource != null ) {
1711
+ final parsed = _parseMath (child, block: true );
1712
+ if (parsed != null ) {
1671
1713
result.add (MathBlockNode (
1672
- texSource: texSource,
1714
+ texSource: parsed.texSource,
1715
+ nodes: parsed.spans,
1673
1716
debugHtmlNode: debugHtmlNode));
1674
1717
continue ;
1675
1718
}
0 commit comments