Autolinking is more robust
and handles URLs with CGI params, recognizes more (and multiple) trailing punctuation marks including entity-encoded punctuation like `"`.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -10,25 +10,65 @@ class HtmlHelperTest < ActionView::TestCase
|
||||
format_html("<p>Check this: https://example.com/</p>")
|
||||
end
|
||||
|
||||
test "don't' include punctuation in URL autolinking" do
|
||||
test "don't include punctuation in URL autolinking" do
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com" rel="noreferrer">https://example.com</a>!</p>),
|
||||
format_html("<p>Check this: https://example.com!</p>")
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>!</p>),
|
||||
format_html("<p>Check this: https://example.com/!</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com" rel="noreferrer">https://example.com</a>.</p>),
|
||||
format_html("<p>Check this: https://example.com.</p>")
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>.</p>),
|
||||
format_html("<p>Check this: https://example.com/.</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com" rel="noreferrer">https://example.com</a>?</p>),
|
||||
format_html("<p>Check this: https://example.com?</p>")
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>?</p>),
|
||||
format_html("<p>Check this: https://example.com/?</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com" rel="noreferrer">https://example.com</a>,</p>),
|
||||
format_html("<p>Check this: https://example.com,</p>")
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>,</p>),
|
||||
format_html("<p>Check this: https://example.com/,</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com" rel="noreferrer">https://example.com</a>:</p>),
|
||||
format_html("<p>Check this: https://example.com:</p>")
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>:</p>),
|
||||
format_html("<p>Check this: https://example.com/:</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com" rel="noreferrer">https://example.com</a>;</p>),
|
||||
format_html("<p>Check this: https://example.com;</p>")
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>;</p>),
|
||||
format_html("<p>Check this: https://example.com/;</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>"</p>),
|
||||
format_html("<p>Check this: https://example.com/\"</p>")
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>'</p>),
|
||||
format_html("<p>Check this: https://example.com/'</p>")
|
||||
|
||||
# trailing entities that decode to punctuation
|
||||
# use assert_equal and not assert_equal_html to make sure we're getting entities correct
|
||||
assert_equal \
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a><</p>),
|
||||
format_html("<p>Check this: https://example.com/<</p>")
|
||||
assert_equal \
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>></p>),
|
||||
format_html("<p>Check this: https://example.com/></p>")
|
||||
assert_equal \
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>"</p>),
|
||||
format_html("<p>Check this: https://example.com/"</p>")
|
||||
|
||||
# multiple punctuation characters including entities
|
||||
assert_equal_html \
|
||||
%(<p>Check this: <a href="https://example.com/" rel="noreferrer">https://example.com/</a>!?;</p>),
|
||||
format_html("<p>Check this: https://example.com/!?;</p>")
|
||||
assert_equal_html \
|
||||
%(<img src="<a href="https://example.com/" rel="noreferrer">https://example.com/</a>">),
|
||||
format_html(%(<img src="https://example.com/">))
|
||||
assert_equal_html \
|
||||
%(<img src="<a href="https://example.com/" rel="noreferrer">https://example.com/</a>"!>),
|
||||
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 \
|
||||
%(<p>Check this: <a href="https://example.com/a?b=c&d=e" rel="noreferrer">https://example.com/a?b=c&d=e</a></p>),
|
||||
format_html("<p>Check this: https://example.com/a?b=c&d=e</p>")
|
||||
|
||||
assert_equal \
|
||||
%(<p>Check this: <a href="https://example.com/a?b=c&d=e" rel="noreferrer">https://example.com/a?b=c&d=e</a></p>),
|
||||
format_html("<p>Check this: https://example.com/a?b=c&d=e</p>")
|
||||
end
|
||||
|
||||
test "respect existing links" do
|
||||
|
||||
Reference in New Issue
Block a user