Skip to content

Commit 9d222da

Browse files
content: Handle multiple math blocks in <p>
Fixes: #1130
1 parent c02d947 commit 9d222da

File tree

2 files changed

+82
-17
lines changed

2 files changed

+82
-17
lines changed

lib/model/content.dart

+64-17
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,60 @@ class _ZulipContentParser {
14511451
return tableNode ?? UnimplementedBlockContentNode(htmlNode: tableElement);
14521452
}
14531453

1454+
List<BlockContentNode> parseMathBlocks(dom.Element element) {
1455+
assert(_debugParserContext == _ParserContext.block);
1456+
assert(element.localName == 'p');
1457+
assert((() {
1458+
final first = element.nodes.first;
1459+
return first is dom.Element
1460+
&& first.localName == 'span'
1461+
&& first.className == 'katex-display';
1462+
})());
1463+
final debugHtmlNode = kDebugMode ? element : null;
1464+
1465+
final blocks = <BlockContentNode>[];
1466+
1467+
// The case with the `<br>\n` can happen when at the end of a quote;
1468+
// it seems like a glitch in the server's Markdown processing,
1469+
// so hopefully there just aren't any further such glitches.
1470+
bool hasTrailingBreakNewline = false;
1471+
if (element.nodes
1472+
case [..., dom.Element(localName: 'br'), dom.Text(text: '\n')]
1473+
) {
1474+
hasTrailingBreakNewline = true;
1475+
}
1476+
1477+
final length = hasTrailingBreakNewline
1478+
? element.nodes.length - 2
1479+
: element.nodes.length;
1480+
for (var i = 0; i < length; i++) {
1481+
final child = element.nodes[i];
1482+
1483+
// If there are multiple <span class="katex-display"> nodes in a <p>
1484+
// each node is interleaved by '\n\n'. Whitespaces are ignored in HTML
1485+
// on web but each node has `display: block`, which renders each node
1486+
// on a newline. So do the same here.
1487+
if (child case dom.Text(text: '\n\n')) continue;
1488+
1489+
if (child is! dom.Element) {
1490+
blocks.add(UnimplementedBlockContentNode(htmlNode: child));
1491+
continue;
1492+
}
1493+
if (child.className != 'katex-display') {
1494+
blocks.add(UnimplementedBlockContentNode(htmlNode: child));
1495+
continue;
1496+
}
1497+
1498+
final texSource = parseMath(child, block: true);
1499+
if (texSource == null) {
1500+
blocks.add(UnimplementedBlockContentNode(htmlNode: child));
1501+
continue;
1502+
}
1503+
blocks.add(MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode));
1504+
}
1505+
return blocks;
1506+
}
1507+
14541508
BlockContentNode parseBlockContent(dom.Node node) {
14551509
assert(_debugParserContext == _ParserContext.block);
14561510
final debugHtmlNode = kDebugMode ? node : null;
@@ -1470,23 +1524,6 @@ class _ZulipContentParser {
14701524
}
14711525

14721526
if (localName == 'p' && className.isEmpty) {
1473-
// Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
1474-
if (element.nodes case [dom.Element(localName: 'span') && var child, ...]) {
1475-
if (child.className == 'katex-display') {
1476-
if (element.nodes case [_]
1477-
|| [_, dom.Element(localName: 'br'),
1478-
dom.Text(text: "\n")]) {
1479-
// This might be too specific; we'll find out when we do #190.
1480-
// The case with the `<br>\n` can happen when at the end of a quote;
1481-
// it seems like a glitch in the server's Markdown processing,
1482-
// so hopefully there just aren't any further such glitches.
1483-
final texSource = parseMath(child, block: true);
1484-
if (texSource == null) return UnimplementedBlockContentNode(htmlNode: node);
1485-
return MathBlockNode(texSource: texSource, debugHtmlNode: debugHtmlNode);
1486-
}
1487-
}
1488-
}
1489-
14901527
final parsed = parseBlockInline(element.nodes);
14911528
return ParagraphNode(debugHtmlNode: debugHtmlNode,
14921529
links: parsed.links,
@@ -1638,6 +1675,16 @@ class _ZulipContentParser {
16381675
continue;
16391676
}
16401677

1678+
// Oddly, the way math blocks get encoded in Zulip HTML is inside a <p>.
1679+
// And there can be multiple math blocks inside the paragraph node, so
1680+
// handle it explicitly here.
1681+
if (node case
1682+
dom.Element(localName: 'p', nodes: [
1683+
dom.Element(localName: 'span', className: 'katex-display'), ...])) {
1684+
result.addAll(parseMathBlocks(node));
1685+
continue;
1686+
}
1687+
16411688
final block = parseBlockContent(node);
16421689
if (block is ImageNode) {
16431690
imageNodes.add(block);

test/model/content_test.dart

+18
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,23 @@ class ContentExample {
506506
'<span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">λ</span></span></span></span></span></p>',
507507
[MathBlockNode(texSource: r'\lambda')]);
508508

509+
static const mathBlocksMultipleInParagraph = ContentExample(
510+
'math blocks, multiple in paragraph',
511+
'```math\na\n\nb\n```',
512+
// https://chat.zulip.org/#narrow/channel/7-test-here/topic/.E2.9C.94.20Rajesh/near/2001490
513+
'<p>'
514+
'<span class="katex-display"><span class="katex">'
515+
'<span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>a</mi></mrow>'
516+
'<annotation encoding="application/x-tex">a</annotation></semantics></math></span>'
517+
'<span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">a</span></span></span></span></span>\n\n'
518+
'<span class="katex-display"><span class="katex">'
519+
'<span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>b</mi></mrow>'
520+
'<annotation encoding="application/x-tex">b</annotation></semantics></math></span>'
521+
'<span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span></span></p>', [
522+
MathBlockNode(texSource: 'a'),
523+
MathBlockNode(texSource: 'b'),
524+
]);
525+
509526
static const mathBlockInQuote = ContentExample(
510527
'math block in quote',
511528
// There's sometimes a quirky extra `<br>\n` at the end of the `<p>` that
@@ -1471,6 +1488,7 @@ void main() {
14711488

14721489
testParseExample(ContentExample.mathBlock);
14731490
testParseExample(ContentExample.mathBlockInQuote);
1491+
testParseExample(ContentExample.mathBlocksMultipleInParagraph);
14741492

14751493
testParseExample(ContentExample.imageSingle);
14761494
testParseExample(ContentExample.imageSingleNoDimensions);

0 commit comments

Comments
 (0)