From acf0f9019ed687e941344e1be57d2e31a0ffa03e Mon Sep 17 00:00:00 2001
From: Marius Balteanu #{result}
',
+ '!http://foo.bar/image.jpg!' => '
',
'floating !>http://foo.bar/image.jpg!' =>
- 'floating
',
+ 'floating
',
'with class !(some-class)http://foo.bar/image.jpg!' =>
- 'with class
',
+ 'with class
',
'with class !(wiki-class-foo)http://foo.bar/image.jpg!' =>
- 'with class
',
+ 'with class
',
'with style !{width:100px;height:100px}http://foo.bar/image.jpg!' =>
- 'with style
',
+ 'with style
',
'with title !http://foo.bar/image.jpg(This is a title)!' =>
- 'with title
',
+ 'with title
',
'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' =>
'with title
',
+ 'alt="This is a double-quoted "title"">',
'with query string !http://foo.bar/image.cgi?a=1&b=2!' =>
- 'with query string '
+ 'with query string
'
}
with_settings :text_formatting => 'textile' do
to_test.each {|text, result| assert_equal "
')
- assert textilizable(raw).include?('
')
+ assert textilizable(raw).include?('
')
+ assert textilizable(raw).include?('
')
end
end
def test_attached_images
to_test = {
'Inline image: !logo.gif!' =>
- 'Inline image:
',
+ 'Inline image:
',
'Inline image: !logo.GIF!' =>
- 'Inline image:
',
+ 'Inline image:
',
'Inline WebP image: !logo.webp!' =>
- 'Inline WebP image:
',
- 'No match: !ogo.gif!' => 'No match:
',
- 'No match: !ogo.GIF!' => 'No match: ',
+ 'Inline WebP image:
',
+ 'No match: !ogo.gif!' => 'No match:
',
+ 'No match: !ogo.GIF!' => 'No match: ',
# link image
'!logo.gif!:http://foo.bar/' =>
- '
',
+ '
',
}
attachments = Attachment.all
with_settings :text_formatting => 'textile' do
@@ -190,31 +190,31 @@ class ApplicationHelperTest < Redmine::HelperTest
attachments = Attachment.all
with_settings text_formatting: 'textile' do
# When alt text is set
- assert_match %r[],
+ assert_match %r[
],
textilizable('!logo.gif(alt text)!', attachments: attachments)
# When alt text and style are set
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!{width:100px}logo.gif(alt text)!', attachments: attachments)
# When alt text is not set
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!logo.gif!', attachments: attachments)
# When alt text is not set and the attachment has no description
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!testfile.PNG!', attachments: attachments)
# When no matching attachments are found
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!no-match.jpg!', attachments: attachments)
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!no-match.jpg(alt text)!', attachments: attachments)
# When no attachment is registered
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!logo.gif!', attachments: [])
- assert_match %r[
],
+ assert_match %r[
],
textilizable('!logo.gif(alt text)!', attachments: [])
end
end
@@ -232,8 +232,8 @@ class ApplicationHelperTest < Redmine::HelperTest
RAW
with_settings :text_formatting => 'textile' do
- assert textilizable(raw, :object => journal).include?("
")
- assert textilizable(raw, :object => journal).include?("
")
+ assert textilizable(raw, :object => journal).include?("
")
+ assert textilizable(raw, :object => journal).include?("
")
end
end
@@ -245,7 +245,7 @@ class ApplicationHelperTest < Redmine::HelperTest
with_settings :text_formatting => 'textile' do
to_test.each do |filename, result|
attachment = Attachment.generate!(:filename => filename)
- assert_include %(),
+ assert_include %(
),
textilizable("!#{filename}!", :attachments => [attachment])
end
end
@@ -272,7 +272,7 @@ class ApplicationHelperTest < Redmine::HelperTest
with_settings :text_formatting => 'textile' do
assert_equal(
%(

',
+ 'Inline image:
',
'Inline image: !testtest.jpe!' =>
- 'Inline image: Another paragraph",
# no multiline link text
"This is a double quote \"on the first line\nand another on a second line\":test" =>
- "This is a double quote \"on the first line
and another on a second line\":test",
+ "This is a double quote \"on the first line
and another on a second line\":test",
# mailto link
"\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" =>
"system administrator",
@@ -391,7 +391,7 @@ class ApplicationHelperTest < Redmine::HelperTest
'(see "inline link":http://www.foo.bar/Test-)' =>
'(see inline link)',
'http://foo.bar/page?p=1&t=z&s=-' =>
- 'http://foo.bar/page?p=1&t=z&s=-',
+ 'http://foo.bar/page?p=1&t=z&s=-',
'This is an intern "link":/foo/bar-' => 'This is an intern link'
}
with_settings :text_formatting => 'textile' do
@@ -1317,10 +1317,10 @@ class ApplicationHelperTest < Redmine::HelperTest
def test_html_tags
to_test = {
"
<div>content</div>
", - "<div class="bold">content</div>
", + "<div class=\"bold\">content</div>
", "" => "<script>some script;</script>
", # do not escape pre/code tags - "\nline 1\nline2" => "
\nline 1\nline2", + "
\nline 1\nline2" => "
line 1\nline2", "
\nline 1\nline2" => "\nline 1\nline2",
"" => "content
<div class=\"foo\">content</div>", "
" => "content
<div class=\"<foo\">content</div>", @@ -1477,7 +1477,7 @@ class ApplicationHelperTest < Redmine::HelperTest "
Dashes: ---
', textilizable('Dashes: ---') end end diff --git a/test/unit/lib/redmine/wiki_formatting/tablesort_scrubber_test.rb b/test/unit/lib/redmine/wiki_formatting/tablesort_scrubber_test.rb new file mode 100644 index 000000000..8144309c0 --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/tablesort_scrubber_test.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006- Jean-Philippe Lang +# This code is released under the GNU General Public License. + +require_relative '../../../../test_helper' + +class Redmine::WikiFormatting::TablesortScrubberTest < ActiveSupport::TestCase + def filter(html) + fragment = Redmine::WikiFormatting::HtmlParser.parse(html) + scrubber = Redmine::WikiFormatting::TablesortScrubber.new + fragment.scrub!(scrubber) + fragment.to_s + end + + test 'should not add data-controller attribute by default' do + table = <<~HTML +| A | +B | +
|---|---|
| + | + |
| + | + |
| A | +B | +
|---|---|
| + | + |
| A | +B | +
|---|---|
| + | + |
| + | + |
| A | +B | +
|---|---|
| + | + |
| + | + |
John said:
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
- Donec odio lorem,
@@ -282,9 +282,11 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCaseThis is a table with empty cells:
+
EXPECTED assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') @@ -298,9 +300,11 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase RAW expected = <<~EXPECTEDcell11 cell12 cell21 cell23 + cell31 cell32 cell33 +
EXPECTED assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') @@ -318,9 +322,11 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCaseright left + justify This is a table with trailing whitespace in one row:
+
EXPECTED assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') @@ -343,21 +349,23 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCasecell11 cell12 cell21 cell22 + cell31 cell32 This is a table with line breaks:
+
EXPECTED assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') @@ -380,18 +388,20 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase- cell11 +
continuedcell11
continuedcell12 cell21- cell23 +
cell23 line2
cell23 line3cell23
cell23 line2
cell23 line3+ cell31 -cell32 +
cell32 line2cell32
cell32 line2cell33 This is a table with lists:
+
EXPECTED assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') @@ -408,7 +418,7 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase expected = 'cell11 cell12 cell21 -ordered list +
# item
# item 2ordered list
# item
# item 2+ cell31 -unordered list +
* item
* item 2unordered list
* item
* item 2' + ''XSS');"" alt="">' assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') end @@ -635,7 +645,7 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase "
unsupported language" => "unsupported language", "special-char language" => - "special-char language", + "special-char language", }, false ) @@ -652,11 +662,11 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase def test_should_prefix_class_attribute_on_tags assert_html_output( { - '!(foo)test.png!' => "", + '!(foo)test.png!' => "
", '%(foo)test%' => "
test
", 'p(foo). test' => "test
", '|(foo). test|' => - "\n\t\t
", + "\n\t\t\t \n\ttest \n\t\t\n\t\t
", }, false ) @@ -665,11 +675,11 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase def test_should_prefix_id_attribute_on_tags assert_html_output( { - '!(#foo)test.png!' => "\n\t\t\t \n\ttest \n\t\t", + '!(#foo)test.png!' => "
", '%(#foo)test%' => "
test
", 'p(#foo). test' => "test
", '|(#foo). test|' => - "\n\t\t
", + "\n\t\t\t \n\ttest \n\t\t\n\t\t
", }, false ) @@ -679,7 +689,7 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase assert_html_output( { '!(wiki-class-foo#wiki-id-bar)test.png!' => - "\n\t\t\t \n\ttest \n\t\t", + "
", }, false ) @@ -711,8 +721,8 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase STR expected = <<~EXPECTED -
<pree>
- This is some text
+<pree>
EXPECTED assert_equal expected.gsub(%r{[\r\n\t]}, ''), to_html(text).gsub(%r{[\r\n\t]}, '') diff --git a/vendor/javascript/tablesort.min.js b/vendor/javascript/tablesort.min.js new file mode 100644 index 000000000..01a6be3e3 --- /dev/null +++ b/vendor/javascript/tablesort.min.js @@ -0,0 +1,6 @@ +/*! + * tablesort v5.7.0 (2026-01-03) + * http://tristen.ca/tablesort/demo/ + * Copyright (c) 2026 ; Licensed MIT + */ +const m=[],v=function(n){if(!window.CustomEvent||typeof window.CustomEvent!="function"){const t=document.createEvent("CustomEvent");return t.initCustomEvent(n,!1,!1,void 0),t}else return new CustomEvent(n)},A=function(n,t){const e=t.sortAttribute||"data-sort";return n.hasAttribute(e)?n.getAttribute(e):n.textContent||n.innerText||""},C=function(n,t){return n=n.trim().toLowerCase(),t=t.trim().toLowerCase(),n===t?0:n
+ This is some text
</pree>0)if(t.tHead&&t.tHead.rows.length>0){for(let s=0;s {this.current&&this.current!==i.target&&this.current.removeAttribute("aria-sort"),this.current=i.target,this.sortTable(i.target)};let s;for(let i=0;i 0&&f.push(r),c++;if(!f)return}for(let o=0;o