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"',['','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)