1
0
mirror of https://github.com/meineerde/redmine.git synced 2026-01-31 11:37:14 +00:00

Enable CommonMark alert extension (#42603).

Patch by Mizuki ISHIKAWA (user:ishikawa999).

git-svn-id: https://svn.redmine.org/redmine/trunk@23724 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Marius Balteanu 2025-04-29 21:13:55 +00:00
parent 0dc7337c7d
commit 8fa4c44581
5 changed files with 127 additions and 9 deletions

View File

@ -1262,6 +1262,38 @@ 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: 0;
}
.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 */

View File

@ -34,6 +34,7 @@ module Redmine
header_ids: nil,
tasklist: true,
shortcodes: false,
alerts: true,
}.freeze,
# https://github.com/gjtorikian/commonmarker#parse-options

View File

@ -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

View File

@ -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
<tag> 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 "<div class=\"markdown-alert markdown-alert-note\">\n<p class=\"markdown-alert-title\">Note</p>\n<p>This is a note.</p>\n</div>", 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 "<blockquote>", 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)

View File

@ -71,6 +71,32 @@ if Object.const_defined?(:Commonmarker)
assert_equal %(<code>foo</code>), filter(input)
end
def test_should_allow_valid_alert_div_and_p_classes
html = <<~HTML
<div class="markdown-alert markdown-alert-tip">
<p class="markdown-alert-title">Tip</p>
<p>Useful tip.</p>
</div>
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 = '<div class="bad-class">Text</div>'
sanitized = filter(html)
refute_include 'bad-class', sanitized
end
def test_should_remove_invalid_p_class
html = '<p class="bad-class">Text</p>'
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 = %(<a href="#{scheme}://example.org/">foo</a>)