module CmAdmin
module ViewHelpers
module FormFieldHelper
def input_field_for_column(form_obj, cm_field, is_required: nil)
return unless cm_field.display_if.call(form_obj.object)
value = if cm_field.helper_method
send(cm_field.helper_method, form_obj.object, cm_field.field_name)
elsif cm_field.input_type.to_s.include?('custom')
nil
else
form_obj.object.send(cm_field.field_name)
end
is_required = is_field_presence_validated?(form_obj, cm_field) if is_required.nil?
required_class = is_required ? 'required' : ''
target_action = @model.available_actions.select { |x| x.name == cm_field.target[:action_name].to_s }.first if cm_field.target.present?
send("cm_#{cm_field.input_type}_field", form_obj, cm_field, value, required_class, target_action, cm_field.ajax_url)
end
def cm_integer_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
form_obj.text_field cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value:,
placeholder: cm_field.placeholder,
data: { behaviour: 'integer-only' }
}, cm_field.html_attrs
)
end
def cm_decimal_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
form_obj.text_field cm_field.field_name,
merge_wrapper_options({
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value:,
placeholder: cm_field.placeholder,
data: { behaviour: 'decimal-only' }
}, cm_field.html_attrs)
end
def cm_string_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
form_obj.text_field cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value:,
placeholder: cm_field.placeholder
}, cm_field.html_attrs
)
end
def cm_switch_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)\
content_tag :div, class: 'form-check form-switch' do
concat form_obj.check_box cm_field.field_name,
merge_wrapper_options(
{
class: "field-control form-check-input #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value:,
role: 'switch'
}, cm_field.html_attrs
)
concat content_tag(:div, cm_field.label, class: 'cm-switch-label')
end
end
def cm_custom_string_field(form_obj, cm_field, value, required_class, _target_action_ajax_url)
text_field_tag cm_field.html_attrs[:name] || cm_field.field_name,
merge_wrapper_options(
{
value:,
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
placeholder: cm_field.placeholder
}, cm_field.html_attrs
)
end
def cm_single_select_field(form_obj, cm_field, _value, required_class, target_action, ajax_url)
class_name = ajax_url.present? ? 'select-2-ajax' : 'select-2'
form_obj.select cm_field.field_name, options_for_select(select_collection_value(form_obj.object, cm_field), form_obj.object.send(cm_field.field_name)),
{ include_blank: cm_field.placeholder },
merge_wrapper_options(
{
class: "field-control #{required_class} #{class_name}",
disabled: cm_field.disabled.call(form_obj.object),
data: {
field_name: cm_field.field_name,
field_type: 'linked-field',
target_action: target_action&.name,
target_url: target_action&.name ? cm_admin.send("cm_#{target_action&.name}_#{@model.name.underscore}_path") : '',
ajax_url:
}
}, cm_field.html_attrs
)
end
def cm_custom_single_select_field(form_obj, cm_field, _value, required_class, target_action, _ajax_url)
select_tag cm_field.html_attrs[:name] || cm_field.field_name,
options_for_select(select_collection_value(form_obj.object, cm_field)),
{ include_blank: cm_field.placeholder },
merge_wrapper_options(
{
class: "field-control #{required_class} select-2",
disabled: cm_field.disabled.call(form_obj.object),
data: {
field_name: cm_field.field_name,
field_type: 'linked-field',
target_action: target_action&.name,
target_url: target_action&.name ? cm_admin.send("cm_#{target_action&.name}_#{@model.name.underscore}_path") : ''
}
}, cm_field.html_attrs
)
end
def cm_multi_select_field(form_obj, cm_field, _value, required_class, _target_action, _ajax_url)
form_obj.select cm_field.field_name,
options_for_select(select_collection_value(form_obj.object, cm_field), form_obj.object.send(cm_field.field_name)),
{ include_blank: cm_field.placeholder },
merge_wrapper_options(
{
class: "field-control #{required_class} select-2",
disabled: cm_field.disabled.call(form_obj.object), multiple: true
}, cm_field.html_attrs
)
end
def cm_date_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
form_obj.text_field cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value: value&.strftime('%d-%m-%Y'),
placeholder: cm_field.placeholder,
data: { behaviour: 'date-only' }
}, cm_field.html_attrs
)
end
def cm_custom_date_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
text_field_tag cm_field.html_attrs[:name] || cm_field.field_name, value&.strftime('%d-%m-%Y'),
merge_wrapper_options(
{
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value: value&.strftime('%d-%m-%Y'),
placeholder: cm_field.placeholder,
data: { behaviour: 'date-only' }
}, cm_field.html_attrs
)
end
def cm_date_time_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
form_obj.text_field cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class}",
disabled: cm_field.disabled.call(form_obj.object),
value:,
placeholder: cm_field.placeholder,
data: { behaviour: 'date-time' }
}, cm_field.html_attrs
)
end
def cm_text_field(form_obj, cm_field, _value, required_class, _target_action, _ajax_url)
form_obj.text_area cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class}",
placeholder: cm_field.placeholder
}, cm_field.html_attrs
)
end
def cm_rich_text_field(form_obj, cm_field, _value, required_class, _target_action, _ajax_url)
form_obj.rich_text_area cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class}",
placeholder: cm_field.placeholder
}, cm_field.html_attrs
)
end
def cm_single_file_upload_field(form_obj, cm_field, _value, required_class, _target_action, _ajax_url)
content_tag(:div, data: { 'field-type': 'single_file_upload' }) do
concat attachment_list(form_obj, cm_field, _value, required_class, _target_action)
concat form_obj.file_field cm_field.field_name,
merge_wrapper_options(
{
class: "field-control #{required_class} #{form_obj.object.send(cm_field.field_name).attached? ? 'hidden' : ''}",
disabled: cm_field.disabled.call(form_obj.object)
}, cm_field.html_attrs
)
end
end
def cm_multi_file_upload_field(form_obj, cm_field, _value, required_class, _target_action, _ajax_url)
content_tag(:div, data: { 'field-type': 'multi_file_upload' }) do
concat attachment_list(form_obj, cm_field, _value, required_class, _target_action)
concat form_obj.file_field cm_field.field_name,
merge_wrapper_options(
{
multiple: true, class: "field-control #{required_class}}",
disabled: cm_field.disabled.call(form_obj.object)
}, cm_field.html_attrs
)
end
end
def attachment_list(form_obj, cm_field, _value, _required_class, _target_action)
attached = form_obj.object.send(cm_field.field_name)
attachment_name = "#{form_obj.object_name}_#{cm_field.field_name}_attachments"
return if defined?(::Paperclip) && attached.instance_of?(::Paperclip::Attachment)
content_tag(:div, data: { section: 'image-preview'}) do
if attached.class == ActiveStorage::Attached::Many
attached.each do |attachment|
concat attachment_with_icon(cm_field, attachment, attachment_name:)
end
elsif attached.attached?
concat attachment_with_icon(cm_field, attached, attachment_name:)
end
end
end
def attachment_with_icon(cm_field, attachment, attachment_name:)
content_tag(:div, data: { section: 'destroy-attachment', ar_id: attachment.id, attachment_name: }) do
concat(content_tag(:a, href: attachment.url, target: '_blank') do
if attachment.content_type.include?('image')
image_tag(attachment.url, height: 50, width: 50, class: "rounded")
end
end) if cm_field.image_preview
concat content_tag(:span, attachment.filename.to_s, class: 'btn-link')
concat(content_tag(:button, '', class: 'btn-ghost') do
concat tag.i(class: 'fa-regular fa-trash-can')
end) if cm_field.input_type == :single_file_upload
end
end
def cm_check_box_field(form_obj, cm_field, _value, required_class, target_action, _ajax_url)
content_tag :div, class: 'form-check' do
concat form_obj.check_box cm_field.field_name,
merge_wrapper_options(
{
class: "form-check-input #{required_class} #{target_action.present? ? 'linked-field-request' : ''}",
disabled: cm_field.disabled.call(form_obj.object),
data: {
field_name: cm_field.field_name,
target_action: target_action&.name,
target_url: target_action&.name ? cm_admin.send("cm_#{target_action&.name}_#{@model.name.underscore}_path") : ''
}
}, cm_field.html_attrs
)
concat content_tag(:div, cm_field.label, class: 'cm-checkbox-label')
end
end
def cm_checkbox_group_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)
original_value = form_obj.object.send(cm_field.field_name)
content_tag :div do
concat form_obj.text_field cm_field.field_name, name: "#{@model.name.underscore}[#{cm_field.field_name}][]",
value: nil, hidden: true
value.each do |key, val|
is_checked = original_value.include?(val)
concat format_check_box(val || key, key, form_obj, cm_field, required_class, is_checked)
end
end
end
def cm_radio_button_field(form_obj, cm_field, value, _required_class, _target_action, _ajax_url)
content_tag :div do
value.each do |key, val|
concat format_radio_option(val || key, key, cm_field, form_obj)
end
end
end
def cm_radio_button_group_field(form_obj, cm_field, value, _required_class, _target_action, _ajax_url)
content_tag :div, class: 'btn-group', role: 'group' do
value.each do |key, val|
format_radio_button_group_option(val || key, key, cm_field, form_obj)
end
end
end
def cm_hidden_field(form_obj, cm_field, value, _required_class, _target_action, _ajax_url)
form_obj.hidden_field cm_field.field_name,
merge_wrapper_options(
{
value:,
name: cm_field.html_attrs[:name] || "#{form_obj.object_name}[#{cm_field.field_name}]"
}, cm_field.html_attrs
)
end
# Refactor: Collection argument can be removed.
# helper_method argument will accept a method where value can be passed.
def select_collection_value(object, cm_field)
if cm_field.helper_method
send(cm_field.helper_method, object, cm_field.field_name)
elsif cm_field.collection
cm_field.collection
else
[]
end
end
def format_check_box(val, key, form_obj, cm_field, required_class, is_checked)
content_tag :div, class: 'form-check' do
concat check_box_tag "#{@model.name.underscore}[#{cm_field.field_name}][]", val, is_checked,
merge_wrapper_options(
{
class: "form-check-input #{required_class}",
disabled: cm_field.disabled.call(form_obj.object)
}, cm_field.html_attrs
)
concat content_tag(:div, key, class: 'cm-checkbox-label')
end
end
def format_radio_option(val, key, cm_field, form_obj)
content_tag :div, class: 'form-check' do
concat form_obj.radio_button cm_field.field_name, val, merge_wrapper_options({ class: 'form-check-input' }, cm_field.html_attrs)
concat content_tag(:div, key, class: 'form-check-label')
end
end
def format_radio_button_group_option(val, key, cm_field, form_obj)
id = "#{cm_field.field_name}_#{val}"
concat form_obj.radio_button cm_field.field_name, val, merge_wrapper_options({ id:, class: 'btn-check' },
cm_field.html_attrs)
concat content_tag(:label, key, class: 'btn btn-outline-dark btn-sm', for: id)
end
def merge_wrapper_options(options, html_attrs)
if html_attrs
options.merge(html_attrs) do |key, oldval, newval|
case key.to_s
when 'class'
oldval + ' ' + newval
when 'data', 'aria'
oldval.merge(newval)
else
newval
end
end
else
options
end
end
end
end
end