@@ -1453,6 +1453,62 @@ class _ZulipContentParser {
1453
1453
return tableNode ?? UnimplementedBlockContentNode (htmlNode: tableElement);
1454
1454
}
1455
1455
1456
+ void parseMathBlocks (dom.NodeList nodes, List <BlockContentNode > result) {
1457
+ assert (nodes.isNotEmpty);
1458
+ assert ((() {
1459
+ final first = nodes.first;
1460
+ return first is dom.Element
1461
+ && first.localName == 'span'
1462
+ && first.className == 'katex-display' ;
1463
+ })());
1464
+
1465
+ final firstChild = nodes.first as dom.Element ;
1466
+ final texSource = _parseMath (firstChild, block: true );
1467
+ if (texSource != null ) {
1468
+ result.add (MathBlockNode (texSource: texSource, debugHtmlNode: firstChild));
1469
+ } else {
1470
+ result.add (UnimplementedBlockContentNode (htmlNode: firstChild));
1471
+ }
1472
+
1473
+ // Skip further checks if there was only a single child.
1474
+ if (nodes.length == 1 ) return ;
1475
+
1476
+ // The case with the `<br>\n` can happen when at the end of a quote;
1477
+ // it seems like a glitch in the server's Markdown processing,
1478
+ // so hopefully there just aren't any further such glitches.
1479
+ bool hasTrailingBreakNewline = false ;
1480
+ if (nodes
1481
+ case [..., dom.Element (localName: 'br' ), dom.Text (text: '\n ' )]
1482
+ ) {
1483
+ hasTrailingBreakNewline = true ;
1484
+ }
1485
+
1486
+ final length = hasTrailingBreakNewline
1487
+ ? nodes.length - 2
1488
+ : nodes.length;
1489
+ for (int i = 1 ; i < length; i++ ) {
1490
+ final child = nodes[i];
1491
+
1492
+ // If there are multiple <span class="katex-display"> nodes in a <p>
1493
+ // each node is interleaved by '\n\n'. Whitespaces are ignored in HTML
1494
+ // on web but each node has `display: block`, which renders each node
1495
+ // on a newline. Since the emitted MathBlockNode are BlockContentNode,
1496
+ // we skip these newlines here to replicate the same behavior as on web.
1497
+ if (child case dom.Text (text: '\n\n ' )) continue ;
1498
+
1499
+ if (child case dom.Element (localName: 'span' , className: 'katex-display' )) {
1500
+ final texSource = _parseMath (child, block: true );
1501
+ if (texSource == null ) {
1502
+ result.add (UnimplementedBlockContentNode (htmlNode: child));
1503
+ continue ;
1504
+ }
1505
+ result.add (MathBlockNode (texSource: texSource, debugHtmlNode: child));
1506
+ } else {
1507
+ result.add (UnimplementedBlockContentNode (htmlNode: child));
1508
+ }
1509
+ }
1510
+ }
1511
+
1456
1512
BlockContentNode parseBlockContent (dom.Node node) {
1457
1513
final debugHtmlNode = kDebugMode ? node : null ;
1458
1514
if (node is ! dom.Element ) {
@@ -1471,21 +1527,6 @@ class _ZulipContentParser {
1471
1527
}
1472
1528
1473
1529
if (localName == 'p' && className.isEmpty) {
1474
- // Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
1475
- if (element.nodes case [dom.Element (localName: 'span' ) && var child, ...]) {
1476
- 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
- }
1486
- }
1487
- }
1488
-
1489
1530
final parsed = parseBlockInline (element.nodes);
1490
1531
return ParagraphNode (debugHtmlNode: debugHtmlNode,
1491
1532
links: parsed.links,
@@ -1599,6 +1640,18 @@ class _ZulipContentParser {
1599
1640
for (final node in nodes) {
1600
1641
if (node is dom.Text && (node.text == '\n ' )) continue ;
1601
1642
1643
+ // Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1644
+ // And there can be multiple math blocks inside the paragraph node, so
1645
+ // handle it explicitly here.
1646
+ if (node case
1647
+ dom.Element (localName: 'p' , nodes: [
1648
+ dom.Element (localName: 'span' , className: 'katex-display' ), ...])) {
1649
+ if (currentParagraph.isNotEmpty) consumeParagraph ();
1650
+ if (imageNodes.isNotEmpty) consumeImageNodes ();
1651
+ parseMathBlocks (node.nodes, result);
1652
+ continue ;
1653
+ }
1654
+
1602
1655
if (_isPossibleInlineNode (node)) {
1603
1656
if (imageNodes.isNotEmpty) {
1604
1657
consumeImageNodes ();
@@ -1642,6 +1695,17 @@ class _ZulipContentParser {
1642
1695
continue ;
1643
1696
}
1644
1697
1698
+ // Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1699
+ // And there can be multiple math blocks inside the paragraph node, so
1700
+ // handle it explicitly here.
1701
+ if (node case
1702
+ dom.Element (localName: 'p' , nodes: [
1703
+ dom.Element (localName: 'span' , className: 'katex-display' ), ...])) {
1704
+ if (imageNodes.isNotEmpty) consumeImageNodes ();
1705
+ parseMathBlocks (node.nodes, result);
1706
+ continue ;
1707
+ }
1708
+
1645
1709
final block = parseBlockContent (node);
1646
1710
if (block is ImageNode ) {
1647
1711
imageNodes.add (block);
0 commit comments