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