From 53e525e975b1bfcdbb716f8f48858bacbec22581 Mon Sep 17 00:00:00 2001 From: ishikawa999 Date: Mon, 28 Apr 2025 01:59:05 +0000 Subject: [PATCH] Enable common_mark alerts --- app/assets/stylesheets/application.css | 33 +++++++++++ .../wiki_formatting/common_mark/formatter.rb | 1 + .../common_mark/sanitization_filter.rb | 20 +++++++ .../common_mark/formatter_test.rb | 57 ++++++++++++++++--- .../common_mark/sanitization_filter_test.rb | 26 +++++++++ 5 files changed, 128 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 7dc1a64b4..f0ffcf276 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -1262,6 +1262,39 @@ div.flash.warning svg.icon-svg, .conflict svg.icon-svg { .conflict-details {font-size:93%;} +/***** CommonMark Alerts *****/ + +.markdown-alert { + border-left: 4px solid; + padding: 10px 10px 1px 10px; + margin: 10px 0; +} + +.markdown-alert-title + p { + margin-top: 2px; +} + +.markdown-alert-title { + font-weight: bold; + margin-bottom: 0.5em; + margin: 0px; +} + +.markdown-alert-tip { border-color: #5db651; } +.markdown-alert-tip .markdown-alert-title { color: #005f00; } + +.markdown-alert-important { border-color: #800080; } +.markdown-alert-important .markdown-alert-title { color: #4b006e; } + +.markdown-alert-caution { border-color: #c22; } +.markdown-alert-caution .markdown-alert-title { color: #880000; } + +.markdown-alert-warning { border-color: #e4bc4b; } +.markdown-alert-warning .markdown-alert-title { color: #a7760c; } + +.markdown-alert-note { border-color: #169; } +.markdown-alert-note .markdown-alert-title { color: #1e40af; } + /***** Ajax indicator ******/ #ajax-indicator { position: absolute; /* fixed not supported by IE */ diff --git a/lib/redmine/wiki_formatting/common_mark/formatter.rb b/lib/redmine/wiki_formatting/common_mark/formatter.rb index b695fb854..f2b9bca04 100644 --- a/lib/redmine/wiki_formatting/common_mark/formatter.rb +++ b/lib/redmine/wiki_formatting/common_mark/formatter.rb @@ -34,6 +34,7 @@ module Redmine header_ids: nil, tasklist: true, shortcodes: false, + alerts: true, }.freeze, # https://github.com/gjtorikian/commonmarker#parse-options diff --git a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb index e603d9f7f..584df9e0d 100644 --- a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb +++ b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb @@ -68,6 +68,26 @@ module Redmine end } + # Allow class on div and p tags only for alert blocks + # (must be exactly: "markdown-alert markdown-alert-*" for div, and "markdown-alert-title" for p) + (allowlist[:attributes]["div"] ||= []) << "class" + (allowlist[:attributes]["p"] ||= []) << "class" + allowlist[:transformers].push lambda{|env| + node = env[:node] + return unless node.element? + + case node.name + when 'div' + unless node['class'] =~ /\Amarkdown-alert markdown-alert-[a-z]+\z/ + node.remove_attribute('class') + end + when 'p' + unless node['class'] == 'markdown-alert-title' + node.remove_attribute('class') + end + end + } + # Allow table cell alignment by style attribute # # Only necessary if we used the TABLE_PREFER_STYLE_ATTRIBUTES diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb index 79581a928..d9a84a2c2 100644 --- a/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb @@ -163,39 +163,39 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase # 0 <<~STR.chomp, # Title - + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. STR # 1 <<~STR.chomp, ## Heading 2 - + ~~~ruby def foo end ~~~ - + Morbi facilisis accumsan orci non pharetra. - + ~~~ ruby def foo end ~~~ - + ``` Pre Content: - + ## Inside pre - + inside pre block - + Morbi facilisis accumsan orci non pharetra. ``` STR # 2 <<~STR.chomp, ### Heading 3 - + Nulla nunc nisi, egestas in ornare vel, posuere ac libero. STR ] @@ -299,6 +299,45 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase assert_equal expected.gsub(%r{[\r\n\t]}, ''), to_html(text).gsub(%r{[\r\n\t]}, '').rstrip end + def test_should_render_alert_blocks + text = <<~MD + > [!note] + > This is a note. + + > [!tip] + > This is a tip. + + > [!warning] + > This is a warning. + + > [!caution] + > This is a caution. + + > [!important] + > This is a important. + MD + + html = to_html(text) + %w[note tip warning caution important].each do |alert| + assert_include "
\n

Note

\n

This is a note.

\n
", html + end + end + + def test_should_not_render_unknown_alert_type + text = <<~MD + > [!unknown] + > This should not become an alert. + MD + + html = to_html(text) + + assert_include "
", html + assert_include "[!unknown]", html + assert_include "This should not become an alert.", html + + assert_not_include 'markdown-alert', html + end + private def assert_section_with_hash(expected, text, index) diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb index 4c0282f2d..d17c2a09f 100644 --- a/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb @@ -71,6 +71,32 @@ if Object.const_defined?(:Commonmarker) assert_equal %(foo), filter(input) end + def test_should_allow_valid_alert_div_and_p_classes + html = <<~HTML +
+

Tip

+

Useful tip.

+
+ HTML + + sanitized = filter(html) + + assert_include 'class="markdown-alert markdown-alert-tip"', sanitized + assert_include 'class="markdown-alert-title"', sanitized + end + + def test_should_remove_invalid_div_class + html = '
Text
' + sanitized = filter(html) + refute_include 'bad-class', sanitized + end + + def test_should_remove_invalid_p_class + html = '

Text

' + sanitized = filter(html) + assert_not_include 'bad-class', sanitized + end + def test_should_allow_links_with_safe_url_schemes %w(http https ftp ssh foo).each do |scheme| input = %(foo) -- 2.49.0