2016-08-26 13:37:45 -04:00
|
|
|
# frozen_string_literal: true
|
2021-06-08 00:28:09 -04:00
|
|
|
require 'haml/object_ref'
|
2015-10-11 02:31:13 -04:00
|
|
|
|
2021-06-08 00:28:09 -04:00
|
|
|
module Haml::AttributeBuilder
|
2015-11-16 17:34:11 -05:00
|
|
|
BOOLEAN_ATTRIBUTES = %w[disabled readonly multiple checked autobuffer
|
|
|
|
autoplay controls loop selected hidden scoped async
|
|
|
|
defer reversed ismap seamless muted required
|
|
|
|
autofocus novalidate formnovalidate open pubdate
|
|
|
|
itemscope allowfullscreen default inert sortable
|
2016-10-12 01:33:58 -04:00
|
|
|
truespeed typemustmatch download].freeze
|
2018-11-01 02:30:12 -04:00
|
|
|
|
2022-10-09 02:37:10 -04:00
|
|
|
# For JRuby, TruffleRuby, and Wasm, fallback to Ruby implementation.
|
|
|
|
if /java|wasm/ === RUBY_PLATFORM || RUBY_ENGINE == 'truffleruby'
|
2018-11-01 02:30:12 -04:00
|
|
|
class << self
|
2021-02-01 16:19:44 -05:00
|
|
|
def build(escape_attrs, quote, format, boolean_attributes, object_ref, *hashes)
|
2021-06-08 00:28:09 -04:00
|
|
|
hashes << Haml::ObjectRef.parse(object_ref) if object_ref
|
2018-11-01 02:30:12 -04:00
|
|
|
buf = []
|
|
|
|
hash = merge_all_attrs(hashes)
|
|
|
|
|
|
|
|
keys = hash.keys.sort!
|
|
|
|
keys.each do |key|
|
|
|
|
case key
|
|
|
|
when 'id'.freeze
|
|
|
|
buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}"
|
|
|
|
when 'class'.freeze
|
|
|
|
buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
|
|
|
|
when 'data'.freeze
|
|
|
|
buf << build_data(escape_attrs, quote, *hash[key])
|
2021-02-01 16:19:44 -05:00
|
|
|
when *boolean_attributes, /\Adata-/
|
2018-11-01 02:30:12 -04:00
|
|
|
build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
|
|
|
|
else
|
|
|
|
buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
buf.join
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_id(escape_attrs, *values)
|
|
|
|
escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_class(escape_attrs, *values)
|
|
|
|
if values.size == 1
|
|
|
|
value = values.first
|
|
|
|
case
|
|
|
|
when value.is_a?(String)
|
|
|
|
# noop
|
|
|
|
when value.is_a?(Array)
|
2020-09-30 22:31:35 -04:00
|
|
|
value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ')
|
2018-11-01 02:30:12 -04:00
|
|
|
when value
|
|
|
|
value = value.to_s
|
|
|
|
else
|
|
|
|
return ''
|
|
|
|
end
|
|
|
|
return escape_html(escape_attrs, value)
|
|
|
|
end
|
|
|
|
|
|
|
|
classes = []
|
|
|
|
values.each do |value|
|
|
|
|
case
|
|
|
|
when value.is_a?(String)
|
|
|
|
classes += value.split(' ')
|
|
|
|
when value.is_a?(Array)
|
|
|
|
classes += value.select { |v| v }
|
|
|
|
when value
|
|
|
|
classes << value.to_s
|
|
|
|
end
|
|
|
|
end
|
2020-09-30 22:31:35 -04:00
|
|
|
escape_html(escape_attrs, classes.map(&:to_s).uniq.join(' '))
|
2018-11-01 02:30:12 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def build_data(escape_attrs, quote, *hashes)
|
|
|
|
build_data_attribute(:data, escape_attrs, quote, *hashes)
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_aria(escape_attrs, quote, *hashes)
|
|
|
|
build_data_attribute(:aria, escape_attrs, quote, *hashes)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def build_data_attribute(key, escape_attrs, quote, *hashes)
|
|
|
|
attrs = []
|
2018-11-01 04:06:00 -04:00
|
|
|
if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
|
|
|
|
data_value = merge_all_attrs(hashes)
|
|
|
|
else
|
|
|
|
data_value = hashes.last
|
|
|
|
end
|
|
|
|
hash = flatten_attributes(key => data_value)
|
2018-11-01 02:30:12 -04:00
|
|
|
|
|
|
|
hash.sort_by(&:first).each do |key, value|
|
|
|
|
case value
|
|
|
|
when true
|
|
|
|
attrs << " #{key}"
|
|
|
|
when nil, false
|
|
|
|
# noop
|
|
|
|
else
|
|
|
|
attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
attrs.join
|
|
|
|
end
|
|
|
|
|
|
|
|
def flatten_attributes(attributes)
|
|
|
|
flattened = {}
|
|
|
|
|
|
|
|
attributes.each do |key, value|
|
|
|
|
case value
|
|
|
|
when attributes
|
|
|
|
when Hash
|
|
|
|
flatten_attributes(value).each do |k, v|
|
2018-11-01 03:50:17 -04:00
|
|
|
if k.nil?
|
2018-11-01 02:30:12 -04:00
|
|
|
flattened[key] = v
|
2018-11-01 03:50:17 -04:00
|
|
|
else
|
|
|
|
flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
|
2018-11-01 02:30:12 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
flattened[key] = value if value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
flattened
|
|
|
|
end
|
|
|
|
|
|
|
|
def merge_all_attrs(hashes)
|
|
|
|
merged = {}
|
|
|
|
hashes.each do |hash|
|
|
|
|
hash.each do |key, value|
|
|
|
|
key = key.to_s
|
|
|
|
case key
|
|
|
|
when 'id'.freeze, 'class'.freeze, 'data'.freeze
|
|
|
|
merged[key] ||= []
|
|
|
|
merged[key] << value
|
|
|
|
else
|
|
|
|
merged[key] = value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
merged
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_boolean!(escape_attrs, quote, format, buf, key, value)
|
|
|
|
case value
|
|
|
|
when true
|
|
|
|
case format
|
|
|
|
when :xhtml
|
|
|
|
buf << " #{key}=#{quote}#{key}#{quote}"
|
|
|
|
else
|
|
|
|
buf << " #{key}"
|
|
|
|
end
|
|
|
|
when false, nil
|
|
|
|
# omitted
|
|
|
|
else
|
|
|
|
buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def escape_html(escape_attrs, str)
|
|
|
|
if escape_attrs
|
2021-07-28 02:09:13 -04:00
|
|
|
Haml::Util.escape_html(str)
|
2018-11-01 02:30:12 -04:00
|
|
|
else
|
|
|
|
str
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-10-09 02:30:48 -04:00
|
|
|
else
|
|
|
|
# Haml::AttributeBuilder.build
|
|
|
|
# Haml::AttributeBuilder.build_id
|
|
|
|
# Haml::AttributeBuilder.build_class
|
|
|
|
# Haml::AttributeBuilder.build_data
|
|
|
|
# Haml::AttributeBuilder.build_aria
|
|
|
|
require 'haml/haml'
|
2018-11-01 02:30:12 -04:00
|
|
|
end
|
2015-10-11 02:31:13 -04:00
|
|
|
end
|