Values can contain dots. We use values to generate classes for form elements, and dots in class names are not valid. This commit replaces dots with dashes in form element classes. Currently, we don't use dots in any of the values, but I'll use them in a future PR.
122 lines
5.2 KiB
Plaintext
122 lines
5.2 KiB
Plaintext
<%# locals: (action:, form_elements:, option_tree:, option_parents:, method: "POST", pre_selected_values: {}, mode: "create") %>
|
|
<% nonce = SecureRandom.base64(32)
|
|
content_security_policy.add_script_src [:nonce, nonce] %>
|
|
|
|
<script nonce="<%==nonce%>">
|
|
let option_tree = <%==JSON.generate(option_tree)%>
|
|
let option_children = <%==JSON.generate(option_parents.each_with_object(Hash.new { |h, k| h[k] = [] }) { |(child, parents), h| h[parents.last] << child if parents.any? })%>
|
|
let option_dirty = <%==JSON.generate(form_elements.map { it[:name] }.each_with_object(Hash.new { |h, k| h[k] = [] }) { |option, h| h[option] = flash.dig("old", option) || pre_selected_values[option] })%>
|
|
</script>
|
|
|
|
<div>
|
|
<div class="grid gap-6">
|
|
<form action="<%= action %>" method="POST" id="creation-form" class="<%= method %>">
|
|
<%== csrf_tag(action, method) %>
|
|
<% container_class = (mode == "create") ? "overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white" : "" %>
|
|
<div class="<%= container_class %>">
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<div class="space-y-12">
|
|
<div>
|
|
<div class="mt-2 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
|
<% selected_options = {}
|
|
pre_selected_values.each { |k, v| selected_options[k] = v.to_s }
|
|
|
|
form_elements.each do |element|
|
|
container_opening_tag = element[:opening_tag] || "<div class='col-span-full'>"
|
|
container_closing_tag = element[:closing_tag] || "</div>"
|
|
|
|
name, type, label, required, placeholder, content_generator = element.values_at(:name, :type, :label, :required, :placeholder, :content_generator)
|
|
|
|
has_option = ["radio_small_cards", "select", "checkbox"].include?(type)
|
|
options = OptionTreeGenerator.generate_allowed_options(name, option_tree, option_parents).map do |option|
|
|
opt_val = if option[name].is_a?(Sequel::Model)
|
|
option[name].ubid
|
|
elsif type == "select"
|
|
option[name][:value]
|
|
else
|
|
option[name]
|
|
end
|
|
|
|
opt_text = content_generator.call(*option.values)
|
|
|
|
parents = option.reject { |k, v| k == name }.transform_values { |v| v.is_a?(Sequel::Model) ? v.ubid : v }
|
|
|
|
parents_selected = parents.all? { |k, v| selected_options[k] == v }
|
|
submitted_value = flash.dig("old", name)
|
|
selected_in_form_submission = submitted_value == opt_val
|
|
selected_in_pre_selection = submitted_value.nil? && selected_options[name] == opt_val
|
|
first_of_its_kind = submitted_value.nil? && selected_options[name].nil?
|
|
checked = parents_selected && (selected_in_form_submission || selected_in_pre_selection || first_of_its_kind)
|
|
selected_options[name] = opt_val if checked
|
|
|
|
opt_classes = parents.map { |k, v| "form_#{k} form_#{k}_#{v.tr(".", "-")}" }
|
|
opt_classes << "hidden" unless parents_selected
|
|
opt_classes = opt_classes.join(" ")
|
|
|
|
opt_attrs = {}
|
|
opt_attrs[:disabled] = "disabled" unless parents_selected
|
|
opt_attrs[:checked] = checked
|
|
|
|
[opt_val, opt_text, opt_classes, opt_attrs]
|
|
end if has_option
|
|
|
|
if has_option && selected_options[name].nil?
|
|
options.find{ |_, _, _, opt_attrs| opt_attrs[:disabled].nil? }&.tap do |opt_val, _, _, opt_attrs|
|
|
opt_attrs[:checked] = true
|
|
selected_options[name] = opt_val
|
|
end
|
|
end
|
|
|
|
attributes = {required:}
|
|
|
|
case type
|
|
when "radio_small_cards"
|
|
locals = {name:, label:, options:, attributes:}
|
|
when "select"
|
|
locals = {name:, label:, options:, placeholder:, attributes:, description_html: element[:description_html]}
|
|
when "checkbox"
|
|
locals = {name:, label:, options:, description: element[:description]}
|
|
when "text"
|
|
locals = {name:, label:, value: element[:value], attributes: attributes.merge!({placeholder:})}
|
|
when "number"
|
|
locals = {name:, label:, type: "number", attributes: attributes.merge!({placeholder:})}
|
|
type = "text"
|
|
when "textarea"
|
|
locals = {name:, label:, description: element[:description], attributes: attributes.merge!({placeholder:, rows: 3})}
|
|
when "hidden"
|
|
selected_options[name] = element[:value]
|
|
locals = {name:, value: element[:value]}
|
|
container_opening_tag, container_closing_tag = "", ""
|
|
when "partnership_notice"
|
|
description, tos_text = content_generator.call(@flavor)
|
|
locals = {description:, tos_text:}
|
|
when "section"
|
|
locals = {label:, content: element[:content], separator: element[:separator]}
|
|
# :nocov:
|
|
else
|
|
raise "Unknown element type: #{type}"
|
|
# :nocov:
|
|
end %>
|
|
<%== container_opening_tag %>
|
|
<%== part("components/form/#{type}", **locals) %>
|
|
<%== container_closing_tag %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<div class="flex items-center justify-end gap-x-6">
|
|
<% if mode == "create" %>
|
|
<a href="<%= action %>" class="text-sm font-semibold leading-6 text-gray-900">Cancel</a>
|
|
<%== part("components/form/submit_button", text: "Create") %>
|
|
<% else %>
|
|
<%== part("components/form/submit_button", text: "Update") %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|