]> source.dussan.org Git - redmine.git/commitdiff
Unify code block and add "data-language" attribute with the user-supplied language...
authorMarius Balteanu <marius.balteanu@zitec.com>
Sun, 15 Aug 2021 21:00:16 +0000 (21:00 +0000)
committerMarius Balteanu <marius.balteanu@zitec.com>
Sun, 15 Aug 2021 21:00:16 +0000 (21:00 +0000)
Patch by Martin Cizek.

git-svn-id: http://svn.redmine.org/redmine/trunk@21183 e93f8b46-1217-0410-a6f0-8f06a7374b81

lib/redmine/wiki_formatting/markdown/formatter.rb
lib/redmine/wiki_formatting/textile/formatter.rb
test/helpers/application_helper_test.rb
test/unit/lib/redmine/wiki_formatting/markdown_formatter_test.rb
test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb

index 418ab8b14283b6b871095115de7217eaac4c9825..44d65248f9bab468ebc71771932e88ce4f97ccaa 100644 (file)
@@ -38,12 +38,14 @@ module Redmine
 
         def block_code(code, language)
           if language.present? && Redmine::SyntaxHighlighting.language_supported?(language)
-            "<pre><code class=\"#{CGI.escapeHTML language} syntaxhl\">" +
-              Redmine::SyntaxHighlighting.highlight_by_language(code, language) +
-              "</code></pre>"
+            html = Redmine::SyntaxHighlighting.highlight_by_language(code, language)
+            classattr = " class=\"#{CGI.escapeHTML language} syntaxhl\""
           else
-            "<pre>" + CGI.escapeHTML(code) + "</pre>"
+            html = CGI.escapeHTML(code)
           end
+          # original language for extension development
+          langattr = " data-language=\"#{CGI.escapeHTML language}\"" if language.present?
+          "<pre><code#{classattr}#{langattr}>#{html}</code></pre>"
         end
 
         def image(link, title, alt_text)
index 8f0200b33dbd97b3a9ebae397af1834ef9494ad1..d425306514a2381555a5cc30a6cc992eccd160e0 100644 (file)
@@ -128,12 +128,14 @@ module Redmine
               if content.match(/<code\s+class=(?:"([^"]+)"|'([^']+)')>\s?(.*)/m)
                 language = $1 || $2
                 text = $3
+                # original language for extension development
+                langattr = " data-language=\"#{CGI.escapeHTML language}\"" if language.present?
                 if Redmine::SyntaxHighlighting.language_supported?(language)
                   text.gsub!(/x%x%/, '&')
-                  content = "<code class=\"#{language} syntaxhl\">" +
+                  content = "<code class=\"#{CGI.escapeHTML language} syntaxhl\"#{langattr}>" +
                     Redmine::SyntaxHighlighting.highlight_by_language(text, language)
                 else
-                  content = "<code>#{ERB::Util.h(text)}"
+                  content = "<code#{langattr}>#{ERB::Util.h(text)}"
                 end
               end
               content
index f918f51d144c2361ce475c246e7d92b7016976dc..06dd04b6a3cf4269d7c5cf95ef34d15d4dae9844 100644 (file)
@@ -1328,7 +1328,7 @@ class ApplicationHelperTest < Redmine::HelperTest
       </code></pre>
     RAW
     expected = <<~EXPECTED
-      <pre><code class="ECMA_script syntaxhl"><span class="cm">/* Hello */</span><span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hello World!</span><span class="dl">"</span><span class="p">);</span></code></pre>
+      <pre><code class="ECMA_script syntaxhl" data-language=\"ECMA_script\"><span class="cm">/* Hello */</span><span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hello World!</span><span class="dl">"</span><span class="p">);</span></code></pre>
     EXPECTED
     assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
   end
@@ -1340,7 +1340,7 @@ class ApplicationHelperTest < Redmine::HelperTest
       </code></pre>
     RAW
     expected = <<~EXPECTED
-      <pre><code class=\"ruby syntaxhl\"><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">&amp;</span> <span class=\"n\">b</span></code></pre>
+      <pre><code class=\"ruby syntaxhl\" data-language=\"ruby\"><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">a</span> <span class=\"o\">&amp;</span> <span class=\"n\">b</span></code></pre>
     EXPECTED
     with_settings :text_formatting => 'textile' do
       assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
index c1264f77b7a5ebd3c8817a6dee3ad8765187a647..5be1521a515e25a50179b3953d1bc741744e2272 100644 (file)
@@ -70,6 +70,7 @@ class Redmine::WikiFormatting::MarkdownFormatterTest < ActionView::TestCase
     STR
     assert_select_in @formatter.new(text).to_html, 'pre code.ruby.syntaxhl' do
       assert_select 'span.k', :text => 'def'
+      assert_select "[data-language='ruby']"
     end
   end
 
@@ -79,7 +80,16 @@ class Redmine::WikiFormatting::MarkdownFormatterTest < ActionView::TestCase
       test
       ~~~
     STR
-    assert_equal "<pre>test\n</pre>", @formatter.new(text).to_html
+    assert_equal "<pre><code data-language=\"foo\">test\n</code></pre>", @formatter.new(text).to_html
+  end
+
+  def test_should_preserve_code_block_language_in_data_language
+    text = <<~STR
+      ~~~c-k&r
+      test
+      ~~~
+    STR
+    assert_equal "<pre><code data-language=\"c-k&amp;r\">test\n</code></pre>", @formatter.new(text).to_html
   end
 
   def test_external_links_should_have_external_css_class
index 5ee4defe16168e6c3eda74c48fb2c6afd1d2a9c0..3a8e0ad0f76ce7427020b28367e1e8e5958182c4 100644 (file)
@@ -596,12 +596,16 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase
   end
 
   def test_should_not_allow_arbitrary_class_attribute_on_offtags
-    %w(code pre kbd).each do |tag|
-      assert_html_output({"<#{tag} class=\"foo\">test</#{tag}>" => "<#{tag}>test</#{tag}>"}, false)
-      assert_html_output({"<#{tag} class='foo'>test</#{tag}>" => "<#{tag}>test</#{tag}>"}, false)
-      assert_html_output({"<#{tag} class=\"ruby foo\">test</#{tag}>" => "<#{tag}>test</#{tag}>"}, false)
-      assert_html_output({"<#{tag} class='ruby foo'>test</#{tag}>" => "<#{tag}>test</#{tag}>"}, false)
-      assert_html_output({"<#{tag} class=\"ruby \"foo\" bar\">test</#{tag}>" => "<#{tag}>test</#{tag}>"}, false)
+    {
+      "class=\"foo\"" => "data-language=\"foo\"",
+      "class='foo'" => "data-language=\"foo\"",
+      "class=\"ruby foo\"" => "data-language=\"ruby foo\"",
+      "class='ruby foo'" => "data-language=\"ruby foo\"",
+      "class=\"ruby \"foo\" bar\"" => "data-language=\"ruby \"",
+    }.each do |classattr, codeattr|
+      assert_html_output({"<code #{classattr}>test</code>" => "<code #{codeattr}>test</code>"}, false)
+      assert_html_output({"<pre #{classattr}>test</pre>" => "<pre>test</pre>"}, false)
+      assert_html_output({"<kbd #{classattr}>test</kbd>" => "<kbd>test</kbd>"}, false)
     end
 
     assert_html_output({"<notextile class=\"foo\">test</notextile>" => "test"}, false)
@@ -615,13 +619,25 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase
     # language name is double-quoted
     assert_html_output(
       {"<code class=\"ruby\">test</code>" =>
-         "<code class=\"ruby syntaxhl\"><span class=\"nb\">test</span></code>"},
+         "<code class=\"ruby syntaxhl\" data-language=\"ruby\"><span class=\"nb\">test</span></code>"},
       false
     )
     # language name is single-quoted
     assert_html_output(
       {"<code class='ruby'>test</code>" =>
-         "<code class=\"ruby syntaxhl\"><span class=\"nb\">test</span></code>"},
+         "<code class=\"ruby syntaxhl\" data-language=\"ruby\"><span class=\"nb\">test</span></code>"},
+      false
+    )
+  end
+
+  def test_should_preserve_code_language_class_attribute_in_data_language
+    assert_html_output(
+      {
+        "<code class=\"foolang\">unsupported language</code>" =>
+          "<code data-language=\"foolang\">unsupported language</code>",
+        "<code class=\"c-k&r\">special-char language</code>" =>
+          "<code data-language=\"c-k&#38;r\">special-char language</code>",
+      },
       false
     )
   end