mirror of https://github.com/rails/rails
Introduce class_names helper
As a follow-up to https://github.com/rails/rails/pull/37872, this change introduces a class_names view helper to make it easier to conditionally apply class names in views. Before: <div class="<%= item.for_sale? ? 'active' : '' %>"> After: <div class="<%= class_names(active: item.for_sale?) %>"> We've been using this helper in the GitHub monolith since 2016. Co-authored-by: Aaron Patterson <tenderlove@github.com>
This commit is contained in:
parent
32b363b246
commit
f24734a7e1
|
@ -94,7 +94,7 @@ module ActionView
|
|||
def tag_option(key, value, escape)
|
||||
case value
|
||||
when Array, Hash
|
||||
value = build_tag_values(value) if key.to_s == "class"
|
||||
value = TagHelper.build_tag_values(value) if key.to_s == "class"
|
||||
value = escape ? safe_join(value, " ") : value.join(" ")
|
||||
else
|
||||
value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
|
||||
|
@ -104,25 +104,6 @@ module ActionView
|
|||
end
|
||||
|
||||
private
|
||||
def build_tag_values(*args)
|
||||
tag_values = []
|
||||
|
||||
args.each do |tag_value|
|
||||
case tag_value
|
||||
when Hash
|
||||
tag_value.each do |key, val|
|
||||
tag_values << key if val
|
||||
end
|
||||
when Array
|
||||
tag_values << build_tag_values(*tag_value).presence
|
||||
else
|
||||
tag_values << tag_value.to_s if tag_value.present?
|
||||
end
|
||||
end
|
||||
|
||||
tag_values.compact.flatten
|
||||
end
|
||||
|
||||
def prefix_tag_option(prefix, key, value, escape)
|
||||
key = "#{prefix}-#{key.to_s.dasherize}"
|
||||
unless value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(BigDecimal)
|
||||
|
@ -309,6 +290,19 @@ module ActionView
|
|||
end
|
||||
end
|
||||
|
||||
# Returns a string of class names built from +args+.
|
||||
#
|
||||
# ==== Examples
|
||||
# class_names("foo", "bar")
|
||||
# # => "foo bar"
|
||||
# class_names({ foo: true, bar: false })
|
||||
# # => "foo"
|
||||
# class_names(nil, false, 123, "", "foo", { bar: true })
|
||||
# # => "foo bar"
|
||||
def class_names(*args)
|
||||
safe_join(build_tag_values(*args), " ")
|
||||
end
|
||||
|
||||
# Returns a CDATA section with the given +content+. CDATA sections
|
||||
# are used to escape blocks of text containing characters which would
|
||||
# otherwise be recognized as markup. CDATA sections begin with the string
|
||||
|
@ -339,6 +333,26 @@ module ActionView
|
|||
end
|
||||
|
||||
private
|
||||
def build_tag_values(*args)
|
||||
tag_values = []
|
||||
|
||||
args.each do |tag_value|
|
||||
case tag_value
|
||||
when Hash
|
||||
tag_value.each do |key, val|
|
||||
tag_values << key if val
|
||||
end
|
||||
when Array
|
||||
tag_values << build_tag_values(*tag_value).presence
|
||||
else
|
||||
tag_values << tag_value.to_s if tag_value.present?
|
||||
end
|
||||
end
|
||||
|
||||
tag_values.compact.flatten
|
||||
end
|
||||
module_function :build_tag_values
|
||||
|
||||
def tag_builder
|
||||
@tag_builder ||= TagBuilder.new(self)
|
||||
end
|
||||
|
|
|
@ -338,6 +338,17 @@ class TagHelperTest < ActionView::TestCase
|
|||
assert_equal "<p class=\"song play>\">limelight</p>", str
|
||||
end
|
||||
|
||||
def test_class_names
|
||||
assert_equal "song play", class_names(["song", { "play": true }])
|
||||
assert_equal "song", class_names({ "song": true, "play": false })
|
||||
assert_equal "song", class_names([{ "song": true }, { "play": false }])
|
||||
assert_equal "song", class_names({ song: true, play: false })
|
||||
assert_equal "song", class_names([{ song: true }, nil, false])
|
||||
assert_equal "song", class_names(["song", { foo: false }])
|
||||
assert_equal "song play", class_names({ "song": true, "play": true })
|
||||
assert_equal "", class_names({ "song": false, "play": false })
|
||||
end
|
||||
|
||||
def test_content_tag_with_data_attributes
|
||||
assert_dom_equal '<p data-number="1" data-string="hello" data-string-with-quotes="double"quote"party"">limelight</p>',
|
||||
content_tag("p", "limelight", data: { number: 1, string: "hello", string_with_quotes: 'double"quote"party"' })
|
||||
|
|
Loading…
Reference in New Issue