diff --git a/app/helpers/html_helper.rb b/app/helpers/html_helper.rb index 3f0100ac5..218d58e78 100644 --- a/app/helpers/html_helper.rb +++ b/app/helpers/html_helper.rb @@ -1,6 +1,9 @@ module HtmlHelper include ERB::Util + EXCLUDE_PUNCTUATION = %(.?,:!;"'<>) + EXCLUDE_PUNCTUATION_REGEX = /[#{Regexp.escape(EXCLUDE_PUNCTUATION)}]+\z/ + def format_html(html) fragment = Nokogiri::HTML5.fragment(html) @@ -44,8 +47,10 @@ module HtmlHelper end def extract_url_and_punctuation(url_match) - if url_match.end_with?(".", "?", ",", ":") - [ url_match[..-2], url_match[-1] ] + url_match = CGI.unescapeHTML(url_match) + if match = url_match.match(EXCLUDE_PUNCTUATION_REGEX) + len = match[0].length + [ url_match[..-(len+1)], url_match[-len..] ] else [ url_match, "" ] end diff --git a/test/helpers/html_helper_test.rb b/test/helpers/html_helper_test.rb index e056a4be8..4011cbf70 100644 --- a/test/helpers/html_helper_test.rb +++ b/test/helpers/html_helper_test.rb @@ -10,25 +10,65 @@ class HtmlHelperTest < ActionView::TestCase format_html("
Check this: https://example.com/
") end - test "don't' include punctuation in URL autolinking" do + test "don't include punctuation in URL autolinking" do assert_equal_html \ - %(Check this: https://example.com!
), - format_html("Check this: https://example.com!
") + %(Check this: https://example.com/!
), + format_html("Check this: https://example.com/!
") assert_equal_html \ - %(Check this: https://example.com.
), - format_html("Check this: https://example.com.
") + %(Check this: https://example.com/.
), + format_html("Check this: https://example.com/.
") assert_equal_html \ - %(Check this: https://example.com?
), - format_html("Check this: https://example.com?
") + %(Check this: https://example.com/?
), + format_html("Check this: https://example.com/?
") assert_equal_html \ - %(Check this: https://example.com,
), - format_html("Check this: https://example.com,
") + %(Check this: https://example.com/,
), + format_html("Check this: https://example.com/,
") assert_equal_html \ - %(Check this: https://example.com:
), - format_html("Check this: https://example.com:
") + %(Check this: https://example.com/:
), + format_html("Check this: https://example.com/:
") assert_equal_html \ - %(Check this: https://example.com;
), - format_html("Check this: https://example.com;
") + %(Check this: https://example.com/;
), + format_html("Check this: https://example.com/;
") + assert_equal_html \ + %(Check this: https://example.com/"
), + format_html("Check this: https://example.com/\"
") + assert_equal_html \ + %(Check this: https://example.com/'
), + format_html("Check this: https://example.com/'
") + + # trailing entities that decode to punctuation + # use assert_equal and not assert_equal_html to make sure we're getting entities correct + assert_equal \ + %(Check this: https://example.com/<
), + format_html("Check this: https://example.com/<
") + assert_equal \ + %(Check this: https://example.com/>
), + format_html("Check this: https://example.com/>
") + assert_equal \ + %(Check this: https://example.com/"
), + format_html("Check this: https://example.com/"
") + + # multiple punctuation characters including entities + assert_equal_html \ + %(Check this: https://example.com/!?;
), + format_html("Check this: https://example.com/!?;
") + assert_equal_html \ + %(<img src="https://example.com/">), + format_html(%(<img src="https://example.com/">)) + assert_equal_html \ + %(<img src="https://example.com/"!>), + format_html(%(<img src="https://example.com/"!>)) + end + + test "handle URLs with query parameters" do + # use assert_equal and not assert_equal_html to make sure we're getting entities correct + assert_equal \ + %(Check this: https://example.com/a?b=c&d=e
), + format_html("Check this: https://example.com/a?b=c&d=e
") + + assert_equal \ + %(Check this: https://example.com/a?b=c&d=e
), + format_html("Check this: https://example.com/a?b=c&d=e
") end test "respect existing links" do