Created
December 18, 2021 10:00
-
-
Save dbroeglin/c85dbe6e6887fae14988cb3d22861879 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ApplicationHelper | |
class BulmaFormBuilder < ActionView::Helpers::FormBuilder | |
delegate :tag, :safe_join, to: :@template | |
def input(method, options = {}) | |
@form_options = options | |
object_type = object_type_for_method(method) | |
input_type = input_type_for_object_type(object_type, options) | |
send("#{input_type}_input", method, options) | |
end | |
def label(method, options = {}) | |
options = {} if options.nil? | |
options[:class] = [options[:class], 'label'].join ' ' | |
super | |
end | |
private | |
def collection_input(method, options, &block) | |
form_field(method, options) do | |
safe_join [ | |
label(method, options[:label]), | |
(tag.div class: 'select' do | |
block.call | |
end)] | |
end | |
end | |
def select_input(method, options = {}) | |
end | |
def string_input(method, options = {}) | |
form_field(method, options) do | |
safe_join [ | |
( | |
unless options[:label] == false | |
label(method, options[:label]) | |
end | |
), | |
( | |
tag.div class: 'control' do | |
string_field( | |
method, | |
merge_input_options( | |
{ | |
class: | |
"input #{'is-danger' if has_error?(method)}", | |
}, | |
options[:input_html], | |
), | |
) | |
end | |
), | |
] | |
end | |
end | |
def select_input(method, options = {}) | |
value_method = options[:value_method] || :to_s | |
text_method = options[:text_method] || :to_s | |
input_options = options[:input_html] || {} | |
multiple = input_options[:multiple] | |
collection_input(method, options) do | |
collection_select( | |
method, | |
options[:collection], | |
value_method, | |
text_method, | |
options, | |
merge_input_options( | |
{ | |
class: | |
"#{'select' unless multiple} form-control #{'is-invalid' if has_error?(method)}", | |
}, | |
options[:input_html], | |
), | |
) | |
end | |
end | |
def boolean_input(method, options = {}) | |
form_field(method, options) do | |
label(method, options) do | |
safe_join [ | |
check_box(method, merge_input_options({class: "checkbox"}, options[:input_html])), | |
" #{object.class.human_attribute_name(method).html_safe}", | |
] | |
end | |
end | |
end | |
def text_input(method, options = {}) | |
form_field(method, options) do | |
safe_join [ | |
(label(method, options[:label]) unless options[:label] == false), | |
text_area(method, merge_input_options({class: "textarea #{"is-invalid" if has_error?(method)}"}, options[:input_html])), | |
] | |
end | |
end | |
def string_field(method, options = {}) | |
case object_type_for_method(method) | |
when :date | |
birthday = method.to_s =~ /birth/ | |
safe_join [ | |
date_field( | |
method, | |
merge_input_options( | |
options, | |
{ data: { datepicker: true } }, | |
), | |
), | |
tag.div { | |
date_select( | |
method, | |
{ | |
order: %i[month day year], | |
start_year: birthday ? 1900 : Date.today.year - 5, | |
end_year: | |
birthday ? Date.today.year : Date.today.year + 5, | |
}, | |
{ data: { date_select: true } }, | |
) | |
}, | |
] | |
when :integer | |
number_field(method, options) | |
when :string | |
case method.to_s | |
when /password/ | |
password_field(method, options) | |
# when /time_zone/ then :time_zone | |
# when /country/ then :country | |
when /email/ | |
email_field(method, options) | |
when /phone/ | |
telephone_field(method, options) | |
when /url/ | |
url_field(method, options) | |
else | |
text_field(method, options) | |
end | |
end | |
end | |
# Compute the type of object we deal with | |
def object_type_for_method(method) | |
result = | |
if @object.respond_to?(:type_for_attribute) && | |
@object.has_attribute?(method) | |
@object.type_for_attribute(method.to_s).try(:type) | |
elsif @object.respond_to?(:column_for_attribute) && | |
@object.has_attribute?(method) | |
@object.column_for_attribute(method).try(:type) | |
end | |
result || :string | |
end | |
# Computes the type of input we will use to edit the object | |
def input_type_for_object_type(object_type, options) | |
input_type = | |
case object_type | |
when :date | |
:string | |
when :integer | |
:string | |
else | |
object_type | |
end | |
if options[:as] | |
options[:as] | |
elsif options[:collection] | |
:select | |
else | |
input_type | |
end | |
end | |
def form_field(method, options = {}, &block) | |
tag.div class: 'field' do | |
safe_join [ | |
block.call, | |
#hint_text(options[:hint]), | |
error_text(method), | |
].compact | |
end | |
end | |
# def hint_text(text) | |
# return if text.nil? | |
# tag.small text, class: "form-text text-muted" | |
# end | |
def error_text(method) | |
@object | |
.errors | |
.where(method) | |
.map { |error| tag.div error.full_message, class: 'help is-danger' } | |
end | |
def has_error?(method) | |
return false unless @object.respond_to?(:errors) | |
@object.errors.key?(method) | |
end | |
def merge_input_options(options, user_options) | |
return options if user_options.nil? | |
# TODO handle class merging here | |
options.merge(user_options) | |
end | |
end | |
def bulma_form_for(name, *args, &block) | |
options = args.extract_options! | |
args << options.merge(builder: BulmaFormBuilder) | |
form_for(name, *args, &block) | |
end | |
def bulma_form_with( | |
model: nil, | |
scope: nil, | |
url: nil, | |
format: nil, | |
**options, | |
&block | |
) | |
options = options.reverse_merge(builder: BulmaFormBuilder) | |
form_with( | |
model: model, | |
scope: scope, | |
url: url, | |
format: format, | |
**options, | |
&block | |
) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment