mirror of https://github.com/rails/rails
Serialize aria- namespaced list attributes
Summary === Prior to this commit, calls passing `aria: { labelledby: [...] }` serialized the `aria-labelledby` Array value as JSON. This commit introduces special case logic to serialize `aria-` prefixed `TrueClass`, `FalseClass`, `Hash`, and `Array` values more appropriately. An element's [`aria-labelledby` attribute][aria-labelledby] and [`aria-describedby` attribute][aria-describedby] can accept a space-delimited list of identifier values (much like the [`class` attribute][class] accepts a space delimited [`DOMTokenList` value][DOMTokenList]). Similarly, there are [no boolean `aria-` attributes][aria-attributes] (only `true`, `false`, or undefined), so this commit serializes `true` to `"true"` and `false` to `"false"`. Testing --- This change moves an assertion _outside_ of a loop over `["aria", :aria]`. Prior to this change, the second assertion within the loop wasn't utilizing the iterated value as a Hash key. That is to say: `aria:` (where an `aria` local variable is declared) is not equivalent an equivalent syntax to `aria =>`. Since the migration to `**options` in response to Ruby 2.7 deprecations, invoking `tag.a("aria" => {...})` incorrectly coerces the `"aria" => {...}` has to be the `TagBuilder#a` method `content = nil` ordered argument, instead of its `options` keyword arguments. This commit does not modify that behavior, but it _does_ move the assertion outside the block so that it isn't run unnecessarily. [aria-labelledby]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute [aria-describedby]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute [aria-attributes]: https://www.w3.org/TR/wai-aria-1.1/#propcharacteristic_value [class]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class [DOMTokenList]: https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList [class_names]: https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-class_names
This commit is contained in:
parent
43daedcb7d
commit
8b19d66fc6
|
@ -1,3 +1,20 @@
|
|||
* ARIA Array and Hash attributes are treated as space separated `DOMTokenList`
|
||||
values. This is useful when declaring lists of label text identifiers in
|
||||
`aria-labelledby` or `aria-describedby`.
|
||||
|
||||
tag.input type: 'checkbox', name: 'published', aria: {
|
||||
invalid: @post.errors[:published].any?,
|
||||
labelledby: ['published_context', 'published_label'],
|
||||
describedby: { published_errors: @post.errors[:published].any? }
|
||||
}
|
||||
#=> <input
|
||||
type="checkbox" name="published" aria-invalid="true"
|
||||
aria-labelledby="published_context published_label"
|
||||
aria-describedby="published_errors"
|
||||
>
|
||||
|
||||
*Sean Doyle*
|
||||
|
||||
* Remove deprecated `escape_whitelist` from `ActionView::Template::Handlers::ERB`.
|
||||
|
||||
*Rafael Mendonça França*
|
||||
|
|
|
@ -26,11 +26,13 @@ module ActionView
|
|||
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
|
||||
BOOLEAN_ATTRIBUTES.freeze
|
||||
|
||||
TAG_PREFIXES = ["aria", "data", :aria, :data].to_set.freeze
|
||||
ARIA_PREFIXES = ["aria", :aria].to_set.freeze
|
||||
DATA_PREFIXES = ["data", :data].to_set.freeze
|
||||
|
||||
TAG_TYPES = {}
|
||||
TAG_TYPES.merge! BOOLEAN_ATTRIBUTES.index_with(:boolean)
|
||||
TAG_TYPES.merge! TAG_PREFIXES.index_with(:prefix)
|
||||
TAG_TYPES.merge! DATA_PREFIXES.index_with(:data)
|
||||
TAG_TYPES.merge! ARIA_PREFIXES.index_with(:aria)
|
||||
TAG_TYPES.freeze
|
||||
|
||||
PRE_CONTENT_STRINGS = Hash.new { "" }
|
||||
|
@ -72,9 +74,18 @@ module ActionView
|
|||
sep = " "
|
||||
options.each_pair do |key, value|
|
||||
type = TAG_TYPES[key]
|
||||
if type == :prefix && value.is_a?(Hash)
|
||||
if type == :data && value.is_a?(Hash)
|
||||
value.each_pair do |k, v|
|
||||
next if v.nil?
|
||||
output << sep
|
||||
output << prefix_tag_option(key, k, v, escape)
|
||||
end
|
||||
elsif type == :aria && value.is_a?(Hash)
|
||||
value.each_pair do |k, v|
|
||||
next if v.nil?
|
||||
|
||||
v = (v.is_a?(Array) || v.is_a?(Hash)) ? safe_join(TagHelper.build_tag_values(v), " ") : v.to_s
|
||||
|
||||
output << sep
|
||||
output << prefix_tag_option(key, k, v, escape)
|
||||
end
|
||||
|
@ -165,8 +176,8 @@ module ActionView
|
|||
# tag.input type: 'text', disabled: true
|
||||
# # => <input type="text" disabled="disabled">
|
||||
#
|
||||
# HTML5 <tt>data-*</tt> attributes can be set with a single +data+ key
|
||||
# pointing to a hash of sub-attributes.
|
||||
# HTML5 <tt>data-*</tt> and <tt>aria-*</tt> attributes can be set with a
|
||||
# single +data+ or +aria+ key pointing to a hash of sub-attributes.
|
||||
#
|
||||
# To play nicely with JavaScript conventions, sub-attributes are dasherized.
|
||||
#
|
||||
|
|
|
@ -441,11 +441,12 @@ class TagHelperTest < ActionView::TestCase
|
|||
|
||||
def test_aria_attributes
|
||||
["aria", :aria].each { |aria|
|
||||
assert_dom_equal '<a aria-a-float="3.14" aria-a-big-decimal="-123.456" aria-a-number="1" aria-array="[1,2,3]" aria-hash="{"key":"value"}" aria-string-with-quotes="double"quote"party"" aria-string="hello" aria-symbol="foo" />',
|
||||
tag("a", aria => { a_float: 3.14, a_big_decimal: BigDecimal("-123.456"), a_number: 1, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { key: "value" }, string_with_quotes: 'double"quote"party"' })
|
||||
assert_dom_equal '<a aria-a-float="3.14" aria-a-big-decimal="-123.456" aria-a-number="1" aria-array="[1,2,3]" aria-hash="{"key":"value"}" aria-string-with-quotes="double"quote"party"" aria-string="hello" aria-symbol="foo" />',
|
||||
tag.a(aria: { a_float: 3.14, a_big_decimal: BigDecimal("-123.456"), a_number: 1, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { key: "value" }, string_with_quotes: 'double"quote"party"' })
|
||||
assert_dom_equal '<a aria-a-float="3.14" aria-a-big-decimal="-123.456" aria-a-number="1" aria-truthy="true" aria-falsey="false" aria-array="1 2 3" aria-hash="a b" aria-tokens="a b" aria-string-with-quotes="double"quote"party"" aria-string="hello" aria-symbol="foo" />',
|
||||
tag("a", aria => { nil: nil, a_float: 3.14, a_big_decimal: BigDecimal("-123.456"), a_number: 1, truthy: true, falsey: false, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { a: true, b: "truthy", falsey: false, nil: nil }, tokens: ["a", { b: true, c: false }], string_with_quotes: 'double"quote"party"' })
|
||||
}
|
||||
|
||||
assert_dom_equal '<a aria-a-float="3.14" aria-a-big-decimal="-123.456" aria-a-number="1" aria-truthy="true" aria-falsey="false" aria-array="1 2 3" aria-hash="a b" aria-tokens="a b" aria-string-with-quotes="double"quote"party"" aria-string="hello" aria-symbol="foo" />',
|
||||
tag.a(aria: { nil: nil, a_float: 3.14, a_big_decimal: BigDecimal("-123.456"), a_number: 1, truthy: true, falsey: false, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { a: true, b: "truthy", falsey: false, nil: nil }, tokens: ["a", { b: true, c: false }], string_with_quotes: 'double"quote"party"' })
|
||||
end
|
||||
|
||||
def test_link_to_data_nil_equal
|
||||
|
|
Loading…
Reference in New Issue