@@ -1055,13 +1055,6 @@ class _ZulipContentParser {
10551055 return inlineParser.parseBlockInline (nodes);
10561056 }
10571057
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- }
1064-
10651058 BlockContentNode parseListNode (dom.Element element) {
10661059 ListStyle ? listStyle;
10671060 switch (element.localName) {
@@ -1453,6 +1446,64 @@ class _ZulipContentParser {
14531446 return tableNode ?? UnimplementedBlockContentNode (htmlNode: tableElement);
14541447 }
14551448
1449+ void parseMathBlocks (dom.NodeList nodes, List <BlockContentNode > result) {
1450+ assert (nodes.isNotEmpty);
1451+ assert ((() {
1452+ final first = nodes.first;
1453+ return first is dom.Element
1454+ && first.localName == 'span'
1455+ && first.className == 'katex-display' ;
1456+ })());
1457+
1458+ final firstChild = nodes.first as dom.Element ;
1459+ final texSource = _parseMath (firstChild, block: true );
1460+ if (texSource != null ) {
1461+ result.add (MathBlockNode (
1462+ texSource: texSource,
1463+ debugHtmlNode: kDebugMode ? firstChild : null ));
1464+ } else {
1465+ result.add (UnimplementedBlockContentNode (htmlNode: firstChild));
1466+ }
1467+
1468+ // Skip further checks if there was only a single child.
1469+ if (nodes.length == 1 ) return ;
1470+
1471+ // The case with the `<br>\n` can happen when at the end of a quote;
1472+ // it seems like a glitch in the server's Markdown processing,
1473+ // so hopefully there just aren't any further such glitches.
1474+ bool hasTrailingBreakNewline = false ;
1475+ if (nodes case [..., dom.Element (localName: 'br' ), dom.Text (text: '\n ' )]) {
1476+ hasTrailingBreakNewline = true ;
1477+ }
1478+
1479+ final length = hasTrailingBreakNewline
1480+ ? nodes.length - 2
1481+ : nodes.length;
1482+ for (int i = 1 ; i < length; i++ ) {
1483+ final child = nodes[i];
1484+ final debugHtmlNode = kDebugMode ? child : null ;
1485+
1486+ // If there are multiple <span class="katex-display"> nodes in a <p>
1487+ // each node is interleaved by '\n\n'. Whitespaces are ignored in HTML
1488+ // on web but each node has `display: block`, which renders each node
1489+ // on a new line. Since the emitted MathBlockNode are BlockContentNode,
1490+ // we skip these newlines here to replicate the same behavior as on web.
1491+ if (child case dom.Text (text: '\n\n ' )) continue ;
1492+
1493+ if (child case dom.Element (localName: 'span' , className: 'katex-display' )) {
1494+ final texSource = _parseMath (child, block: true );
1495+ if (texSource != null ) {
1496+ result.add (MathBlockNode (
1497+ texSource: texSource,
1498+ debugHtmlNode: debugHtmlNode));
1499+ continue ;
1500+ }
1501+ }
1502+
1503+ result.add (UnimplementedBlockContentNode (htmlNode: child));
1504+ }
1505+ }
1506+
14561507 BlockContentNode parseBlockContent (dom.Node node) {
14571508 final debugHtmlNode = kDebugMode ? node : null ;
14581509 if (node is ! dom.Element ) {
@@ -1584,27 +1635,14 @@ class _ZulipContentParser {
15841635 for (final node in nodes) {
15851636 if (node is dom.Text && (node.text == '\n ' )) continue ;
15861637
1587- // Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
1638+ // Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1639+ // And there can be multiple math blocks inside the paragraph node, so
1640+ // handle it explicitly here.
15881641 if (node case dom.Element (localName: 'p' , className: '' , nodes: [
1589- dom.Element (
1590- localName: 'span' ,
1591- className: 'katex-display' ) && final child, ...])) {
1592- final BlockContentNode parsed;
1593- if (node.nodes case [_]
1594- || [_, dom.Element (localName: 'br' ),
1595- dom.Text (text: "\n " )]) {
1596- // This might be too specific; we'll find out when we do #190.
1597- // The case with the `<br>\n` can happen when at the end of a quote;
1598- // it seems like a glitch in the server's Markdown processing,
1599- // so hopefully there just aren't any further such glitches.
1600- parsed = parseMathBlock (child);
1601- } else {
1602- parsed = UnimplementedBlockContentNode (htmlNode: node);
1603- }
1604-
1642+ dom.Element (localName: 'span' , className: 'katex-display' ), ...])) {
16051643 if (currentParagraph.isNotEmpty) consumeParagraph ();
16061644 if (imageNodes.isNotEmpty) consumeImageNodes ();
1607- result. add (parsed );
1645+ parseMathBlocks (node.nodes, result );
16081646 continue ;
16091647 }
16101648
@@ -1651,26 +1689,13 @@ class _ZulipContentParser {
16511689 continue ;
16521690 }
16531691
1654- // Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
1692+ // Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1693+ // And there can be multiple math blocks inside the paragraph node, so
1694+ // handle it explicitly here.
16551695 if (node case dom.Element (localName: 'p' , className: '' , nodes: [
1656- dom.Element (
1657- localName: 'span' ,
1658- className: 'katex-display' ) && final child, ...])) {
1659- final BlockContentNode parsed;
1660- if (node.nodes case [_]
1661- || [_, dom.Element (localName: 'br' ),
1662- dom.Text (text: "\n " )]) {
1663- // This might be too specific; we'll find out when we do #190.
1664- // The case with the `<br>\n` can happen when at the end of a quote;
1665- // it seems like a glitch in the server's Markdown processing,
1666- // so hopefully there just aren't any further such glitches.
1667- parsed = parseMathBlock (child);
1668- } else {
1669- parsed = UnimplementedBlockContentNode (htmlNode: node);
1670- }
1671-
1696+ dom.Element (localName: 'span' , className: 'katex-display' ), ...])) {
16721697 if (imageNodes.isNotEmpty) consumeImageNodes ();
1673- result. add (parsed );
1698+ parseMathBlocks (node.nodes, result );
16741699 continue ;
16751700 }
16761701
0 commit comments