From 9af2ba2c13d2dc706bdf1387110c13b82175a0cf Mon Sep 17 00:00:00 2001
From: Marius Balteanu
Date: Wed, 11 Aug 2021 21:40:56 +0000
Subject: [PATCH] Adds CommonMark Markdown (GitHub Flavored) as third text
formatting option (#32424).
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit
Patch by Jens Krämer.
git-svn-id: http://svn.redmine.org/redmine/trunk@21156 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
Gemfile | 7 +
lib/redmine.rb | 8 +
.../common_mark/external_links_filter.rb | 48 +++
.../common_mark/fixup_auto_links_filter.rb | 51 +++
.../wiki_formatting/common_mark/formatter.rb | 66 ++++
.../wiki_formatting/common_mark/helper.rb | 57 +++
.../common_mark/html_parser.rb | 26 ++
.../common_mark/markdown_filter.rb | 57 +++
.../common_mark/sanitization_filter.rb | 86 +++++
.../common_mark/syntax_highlight_filter.rb | 50 +++
public/help/en/wiki_syntax_common_mark.html | 87 +++++
.../en/wiki_syntax_detailed_common_mark.html | 361 ++++++++++++++++++
public/help/wiki_syntax_detailed.css | 3 +
.../common_mark/application_helper_test.rb | 66 ++++
.../common_mark/external_links_filter_test.rb | 48 +++
.../fixup_auto_links_filter_test.rb | 50 +++
.../common_mark/formatter_test.rb | 270 +++++++++++++
.../common_mark/markdown_filter_test.rb | 35 ++
.../common_mark/sanitization_filter_test.rb | 211 ++++++++++
.../syntax_highlight_filter_test.rb | 75 ++++
20 files changed, 1662 insertions(+)
create mode 100644 lib/redmine/wiki_formatting/common_mark/external_links_filter.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/formatter.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/helper.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/html_parser.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/markdown_filter.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
create mode 100644 lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter.rb
create mode 100644 public/help/en/wiki_syntax_common_mark.html
create mode 100644 public/help/en/wiki_syntax_detailed_common_mark.html
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
create mode 100644 test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb
diff --git a/Gemfile b/Gemfile
index 21fe38266..08879c5a1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -47,6 +47,13 @@ group :markdown do
gem 'redcarpet', '~> 3.5.1'
end
+# Optional CommonMark support, not for JRuby
+group :common_mark do
+ gem "html-pipeline", "~> 2.12"
+ gem "commonmarker", "~> 0.20"
+ gem "sanitize", "~> 5.1"
+end
+
# Include database gems for the adapters found in the database
# configuration file
require 'erb'
diff --git a/lib/redmine.rb b/lib/redmine.rb
index 1328935da..937504892 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -29,6 +29,11 @@ begin
rescue LoadError
# Redcarpet is not available
end
+begin
+ require 'commonmarker' unless Object.const_defined?(:CommonMarker)
+rescue LoadError
+ # CommonMarker is not available
+end
require 'redmine/acts/positioned'
@@ -442,6 +447,9 @@ end
Redmine::WikiFormatting.map do |format|
format.register :textile
format.register :markdown if Object.const_defined?(:Redcarpet)
+ if Object.const_defined?(:CommonMarker)
+ format.register :common_mark, label: 'CommonMark Markdown (GitHub Flavored)'
+ end
end
ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
diff --git a/lib/redmine/wiki_formatting/common_mark/external_links_filter.rb b/lib/redmine/wiki_formatting/common_mark/external_links_filter.rb
new file mode 100644
index 000000000..023593b5a
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/external_links_filter.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require 'uri'
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # adds class="external" to external links, and class="email" to mailto
+ # links
+ class ExternalLinksFilter < HTML::Pipeline::Filter
+ def call
+ doc.search("a").each do |node|
+ url = node["href"]
+ next unless url
+ next if url.starts_with?("/") || url.starts_with?("#") || !url.include?(':')
+
+ scheme = URI.parse(url).scheme
+ next if scheme.blank?
+
+ klass = node["class"].presence
+ node["class"] = [
+ klass,
+ (scheme == "mailto" ? "email" : "external")
+ ].compact.join " "
+ end
+ doc
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter.rb b/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter.rb
new file mode 100644
index 000000000..94120bccf
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # fixes:
+ # - autolinked email addresses that are actually references to users:
+ # user:user@example.org
+ # @user@example.org
+ # - autolinked hi res image names that look like email addresses:
+ # printscreen@2x.png
+ class FixupAutoLinksFilter < HTML::Pipeline::Filter
+ USER_LINK_PREFIX = /(@|user:)\z/.freeze
+ HIRES_IMAGE = /.+@\dx\.(bmp|gif|jpg|jpe|jpeg|png)\z/.freeze
+
+ def call
+ doc.search("a").each do |node|
+ unless (url = node['href']) && url.starts_with?('mailto:')
+ next
+ end
+
+ if ((p = node.previous) && p.text? &&
+ p.text =~(USER_LINK_PREFIX)) ||
+ (node.text =~ HIRES_IMAGE)
+
+ node.replace node.text
+ end
+ end
+ doc
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/formatter.rb b/lib/redmine/wiki_formatting/common_mark/formatter.rb
new file mode 100644
index 000000000..6a9c95c8e
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/formatter.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require 'html/pipeline'
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # configuration of the rendering pipeline
+ PIPELINE_CONFIG = {
+ # https://github.com/gjtorikian/commonmarker#extensions
+ commonmarker_extensions: [
+ :table,
+ :strikethrough,
+ :tagfilter,
+ :autolink
+ ].freeze,
+
+ # https://github.com/gjtorikian/commonmarker#parse-options
+ commonmarker_parse_options: [
+ :FOOTNOTES,
+ :STRIKETHROUGH_DOUBLE_TILDE,
+ :UNSAFE,
+ :VALIDATE_UTF8
+ ].freeze,
+
+ # https://github.com/gjtorikian/commonmarker#render-options
+ commonmarker_render_options: [
+ :HARDBREAKS,
+ :UNSAFE
+ ].freeze,
+ }.freeze
+
+ MarkdownPipeline = HTML::Pipeline.new [
+ MarkdownFilter,
+ SanitizationFilter,
+ SyntaxHighlightFilter,
+ FixupAutoLinksFilter,
+ ExternalLinksFilter,
+ ], PIPELINE_CONFIG
+
+ class Formatter < Redmine::WikiFormatting::Markdown::Formatter
+ def to_html(*args)
+ result = MarkdownPipeline.call @text
+ result[:output].to_s
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/helper.rb b/lib/redmine/wiki_formatting/common_mark/helper.rb
new file mode 100644
index 000000000..471835708
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/helper.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ module Helper
+ include Redmine::WikiFormatting::Markdown::Helper
+
+ def wikitoolbar_for(field_id, preview_url = preview_text_path)
+ heads_for_wiki_formatter
+ help_file = "/help/#{current_language.to_s.downcase}/wiki_syntax_common_mark.html"
+ # fall back to the english help page if there is none for the current
+ # language
+ unless File.readable? Rails.root.join("public", help_file)
+ help_file = "/help/en/wiki_syntax_common_mark.html"
+ end
+ url = "#{Redmine::Utils.relative_url_root}#{help_file}"
+ javascript_tag(
+ "var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); " \
+ "wikiToolbar.setHelpLink('#{escape_javascript url}'); " \
+ "wikiToolbar.setPreviewUrl('#{escape_javascript preview_url}'); " \
+ "wikiToolbar.draw();"
+ )
+ end
+
+ # removes the 'underline' icon from the markdown toolbar since there
+ # is no such thing in CommonMark
+ def heads_for_wiki_formatter
+ unless @common_mark_heads_for_wiki_formatter_included
+ super
+ content_for :header_tags do
+ javascript_tag(%[delete jsToolBar.prototype.elements.ins;])
+ end
+ @common_mark_heads_for_wiki_formatter_included = true
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/html_parser.rb b/lib/redmine/wiki_formatting/common_mark/html_parser.rb
new file mode 100644
index 000000000..707829fb6
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/html_parser.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ HtmlParser = Redmine::WikiFormatting::Markdown::HtmlParser
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/markdown_filter.rb b/lib/redmine/wiki_formatting/common_mark/markdown_filter.rb
new file mode 100644
index 000000000..b93b35b68
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/markdown_filter.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # Converts Markdown to HTML using CommonMarker
+ #
+ # We do not use the stock HTML::Pipeline::MarkdownFilter because this
+ # does not allow for straightforward configuration of render and parsing
+ # options
+ class MarkdownFilter < HTML::Pipeline::TextFilter
+ def initialize(text, context = nil, result = nil)
+ super text, context, result
+ @text = @text.delete "\r"
+ end
+
+ def call
+ doc = CommonMarker.render_doc(@text, parse_options, extensions)
+ html = doc.to_html render_options, extensions
+ html.rstrip!
+ html
+ end
+
+ private
+
+ def extensions
+ context.fetch :commonmarker_extensions, []
+ end
+
+ def parse_options
+ context.fetch :commonmarker_parse_options, :DEFAULT
+ end
+
+ def render_options
+ context.fetch :commonmarker_render_options, :DEFAULT
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
new file mode 100644
index 000000000..a76201dfd
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # sanitizes rendered HTML using the Sanitize gem
+ class SanitizationFilter < HTML::Pipeline::SanitizationFilter
+ def whitelist
+ @@whitelist ||= customize_whitelist(super.deep_dup)
+ end
+
+ private
+
+ # customizes the whitelist defined in
+ # https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/sanitization_filter.rb
+ def customize_whitelist(whitelist)
+ # Disallow `name` attribute globally, allow on `a`
+ whitelist[:attributes][:all].delete("name")
+ whitelist[:attributes]["a"].push("name")
+
+ # allow class on code tags (this holds the language info from fenced
+ # code bocks and has the format language-foo)
+ whitelist[:attributes]["code"] = %w(class)
+ whitelist[:transformers].push lambda{|env|
+ node = env[:node]
+ return unless node.name == "code"
+ return unless node.has_attribute?("class")
+
+ unless /\Alanguage-(\w+)\z/.match?(node["class"])
+ node.remove_attribute("class")
+ end
+ }
+
+ # Allow table cell alignment by style attribute
+ #
+ # Only necessary if we used the TABLE_PREFER_STYLE_ATTRIBUTES
+ # commonmarker option (which we do not, currently).
+ # By default, the align attribute is used (which is allowed on all
+ # elements).
+ # whitelist[:attributes]["th"] = %w(style)
+ # whitelist[:attributes]["td"] = %w(style)
+ # whitelist[:css] = { properties: ["text-align"] }
+
+ # Allow `id` in a and li elements for footnotes
+ # and remove any `id` properties not matching for footnotes
+ whitelist[:attributes]["a"].push "id"
+ whitelist[:attributes]["li"] = %w(id)
+ whitelist[:transformers].push lambda{|env|
+ node = env[:node]
+ return unless node.name == "a" || node.name == "li"
+ return unless node.has_attribute?("id")
+ return if node.name == "a" && node["id"] =~ /\Afnref\d+\z/
+ return if node.name == "li" && node["id"] =~ /\Afn\d+\z/
+
+ node.remove_attribute("id")
+ }
+
+ # allow the same set of URL schemes for links as is the default in
+ # Redmine::Helpers::URL#uri_with_safe_scheme?
+ whitelist[:protocols]["a"]["href"] = [
+ 'http', 'https', 'ftp', 'mailto', :relative
+ ]
+
+ whitelist
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter.rb b/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter.rb
new file mode 100644
index 000000000..a027e6a17
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # Redmine Syntax highlighting for
+ # blocks as generated by commonmarker
+ class SyntaxHighlightFilter < HTML::Pipeline::Filter
+ def call
+ doc.search("pre > code").each do |node|
+ next unless lang = node["class"].presence
+ next unless lang =~ /\Alanguage-(\w+)\z/
+
+ lang = $1
+ text = node.inner_text
+
+ if Redmine::SyntaxHighlighting.language_supported?(lang)
+ html = Redmine::SyntaxHighlighting.highlight_by_language(text, lang)
+ next if html.nil?
+
+ node.inner_html = html
+ node["class"] = "#{lang} syntaxhl"
+ else
+ # unsupported language, strip out the code tag
+ node.parent.inner_html = text
+ end
+ end
+ doc
+ end
+ end
+ end
+ end
+end
diff --git a/public/help/en/wiki_syntax_common_mark.html b/public/help/en/wiki_syntax_common_mark.html
new file mode 100644
index 000000000..bda25b13b
--- /dev/null
+++ b/public/help/en/wiki_syntax_common_mark.html
@@ -0,0 +1,87 @@
+
+
+
+Wiki formatting
+
+
+
+
+
Wiki Syntax Quick Reference (CommonMark Markdown (GitHub Flavored))
For things such as headlines, bold, tables, lists, Redmine supports Markdown syntax according to CommonMark including some extensions commonly referred to as GitHub flavored Markdown. See the GitHub Flavored Markdown Spec for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.
![](image_url) displays an image located at image_url (markdown syntax)
+
If you have an image attached to your wiki page, it can be displayed inline using its filename: ![](attached_image)
+
Images in your computer's clipboard can be pasted directly using Ctrl-v or Command-v.
+
Image files can be dragged onto the text area in order to be uploaded and embedded.
+
+
+
Headings
+
+
+# Heading
+## Subheading
+### Subsubheading
+
+
+
Redmine assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.
+
+
+
Blockquotes
+
+
Start the paragraph with >
+
+
+> Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
+To go live, all you need to add is a database and a web server.
+
+
+
Display:
+
+
+
Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern. To go live, all you need to add is a database and a web server.
+
+
+
+
Table of content
+
+
+{{toc}} => left aligned toc
+{{>toc}} => right aligned toc
+
+
+
Horizontal Rule
+
+
+---
+
+
+
Macros
+
+
Redmine has the following builtin macros:
+
+
+
+
hello_world
+
Sample macro.
+
+
macro_list
+
Displays a list of all available macros, including description if available.
+
+
child_pages
+
Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:
+
{{child_pages}} -- can be used from a wiki page only
+{{child_pages(depth=2)}} -- display 2 levels nesting only
+
+
include
+
Include a wiki page. Example:
+
{{include(Foo)}}
+
or to include a page of a specific project wiki:
+
{{include(projectname:Foo)}}
+
+
collapse
+
Inserts of collapsed block of text. Example:
+
{{collapse(View details...)
+This is a block of text that is collapsed by default.
+It can be expanded by clicking a link.
+}}
+
+
thumbnail
+
Displays a clickable thumbnail of an attached image. Examples:
Default code highlighting relies on Rouge, a syntax highlighting library written in pure Ruby. It supports many commonly used languages such as c, cpp (c++), csharp (c#, cs), css, diff (patch, udiff), go (golang), groovy, html, java, javascript (js), kotlin, objective_c (objc), perl (pl), php, python (py), r, ruby (rb), sass, scala, shell (bash, zsh, ksh, sh), sql, swift, xml and yaml (yml) languages, where the names inside parentheses are aliases. Please refer to https://www.redmine.org/projects/redmine/wiki/RedmineCodeHighlightingLanguages for the full list of supported languages.
+
+
You can highlight code at any place that supports wiki formatting using this syntax (note that the language name or alias is case-insensitive):
+
+
+```ruby
+ Place your code here.
+```
+
+
+
Example:
+
+
# The Greeter class
+classGreeter
+ definitialize(name)
+ @name=name.capitalize
+ end
+
+ defsalute
+ puts"Hello #{@name}!"
+ end
+end
+
+
+
Raw HTML
+
+
You may use raw HTML for more complex formatting tasks, i.e. complex tables with cells spanning multiple rows or columns:
+
+
+
+
diff --git a/public/help/wiki_syntax_detailed.css b/public/help/wiki_syntax_detailed.css
index ab37aff7b..4e99410fe 100644
--- a/public/help/wiki_syntax_detailed.css
+++ b/public/help/wiki_syntax_detailed.css
@@ -15,6 +15,9 @@ a, a:link, a:visited{ color: #169; text-decoration: none; }
a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
a.new { color: #b73535; }
+table.sample { border-collapse: collapse; border-spacing: 0; margin: 4px; margin-left: 30px;}
+table.sample th, table.sample td { border: solid 1px #bbb; padding: 4px; height: 1em; }
+
.syntaxhl .c1 { color: #888888 }
.syntaxhl .k { color: #008800; font-weight: bold }
.syntaxhl .nc { color: #BB0066; font-weight: bold }
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb
new file mode 100644
index 000000000..fecafd660
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+class Redmine::WikiFormatting::CommonMark::ApplicationHelperTest < Redmine::HelperTest
+ if Object.const_defined?(:CommonMarker)
+
+ include ERB::Util
+ include Rails.application.routes.url_helpers
+
+ fixtures :projects, :enabled_modules,
+ :users, :email_addresses,
+ :members, :member_roles, :roles,
+ :repositories, :changesets,
+ :projects_trackers,
+ :trackers, :issue_statuses, :issues, :versions, :documents, :journals,
+ :wikis, :wiki_pages, :wiki_contents,
+ :boards, :messages, :news,
+ :attachments, :enumerations,
+ :custom_values, :custom_fields, :custom_fields_projects
+
+ def setup
+ super
+ set_tmp_attachments_directory
+ end
+
+ def test_attached_images_with_markdown_and_non_ascii_filename
+ to_test = {
+ 'CAFÃ.JPG' => 'CAF%C3%89.JPG',
+ 'crème.jpg' => 'cr%C3%A8me.jpg',
+ }
+ with_settings :text_formatting => 'common_mark' do
+ to_test.each do |filename, result|
+ attachment = Attachment.generate!(:filename => filename)
+ assert_include %(), textilizable("![](#{filename})", :attachments => [attachment])
+ end
+ end
+ end
+
+ def test_toc_with_markdown_formatting_should_be_parsed
+ with_settings :text_formatting => 'common_mark' do
+ assert_select_in textilizable("{{toc}}\n\n# Heading"), 'ul.toc li', :text => 'Heading'
+ assert_select_in textilizable("{{ 'Heading'
+ assert_select_in textilizable("{{>toc}}\n\n# Heading"), 'ul.toc.right li', :text => 'Heading'
+ end
+ end
+
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb
new file mode 100644
index 000000000..d4e8fa0df
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/external_links_filter'
+
+ class Redmine::WikiFormatting::CommonMark::ExternalLinksFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::ExternalLinksFilter.to_html(html, @options)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_external_links_should_have_external_css_class
+ assert_equal %(link), filter(%(link))
+ end
+
+ def test_locals_links_should_not_have_external_css_class
+ assert_equal %(home), filter(%(home))
+ assert_equal %(relative), filter(%(relative))
+ assert_equal %(anchor), filter(%(anchor))
+ end
+
+ def test_mailto_links_should_have_email_class
+ assert_equal %(user), filter(%(user))
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb
new file mode 100644
index 000000000..92b324151
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/fixup_auto_links_filter'
+
+ class Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilter.to_html(html, @options)
+ end
+
+ def format(markdown)
+ Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown, Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_should_fixup_autolinked_user_references
+ text = "user:user@example.org"
+ assert_equal "
#{text}
", filter(format(text))
+ text = "@user@example.org"
+ assert_equal "
#{text}
", filter(format(text))
+ end
+
+ def test_should_fixup_autolinked_hires_files
+ text = "printscreen@2x.png"
+ assert_equal "
#{text}
", filter(format(text))
+ end
+ end
+end
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
new file mode 100644
index 000000000..9f23dba30
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
@@ -0,0 +1,270 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
+ if Object.const_defined?(:CommonMarker)
+
+ def setup
+ @formatter = Redmine::WikiFormatting::CommonMark::Formatter
+ end
+
+ def format(text)
+ @formatter.new(text).to_html
+ end
+
+ def test_should_render_hard_breaks
+ html ="
", format("foo_bar_baz")
+ end
+
+ def test_wiki_links_should_be_preserved
+ text = 'This is a wiki link: [[Foo]]'
+ assert_include '[[Foo]]', format(text)
+ end
+
+ def test_redmine_links_with_double_quotes_should_be_preserved
+ text = 'This is a redmine link: version:"1.0"'
+ assert_include 'version:"1.0"', format(text)
+ end
+
+ def test_links_by_id_should_be_preserved
+ text = "[project#3]"
+ assert_equal "
#{text}
", format(text)
+ end
+
+ def test_links_to_users_should_be_preserved
+ text = "[@login]"
+ assert_equal "
#{text}
", format(text)
+ text = "[user:login]"
+ assert_equal "
#{text}
", format(text)
+ text = "user:user@example.org"
+ assert_equal "
#{text}
", format(text)
+ text = "[user:user@example.org]"
+ assert_equal "
#{text}
", format(text)
+ text = "@user@example.org"
+ assert_equal "
#{text}
", format(text)
+ text = "[@user@example.org]"
+ assert_equal "
#{text}
", format(text)
+ end
+
+ def test_files_with_at_should_not_end_up_as_mailto_links
+ text = "printscreen@2x.png"
+ assert_equal "
#{text}
", format(text)
+ text = "[printscreen@2x.png]"
+ assert_equal "
#{text}
", format(text)
+ end
+
+ def test_should_support_syntax_highlight
+ text = <<-STR
+ ~~~ruby
+ def foo
+ end
+ ~~~
+ STR
+ assert_select_in format(text), 'pre code.ruby.syntaxhl' do
+ assert_select 'span.k', :text => 'def'
+ end
+ end
+
+ def test_should_not_allow_invalid_language_for_code_blocks
+ text = <<-STR
+ ~~~foo
+ test
+ ~~~
+ STR
+ assert_equal "
test\n
", format(text)
+ end
+
+ def test_external_links_should_have_external_css_class
+ text = 'This is a [link](http://example.net/)'
+ assert_equal '
', format(text)
+ end
+
+ def test_markdown_should_not_require_surrounded_empty_line
+ text = <<-STR
+ This is a list:
+ * One
+ * Two
+ STR
+ assert_equal "
This is a list:
\n
\n
One
\n
Two
\n
", format(text)
+ end
+
+ def test_footnotes
+ text = <<-STR
+ This is some text[^1].
+
+ [^1]: This is the foot note
+ STR
+
+ expected = <<-EXPECTED
+
'],
+ ].each do |text, html|
+ assert_equal html, format(text)
+ end
+ end
+
+ def test_should_escape_unwanted_tags
+ [
+ [
+ %[
sit amet <style>.foo { color: #fff; }</style> <script>alert("hello world");</script>
],
+ %[sit amet ]
+ ]
+ ].each do |expected, input|
+ assert_equal expected, format(input)
+ end
+ end
+
+ private
+
+ def assert_section_with_hash(expected, text, index)
+ result = @formatter.new(text).get_section(index)
+
+ assert_kind_of Array, result
+ assert_equal 2, result.size
+ assert_equal expected, result.first, "section content did not match"
+ assert_equal Digest::MD5.hexdigest(expected), result.last, "section hash did not match"
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb
new file mode 100644
index 000000000..195c3e11e
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/markdown_filter'
+
+ class Redmine::WikiFormatting::CommonMark::MarkdownFilterTest < ActiveSupport::TestCase
+ def filter(markdown)
+ Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown)
+ end
+
+ # just a basic sanity test. more formatting tests in the formatter_test
+ def test_should_render_markdown
+ assert_equal "
bold
", filter("**bold**")
+ end
+ end
+end
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
new file mode 100644
index 000000000..72ef52a63
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
@@ -0,0 +1,211 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/sanitization_filter'
+
+ class Redmine::WikiFormatting::CommonMark::SanitizationFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::SanitizationFilter.to_html(html, @options)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_should_filter_tags
+ input = %( )
+ assert_equal %(foo dont blink), filter(input)
+ end
+
+ def test_should_sanitize_attributes
+ input = %(link)
+ assert_equal %(link), filter(input)
+ end
+
+ def test_should_allow_relative_links
+ input = %(foo/bar)
+ assert_equal input, filter(input)
+ end
+
+ def test_should_support_footnotes
+ input = %(foo)
+ assert_equal input, filter(input)
+ input = %(