11import 'package:collection/collection.dart' ;
22import 'package:flutter/foundation.dart' ;
3+ import 'package:flutter/widgets.dart' ;
34import 'package:html/dom.dart' as dom;
45import 'package:html/parser.dart' ;
56
67import '../api/model/model.dart' ;
78import '../api/model/submessage.dart' ;
89import 'code_block.dart' ;
10+ import 'katex.dart' ;
911
1012/// A node in a parse tree for Zulip message-style content.
1113///
@@ -340,23 +342,46 @@ class CodeBlockSpanNode extends ContentNode {
340342 }
341343}
342344
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+ });
345352
346- final String texSource;
353+ final List <String > spanClasses;
354+ final KatexSpanStyle ? spanStyle;
355+ final String ? text;
356+ final List <KatexSpan > spans;
347357
348358 @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));
351364 }
352365
353366 @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;
355381
356382 @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 ();
360385 }
361386}
362387
@@ -1113,6 +1138,13 @@ class _ZulipContentParser {
11131138 return inlineParser.parseBlockInline (nodes);
11141139 }
11151140
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+
11161148 BlockContentNode parseListNode (dom.Element element) {
11171149 assert (element.localName == 'ol' || element.localName == 'ul' );
11181150 assert (element.className.isEmpty);
@@ -1624,11 +1656,9 @@ class _ZulipContentParser {
16241656 })());
16251657
16261658 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);
16321662 } else {
16331663 result.add (UnimplementedBlockContentNode (htmlNode: firstChild));
16341664 }
@@ -1649,7 +1679,6 @@ class _ZulipContentParser {
16491679 : nodes.length;
16501680 for (int i = 1 ; i < length; i++ ) {
16511681 final child = nodes[i];
1652- final debugHtmlNode = kDebugMode ? child : null ;
16531682
16541683 // If there are multiple <span class="katex-display"> nodes in a <p>
16551684 // each node is interleaved by '\n\n'. Whitespaces are ignored in HTML
@@ -1659,11 +1688,9 @@ class _ZulipContentParser {
16591688 if (child case dom.Text (text: '\n\n ' )) continue ;
16601689
16611690 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);
16671694 continue ;
16681695 }
16691696 }
@@ -1672,6 +1699,33 @@ class _ZulipContentParser {
16721699 }
16731700 }
16741701
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+
16751729 BlockContentNode parseBlockContent (dom.Node node) {
16761730 final debugHtmlNode = kDebugMode ? node : null ;
16771731 if (node is ! dom.Element ) {
0 commit comments