diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index d13cc0c7a7426a631948ec3c4a2f70e6e30fd1c8..d825d3b627164d2456854b3c5de54eb8931ddba6 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,13 @@ +* Flatten the array parameter in `safe_join`, so it behaves consistently with + `Array#join`. + + *Paul Grayson* + +* Honor `html_safe` on array elements in tag values, as we do for plain string + values. + + *Paul Grayson* + * Add `ActionView::Template::Handler.unregister_template_handler`. It performs the opposite of `ActionView::Template::Handler.register_template_handler`. diff --git a/actionview/lib/action_view/helpers/output_safety_helper.rb b/actionview/lib/action_view/helpers/output_safety_helper.rb index e1f40011c0d60ef2fbffdbaed53fefd518a75911..b0d9c7c7f9fb21303a8ccad51ea01ed5ce648ca5 100644 --- a/actionview/lib/action_view/helpers/output_safety_helper.rb +++ b/actionview/lib/action_view/helpers/output_safety_helper.rb @@ -18,9 +18,9 @@ def raw(stringish) end # This method returns a html safe string similar to what Array#join - # would return. All items in the array, including the supplied separator, are - # html escaped unless they are html safe, and the returned string is marked - # as html safe. + # would return. The array is flattened, and all items, including + # the supplied separator, are html escaped unless they are html + # safe, and the returned string is marked as html safe. # # safe_join(["

foo

".html_safe, "

bar

"], "
") # # => "

foo

<br /><p>bar</p>" @@ -31,7 +31,7 @@ def raw(stringish) def safe_join(array, sep=$,) sep = ERB::Util.unwrapped_html_escape(sep) - array.map { |i| ERB::Util.unwrapped_html_escape(i) }.join(sep).html_safe + array.flatten.map! { |i| ERB::Util.unwrapped_html_escape(i) }.join(sep).html_safe end end end diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb index 9b9ca7d60dc79f87c903da5b2e6d6ff0dd7dc1fc..35444bcfb422ee130917078d3133eeab0f1f72a5 100644 --- a/actionview/lib/action_view/helpers/tag_helper.rb +++ b/actionview/lib/action_view/helpers/tag_helper.rb @@ -173,8 +173,11 @@ def boolean_tag_option(key) end def tag_option(key, value, escape) - value = value.join(" ") if value.is_a?(Array) - value = ERB::Util.unwrapped_html_escape(value) if escape + if value.is_a?(Array) + value = escape ? safe_join(value, " ") : value.join(" ") + else + value = escape ? ERB::Util.unwrapped_html_escape(value) : value + end %(#{key}="#{value}") end end diff --git a/actionview/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb index 76c71c9e6d03aad6fdfd2f7d87996b884e33537f..a1bf0e1a5fa645a8085a6ae262cc6eee7aec1ac8 100644 --- a/actionview/test/template/output_safety_helper_test.rb +++ b/actionview/test/template/output_safety_helper_test.rb @@ -25,4 +25,11 @@ def setup assert_equal "

foo


bar

", joined end -end \ No newline at end of file + test "safe_join should work recursively similarly to Array.join" do + joined = safe_join(['a',['b','c']], ':') + assert_equal 'a:b:c', joined + + joined = safe_join(['"a"',['','']], '
') + assert_equal '"a" <br/> <b> <br/> <c>', joined + end +end diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb index fb016a52de6d958eeefb21197f65e776d66b42f6..c78b6450f222b064745a0a74bc5f644b1e14fab0 100644 --- a/actionview/test/template/tag_helper_test.rb +++ b/actionview/test/template/tag_helper_test.rb @@ -80,11 +80,27 @@ def test_content_tag_with_escaped_array_class str = content_tag('p', "limelight", :class => ["song", "play"]) assert_equal "

limelight

", str + + str = content_tag('p', "limelight", :class => ["song", ["play"]]) + assert_equal "

limelight

", str end def test_content_tag_with_unescaped_array_class str = content_tag('p', "limelight", {:class => ["song", "play>"]}, false) assert_equal "

\">limelight

", str + + str = content_tag('p', "limelight", {:class => ["song", ["play>"]]}, false) + assert_equal "

\">limelight

", str + end + + def test_content_tag_with_empty_array_class + str = content_tag('p', 'limelight', {:class => []}) + assert_equal '

limelight

', str + end + + def test_content_tag_with_unescaped_empty_array_class + str = content_tag('p', 'limelight', {:class => []}, false) + assert_equal '

limelight

', str end def test_content_tag_with_data_attributes @@ -115,6 +131,14 @@ def test_tag_honors_html_safe_for_param_values end end + def test_tag_honors_html_safe_with_escaped_array_class + str = tag('p', :class => ['song>', 'play>'.html_safe]) + assert_equal '

', str + + str = tag('p', :class => ['song>'.html_safe, 'play>']) + assert_equal '

', str + end + def test_skip_invalid_escaped_attributes ['&1;', 'dfa3;', '& #123;'].each do |escaped| assert_equal %(), tag('a', :href => escaped)