module Avo module Concerns module HasHTMLAttributes extend ActiveSupport::Concern attr_reader :html # Used to get attributes for elements and views # # examples: # get_html :data, view: :edit, element: :input # get_html :classes, view: :show, element: :wrapper # get_html :styles, view: :index, element: :wrapper def get_html(name = nil, element:, view:) if [view, element].any?(&:nil?) || Avo::App.license.lacks_with_trial(:stimulus_js_integration) default_attribute_value name end attributes = if html_builder.is_a? Hash get_html_from_hash name, element: element, view: view elsif html_builder.is_a? Avo::HTML::Builder get_html_from_block name, element: element, view: view elsif html_builder.nil? # Handle empty html_builder by returning an empty state default_attribute_value name end add_default_data_attributes attributes, name, element, view end private def html_builder return @parsed_html if @parsed_html.present? return if @html.nil? # Memoize the value @parsed_html = if @html.is_a? Hash @html elsif @html.respond_to? :call Avo::HTML::Builder.parse_block(record: model, resource: resource, &@html) end @parsed_html end def default_attribute_value(name) name == :data ? {} : "" end def add_default_data_attributes(attributes, name, element, view) if !attributes.nil? && name == :data && element == :input && view.in?([:edit, :new]) && resource.present? && resource.respond_to?(:get_stimulus_controllers) extra_attributes = resource.get_stimulus_controllers .split(" ") .map do |controller| [:"#{controller}-target", "#{id.to_s.underscore}_#{type.to_s.underscore}_input".camelize(:lower)] end .to_h extra_attributes.merge attributes else attributes end end def get_html_from_block(name = nil, element:, view:) values = [] # get view ancestor values << html_builder.dig_stack(view, element, name) # get element ancestor values << html_builder.dig_stack(element, name) # get direct ancestor values << html_builder.dig_stack(name) values_type = if name == :data :hash else :string end merge_values_as(as: values_type, values: values) end def get_html_from_hash(name = nil, element:, view:) # @todo: what if this is not a Hash but a string? html_builder.dig(view, element, name) || {} end # Merge the values from all possible locations. # If the result is "blank", return nil so the attributes are not outputted to the DOM. # # Ex: if the style attribute is empty return `nil` instead of an empty space `" "` def merge_values_as(as: :array, values: []) result = if as == :array values.flatten elsif as == :string values.select do |value| value.is_a? String end.join " " elsif as == :hash values.reduce({}, :merge) end result if result.present? end end end end