From 5eed4cd2b5881ec56bf62d4fcabefcb1349a2426 Mon Sep 17 00:00:00 2001 From: Istvan Soos Date: Tue, 10 Sep 2024 10:37:05 +0200 Subject: [PATCH] Transform GitHub markdown task list's rendered into icons. --- app/lib/shared/markdown.dart | 34 ++++++++++++++++++++++++++++++ app/test/shared/markdown_test.dart | 11 ++++++++++ 2 files changed, 45 insertions(+) diff --git a/app/lib/shared/markdown.dart b/app/lib/shared/markdown.dart index 1b6d73877..75feb5099 100644 --- a/app/lib/shared/markdown.dart +++ b/app/lib/shared/markdown.dart @@ -97,6 +97,8 @@ String _renderSafeHtml( }) { // Filter unsafe urls on some of the elements. nodes.forEach((node) => node.accept(_UnsafeUrlFilter())); + // Transform GitHub task lists. + nodes.forEach((node) => node.accept(_TaskListRewriteNodeVisitor())); if (!disableHashIds) { // add hash link HTML to header blocks @@ -277,6 +279,38 @@ class _RelativeUrlRewriter implements m.NodeVisitor { } } +/// HTML sanitization will remove the rendered `` elements, +/// we are replacing them with icons. +class _TaskListRewriteNodeVisitor implements m.NodeVisitor { + @override + void visitElementAfter(m.Element element) { + if (element.tag != 'li') { + return; + } + if (!(element.attributes['class']?.contains('task-list-item') ?? false)) { + return; + } + final children = element.children; + if (children == null || children.isEmpty) { + return null; + } + final first = children.first; + if (first is m.Element && + first.tag == 'input' && + first.attributes['type'] == 'checkbox') { + final checked = first.attributes['checked'] == 'true'; + children.removeAt(0); + children.insert(0, m.Text(checked ? '✅ ' : '❌ ')); + } + } + + @override + bool visitElementBefore(m.Element element) => true; + + @override + void visitText(m.Text text) {} +} + bool _isAbsolute(String url) => url.contains(':'); String _rewriteAbsoluteUrl(String url) { diff --git a/app/test/shared/markdown_test.dart b/app/test/shared/markdown_test.dart index 2d63aaae7..7031d2184 100644 --- a/app/test/shared/markdown_test.dart +++ b/app/test/shared/markdown_test.dart @@ -15,6 +15,17 @@ void main() { expect(markdownToHtml('# ABC def'), '

ABC def #

\n'); }); + + test('task list', () { + expect( + markdownToHtml('- [ ] a\n- [X] b\n- [ ] c\n'), + '\n', + ); + }); }); group('Valid custom base URL', () {