@@ -1453,6 +1453,61 @@ 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 (MathBlockNode (texSource: texSource, debugHtmlNode: child));
1503
+ continue ;
1504
+ }
1505
+ }
1506
+
1507
+ result.add (UnimplementedBlockContentNode (htmlNode: child));
1508
+ }
1509
+ }
1510
+
1456
1511
BlockContentNode parseBlockContent (dom.Node node) {
1457
1512
final debugHtmlNode = kDebugMode ? node : null ;
1458
1513
if (node is ! dom.Element ) {
@@ -1471,21 +1526,6 @@ class _ZulipContentParser {
1471
1526
}
1472
1527
1473
1528
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
1529
final parsed = parseBlockInline (element.nodes);
1490
1530
return ParagraphNode (debugHtmlNode: debugHtmlNode,
1491
1531
links: parsed.links,
@@ -1599,6 +1639,18 @@ class _ZulipContentParser {
1599
1639
for (final node in nodes) {
1600
1640
if (node is dom.Text && (node.text == '\n ' )) continue ;
1601
1641
1642
+ // Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1643
+ // And there can be multiple math blocks inside the paragraph node, so
1644
+ // handle it explicitly here.
1645
+ if (node case
1646
+ dom.Element (localName: 'p' , nodes: [
1647
+ dom.Element (localName: 'span' , className: 'katex-display' ), ...])) {
1648
+ if (currentParagraph.isNotEmpty) consumeParagraph ();
1649
+ if (imageNodes.isNotEmpty) consumeImageNodes ();
1650
+ parseMathBlocks (node.nodes, result);
1651
+ continue ;
1652
+ }
1653
+
1602
1654
if (_isPossibleInlineNode (node)) {
1603
1655
if (imageNodes.isNotEmpty) {
1604
1656
consumeImageNodes ();
@@ -1642,6 +1694,17 @@ class _ZulipContentParser {
1642
1694
continue ;
1643
1695
}
1644
1696
1697
+ // Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1698
+ // And there can be multiple math blocks inside the paragraph node, so
1699
+ // handle it explicitly here.
1700
+ if (node case
1701
+ dom.Element (localName: 'p' , nodes: [
1702
+ dom.Element (localName: 'span' , className: 'katex-display' ), ...])) {
1703
+ if (imageNodes.isNotEmpty) consumeImageNodes ();
1704
+ parseMathBlocks (node.nodes, result);
1705
+ continue ;
1706
+ }
1707
+
1645
1708
final block = parseBlockContent (node);
1646
1709
if (block is ImageNode ) {
1647
1710
imageNodes.add (block);
0 commit comments