Skip to content

Commit a7d97d5

Browse files
Khader-1gnprice
authored andcommitted
content: Handle <hr> horizontal lines
Fixes: zulip#353
1 parent 8605c7e commit a7d97d5

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

lib/model/content.dart

+17
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,19 @@ class LineBreakNode extends BlockContentNode {
178178
int get hashCode => 'LineBreakNode'.hashCode;
179179
}
180180

181+
/// A `hr` element
182+
class ThematicBreakNode extends BlockContentNode {
183+
const ThematicBreakNode({super.debugHtmlNode});
184+
185+
@override
186+
bool operator ==(Object other) {
187+
return other is ThematicBreakNode;
188+
}
189+
190+
@override
191+
int get hashCode => 'ThematicBreakNode'.hashCode;
192+
}
193+
181194
/// A `p` element, or a place where the DOM tree logically wanted one.
182195
///
183196
/// We synthesize these in the absence of an actual `p` element in cases where
@@ -969,6 +982,10 @@ class _ZulipContentParser {
969982
return LineBreakNode(debugHtmlNode: debugHtmlNode);
970983
}
971984

985+
if (localName == 'hr' && className.isEmpty) {
986+
return ThematicBreakNode(debugHtmlNode: debugHtmlNode);
987+
}
988+
972989
if (localName == 'p' && className.isEmpty) {
973990
// Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
974991
if (element.nodes case [dom.Element(localName: 'span') && var child, ...]) {

lib/widgets/content.dart

+18
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ class BlockContentList extends StatelessWidget {
7474
// This goes in a Column. So to get the effect of a newline,
7575
// just use an empty Text.
7676
return const Text('');
77+
} else if (node is ThematicBreakNode) {
78+
return const ThematicBreak();
7779
} else if (node is ParagraphNode) {
7880
return Paragraph(node: node);
7981
} else if (node is HeadingNode) {
@@ -107,6 +109,22 @@ class BlockContentList extends StatelessWidget {
107109
}
108110
}
109111

112+
class ThematicBreak extends StatelessWidget {
113+
const ThematicBreak({super.key});
114+
115+
static const htmlHeight = 2.0;
116+
static const htmlMarginY = 20.0;
117+
118+
@override
119+
Widget build(BuildContext context) {
120+
return Divider(
121+
color: const HSLColor.fromAHSL(1, 0, 0, .87).toColor(),
122+
thickness: htmlHeight,
123+
height: 2 * htmlMarginY + htmlHeight,
124+
);
125+
}
126+
}
127+
110128
class Paragraph extends StatelessWidget {
111129
const Paragraph({super.key, required this.node});
112130

test/model/content_test.dart

+13
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,17 @@ class ContentExample {
521521
blockUnimplemented('more text'),
522522
]]),
523523
]);
524+
525+
static const thematicBreak = ContentExample(
526+
'parse thematic break (<hr>)',
527+
// https://chat.zulip.org/#narrow/stream/7-test-here/near/1774718
528+
'a\n---\nb',
529+
'<p>a</p>\n<hr>\n<p>b</p>',
530+
[
531+
ParagraphNode(links: null, nodes: [TextNode('a')]),
532+
ThematicBreakNode(),
533+
ParagraphNode(links: null, nodes: [TextNode('b')]),
534+
]);
524535
}
525536

526537
UnimplementedBlockContentNode blockUnimplemented(String html) {
@@ -721,6 +732,8 @@ void main() {
721732
LineBreakNode(),
722733
]);
723734

735+
testParseExample(ContentExample.thematicBreak);
736+
724737
testParse('parse two plain-text paragraphs',
725738
// "hello\n\nworld"
726739
'<p>hello</p>\n<p>world</p>', const [

test/widgets/content_test.dart

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ void main() {
6262
});
6363
}
6464

65+
group('ThematicBreak', () {
66+
testWidgets('smoke ThematicBreak', (tester) async {
67+
await prepareContentBare(tester, ContentExample.thematicBreak.html);
68+
tester.widget(find.byType(ThematicBreak));
69+
});
70+
});
71+
6572
group('Heading', () {
6673
testWidgets('plain h6', (tester) async {
6774
await prepareContentBare(tester,

0 commit comments

Comments
 (0)