Skip to content

Commit 5a9ba2b

Browse files
committed
content: Handle <hr> horizontal lines
Fixes: zulip#353
1 parent 9044a9a commit 5a9ba2b

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

lib/model/content.dart

Lines changed: 17 additions & 0 deletions
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
@@ -962,6 +975,10 @@ class _ZulipContentParser {
962975
return LineBreakNode(debugHtmlNode: debugHtmlNode);
963976
}
964977

978+
if (localName == 'hr' && className.isEmpty) {
979+
return ThematicBreakNode(debugHtmlNode: debugHtmlNode);
980+
}
981+
965982
if (localName == 'p' && className.isEmpty) {
966983
// Oddly, the way a math block gets encoded in Zulip HTML is inside a <p>.
967984
if (element.nodes case [dom.Element(localName: 'span') && var child, ...]) {

lib/widgets/content.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class InheritedMessage extends InheritedWidget {
4747

4848
@override
4949
bool updateShouldNotify(covariant InheritedMessage oldWidget) =>
50-
!identical(oldWidget.message, message);
50+
!identical(oldWidget.message, message);
5151

5252
static Message of(BuildContext context) {
5353
final widget = context.dependOnInheritedWidgetOfExactType<InheritedMessage>();
@@ -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,27 @@ class BlockContentList extends StatelessWidget {
107109
}
108110
}
109111

112+
/// A Divider matching the style found in:
113+
/// [web/styles/rendered_markdown.css](https://github.com/zulip/zulip/blob/main/web/styles/rendered_markdown.css)
114+
class ThematicBreak extends StatelessWidget {
115+
const ThematicBreak({
116+
super.key,
117+
this.thickness = 2,
118+
this.color,
119+
});
120+
121+
final double thickness;
122+
final Color? color;
123+
124+
@override
125+
Widget build(BuildContext context) {
126+
return Divider(
127+
color: color ?? const HSLColor.fromAHSL(1, 0, 0, .87).toColor(),
128+
thickness: 2,
129+
);
130+
}
131+
}
132+
110133
class Paragraph extends StatelessWidget {
111134
const Paragraph({super.key, required this.node});
112135

test/model/content_test.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,24 @@ class ContentExample {
521521
blockUnimplemented('more text'),
522522
]]),
523523
]);
524+
525+
static const thematicBreaks = ContentExample(
526+
'parse thematic break (<hr>) in block context',
527+
'---'
528+
'---'
529+
'a'
530+
'---'
531+
'b'
532+
'---',
533+
'<hr><hr><p>a</p><hr><p>b</p><hr>',
534+
[
535+
ThematicBreakNode(),
536+
ThematicBreakNode(),
537+
ParagraphNode(links: null, nodes: [TextNode('a')]),
538+
ThematicBreakNode(),
539+
ParagraphNode(links: null, nodes: [TextNode('b')]),
540+
ThematicBreakNode(),
541+
]);
524542
}
525543

526544
UnimplementedBlockContentNode blockUnimplemented(String html) {
@@ -875,6 +893,8 @@ void main() {
875893
]]),
876894
]);
877895

896+
testParseExample(ContentExample.thematicBreaks);
897+
878898
test('all content examples are tested', () {
879899
// Check that every ContentExample defined above has a corresponding
880900
// actual test case that runs on it. If you've added a new example

0 commit comments

Comments
 (0)