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
///
@@ -334,23 +336,46 @@ class CodeBlockSpanNode extends ContentNode {
334
336
}
335
337
}
336
338
337
- class MathBlockNode extends BlockContentNode {
338
- const MathBlockNode ({super .debugHtmlNode, required this .texSource});
339
+ class KatexSpan extends ContentNode {
340
+ const KatexSpan ({
341
+ required this .spanClasses,
342
+ required this .spanStyle,
343
+ required this .text,
344
+ this .spans = const [],
345
+ });
339
346
340
- final String texSource;
347
+ final List <String > spanClasses;
348
+ final KatexSpanStyle ? spanStyle;
349
+ final String ? text;
350
+ final List <KatexSpan > spans;
341
351
342
352
@override
343
- bool operator == (Object other) {
344
- return other is MathBlockNode && other.texSource == texSource;
353
+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
354
+ super .debugFillProperties (properties);
355
+ properties.add (StringProperty ('spanClass' , spanClasses.join (', ' )));
356
+ properties.add (KatexSpanStyleProperty ('spanStyle' , spanStyle));
357
+ properties.add (StringProperty ('text' , text));
345
358
}
346
359
347
360
@override
348
- int get hashCode => Object .hash ('MathBlockNode' , texSource);
361
+ List <DiagnosticsNode > debugDescribeChildren () {
362
+ return spans.map ((node) => node.toDiagnosticsNode ()).toList ();
363
+ }
364
+ }
365
+
366
+ class MathBlockNode extends BlockContentNode {
367
+ const MathBlockNode ({
368
+ super .debugHtmlNode,
369
+ required this .texSource,
370
+ required this .spans,
371
+ });
372
+
373
+ final String texSource;
374
+ final List <KatexSpan > spans;
349
375
350
376
@override
351
- void debugFillProperties (DiagnosticPropertiesBuilder properties) {
352
- super .debugFillProperties (properties);
353
- properties.add (StringProperty ('texSource' , texSource));
377
+ List <DiagnosticsNode > debugDescribeChildren () {
378
+ return spans.map ((node) => node.toDiagnosticsNode ()).toList ();
354
379
}
355
380
}
356
381
@@ -1055,12 +1080,12 @@ class _ZulipContentParser {
1055
1080
return inlineParser.parseBlockInline (nodes);
1056
1081
}
1057
1082
1058
- BlockContentNode parseMathBlock (dom.Element element) {
1059
- final debugHtmlNode = kDebugMode ? element : null ;
1060
- final texSource = _parseMath (element, block: true );
1061
- if (texSource == null ) return UnimplementedBlockContentNode (htmlNode: element);
1062
- return MathBlockNode (texSource: texSource, debugHtmlNode: debugHtmlNode);
1063
- }
1083
+ // BlockContentNode parseMathBlock(dom.Element element) {
1084
+ // final debugHtmlNode = kDebugMode ? element : null;
1085
+ // final texSource = _parseMath(element, block: true);
1086
+ // if (texSource == null) return UnimplementedBlockContentNode(htmlNode: element);
1087
+ // return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
1088
+ // }
1064
1089
1065
1090
BlockContentNode parseListNode (dom.Element element) {
1066
1091
ListStyle ? listStyle;
@@ -1453,6 +1478,29 @@ class _ZulipContentParser {
1453
1478
return tableNode ?? UnimplementedBlockContentNode (htmlNode: tableElement);
1454
1479
}
1455
1480
1481
+ BlockContentNode ? parseKatexBlock (dom.Element element) {
1482
+ assert (element.localName == 'span' && element.className == 'katex-display' );
1483
+ if (element.nodes.length != 1 ) return null ;
1484
+ final child = element.nodes.single;
1485
+ if (child is ! dom.Element ) return null ;
1486
+ if (child.localName != 'span' ) return null ;
1487
+ if (child.className != 'katex' ) return null ;
1488
+
1489
+ if (child.nodes.length != 2 ) return null ;
1490
+ final grandchild = child.nodes.last;
1491
+ if (grandchild is ! dom.Element ) return null ;
1492
+ if (grandchild.localName != 'span' ) return null ;
1493
+ if (grandchild.className != 'katex-html' ) return null ;
1494
+
1495
+ try {
1496
+ final spans = parseKatexSpans (grandchild);
1497
+ return MathBlockNode (texSource: '' , spans: spans);
1498
+ } on KatexHtmlParseError catch (e, st) {
1499
+ print ('$e \n $st ' );
1500
+ return null ;
1501
+ }
1502
+ }
1503
+
1456
1504
BlockContentNode parseBlockContent (dom.Node node) {
1457
1505
final debugHtmlNode = kDebugMode ? node : null ;
1458
1506
if (node is ! dom.Element ) {
@@ -1474,15 +1522,18 @@ class _ZulipContentParser {
1474
1522
// Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
1475
1523
if (element.nodes case [dom.Element (localName: 'span' ) && var child, ...]) {
1476
1524
if (child.className == 'katex-display' ) {
1477
- if (element.nodes case [_]
1478
- || [_, dom.Element (localName: 'br' ),
1479
- dom.Text (text: "\n " )]) {
1480
- // This might be too specific; we'll find out when we do #190.
1481
- // The case with the `<br>\n` can happen when at the end of a quote;
1482
- // it seems like a glitch in the server's Markdown processing,
1483
- // so hopefully there just aren't any further such glitches.
1484
- return parseMathBlock (child);
1485
- }
1525
+ // if (element.nodes case [_]
1526
+ // || [_, dom.Element(localName: 'br'),
1527
+ // dom.Text(text: "\n")]) {
1528
+ // // This might be too specific; we'll find out when we do #190.
1529
+ // // The case with the `<br>\n` can happen when at the end of a quote;
1530
+ // // it seems like a glitch in the server's Markdown processing,
1531
+ // // so hopefully there just aren't any further such glitches.
1532
+ // return parseMathBlock(child);
1533
+ // }
1534
+ final block = parseKatexBlock (child);
1535
+ if (block == null ) return UnimplementedBlockContentNode (htmlNode: child);
1536
+ return block;
1486
1537
}
1487
1538
}
1488
1539
0 commit comments