diff --git a/.gitignore b/.gitignore index b04a8c8..014fe7a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,10 @@ # rspec failure tracking .rspec_status + + +demo/db/*.sqlite3 +demo/log/** +demo/tmp/**/* +demo/*.byebug_history +demo/public/assets diff --git a/Gemfile.lock b/Gemfile.lock index 6ffee31..0174178 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - rails_bootstrap_form (0.2.0) + rails_bootstrap_form (0.2.1) GEM remote: http://rubygems.org/ diff --git a/demo/config/locales/en.rb b/demo/config/locales/en.rb index 44453c8..4181470 100644 --- a/demo/config/locales/en.rb +++ b/demo/config/locales/en.rb @@ -6,11 +6,44 @@ en: { activerecord: { attributes: { - + country: { + name: "Name", + }, + fruit: { + name: "Name", + }, + skill: { + name: "Name", + }, + user: { + name: "Name", + email: "Email address", + password: "Password", + password_confirmation: "Confirm password", + mobile_number: "Mobile number", + blog_url: "Blog URL", + birth_date: "Birth date", + fruit_id: "Favorite fruit", + terms: "I accept terms and conditions", + excellence: "Excellence", + }, + user_skill: { + user_id: "User", + skill_id: "Skill" + }, + address: { + street: "Street", + state: "State", + city: "City", + postal_code: "Postal code", + country_id: "Country" + }, }, help_texts: { - + user: { + email: "Please use official email address" + } }, - }, + } } } diff --git a/lib/rails_bootstrap_form.rb b/lib/rails_bootstrap_form.rb index 3ac939f..be24e8c 100644 --- a/lib/rails_bootstrap_form.rb +++ b/lib/rails_bootstrap_form.rb @@ -13,11 +13,15 @@ module RailsBootstrapForm autoload :Configuration autoload :BootstrapFormOptions autoload :BootstrapFormBuilder + autoload :FieldWrapperBuilder + autoload :Components + autoload :Inputs end class << self def eager_load! super + RailsBootstrapForm::Components.eager_load! end def config diff --git a/lib/rails_bootstrap_form/bootstrap_form_builder.rb b/lib/rails_bootstrap_form/bootstrap_form_builder.rb index 5aa0734..4396d28 100644 --- a/lib/rails_bootstrap_form/bootstrap_form_builder.rb +++ b/lib/rails_bootstrap_form/bootstrap_form_builder.rb @@ -4,6 +4,11 @@ module RailsBootstrapForm class BootstrapFormBuilder < ActionView::Helpers::FormBuilder + + include RailsBootstrapForm::FieldWrapperBuilder + include RailsBootstrapForm::Components + include RailsBootstrapForm::Inputs + delegate :capture, :concat, :tag, to: :@template attr_accessor :bootstrap_form_options diff --git a/lib/rails_bootstrap_form/bootstrap_form_options.rb b/lib/rails_bootstrap_form/bootstrap_form_options.rb index 1c91652..f07b894 100644 --- a/lib/rails_bootstrap_form/bootstrap_form_options.rb +++ b/lib/rails_bootstrap_form/bootstrap_form_options.rb @@ -20,6 +20,20 @@ class BootstrapFormOptions # It can also be "floating" if field should have floating labels. attr_accessor :layout + # A CSS class that will be applied to all form fields and it can be overridden + # by the `BootstrapFormOptions` object. Default is `form-control`. + attr_accessor :field_class + + # An additional CSS class that will be added along with the existing + # `field_class` of the field. Default is nil. + attr_accessor :additional_field_class + + # Describes help text for the HTML field. Help text is automatically read + # from translation file. If you want to customize it, you can pass string. + # You can also set it false if you do not want help text displayed. + # Default is nil. + attr_accessor :help_text + def initialize(options = {}) set_defaults set_bootstrap_form_options(options) @@ -64,6 +78,11 @@ def set_bootstrap_form_options(options) def set_defaults @layout = "vertical" + + @field_class = "form-control" + @additional_field_class = nil + + @help_text = nil end private :set_defaults diff --git a/lib/rails_bootstrap_form/components.rb b/lib/rails_bootstrap_form/components.rb new file mode 100644 index 0000000..0e71461 --- /dev/null +++ b/lib/rails_bootstrap_form/components.rb @@ -0,0 +1,13 @@ +# -*- encoding: utf-8 -*- +# -*- frozen_string_literal: true -*- +# -*- warn_indent: true -*- + +module RailsBootstrapForm + module Components + extend ActiveSupport::Autoload + + autoload :HelpText + + include HelpText + end +end diff --git a/lib/rails_bootstrap_form/components/help_text.rb b/lib/rails_bootstrap_form/components/help_text.rb new file mode 100644 index 0000000..c6b2232 --- /dev/null +++ b/lib/rails_bootstrap_form/components/help_text.rb @@ -0,0 +1,53 @@ +# -*- encoding: utf-8 -*- +# -*- frozen_string_literal: true -*- +# -*- warn_indent: true -*- + +module RailsBootstrapForm + module Components + module HelpText + extend ActiveSupport::Concern + + def self.included(base_class) + def help_text(attribute, bootstrap_options) + return if bootstrap_options.help_text == false + + help_text = (bootstrap_options.help_text || scoped_help_text(attribute)) + + tag.span(help_text, class: "form-text text-muted") if help_text.present? + end + + def object_class + if !object.class.is_a?(ActiveModel::Naming) && + object.respond_to?(:klass) && object.klass.is_a?(ActiveModel::Naming) + object.klass + else + object.class + end + end + + def partial_scope + if object_class.respond_to?(:model_name) + object_class.model_name.name + else + object_class.name + end + end + + def scoped_help_text(attribute) + translation_scope = "activerecord.help_texts.#{partial_scope.underscore}" + + help_text = translated_help_text(attribute, translation_scope).presence + + help_text + end + + def translated_help_text(attribute, scope) + ActiveSupport::SafeBuffer.new(I18n.t(attribute, scope: scope, default: "")) + end + + private :help_text, :partial_scope, :object_class, :scoped_help_text + :translated_help_text + end + end + end +end diff --git a/lib/rails_bootstrap_form/field_wrapper_builder.rb b/lib/rails_bootstrap_form/field_wrapper_builder.rb new file mode 100644 index 0000000..027311d --- /dev/null +++ b/lib/rails_bootstrap_form/field_wrapper_builder.rb @@ -0,0 +1,51 @@ +# -*- encoding: utf-8 -*- +# -*- frozen_string_literal: true -*- +# -*- warn_indent: true -*- + +module RailsBootstrapForm + module FieldWrapperBuilder + def field_wrapper_builder(attribute, options, html_options = nil, &block) + bootstrap_options = bootstrap_form_options.scoped(options.delete(:bootstrap_form)) + + field_options = field_css_options(attribute, bootstrap_options, options, html_options.try(:symbolize_keys!)) + + field_wrapper(attribute, bootstrap_options, field_options, &block) + end + + def field_wrapper(attribute, bootstrap_options, options, &block) + help_text = help_text(attribute, bootstrap_options) + + tag.div(class: field_wrapper_classes) do + concat(capture(&block)) + concat(help_text) + end + end + + def field_wrapper_classes + classes = [form_wrapper_default_class] + classes.flatten.compact + end + + def field_wrapper_options + end + + def form_wrapper_default_class + "mb-3" + end + + def field_css_options(attribute, bootstrap_options, options, html_options) + css_options = (html_options || options) + + field_classes = [ + bootstrap_options.field_class, + bootstrap_options.additional_field_class + ] + css_options[:class] = field_classes.flatten.compact + + css_options + end + + private :field_wrapper, :field_wrapper_classes, :form_wrapper_default_class, + :field_css_options + end +end diff --git a/lib/rails_bootstrap_form/inputs.rb b/lib/rails_bootstrap_form/inputs.rb new file mode 100644 index 0000000..21af500 --- /dev/null +++ b/lib/rails_bootstrap_form/inputs.rb @@ -0,0 +1,43 @@ +# -*- encoding: utf-8 -*- +# -*- frozen_string_literal: true -*- +# -*- warn_indent: true -*- + +module RailsBootstrapForm + module Inputs + + FIELD_HELPERS = %i[ + text_field + url_field + search_field + telephone_field + number_field + email_field + file_field + phone_field + password_field + text_area + date_field + time_field + datetime_field + datetime_local_field + month_field + week_field + ].freeze + + FIELD_HELPERS.each do |field_tag_name| + define_method(field_tag_name) do |attribute, options = {}| + field_wrapper_builder(attribute, options) do + super(attribute, options) + end + end + end + + def select(attribute, choices = nil, options = {}, html_options = {}, &block) + options = options.reverse_merge(bootstrap_form: {field_class: "form-select"}) + + field_wrapper_builder(attribute, options, html_options) do + super(attribute, choices, options, html_options, &block) + end + end + end +end diff --git a/lib/rails_bootstrap_form/version.rb b/lib/rails_bootstrap_form/version.rb index d62f941..a4b2f6b 100644 --- a/lib/rails_bootstrap_form/version.rb +++ b/lib/rails_bootstrap_form/version.rb @@ -3,6 +3,6 @@ # -*- warn_indent: true -*- module RailsBootstrapForm - VERSION = "0.2.0".freeze + VERSION = "0.2.1".freeze REQUIRED_RAILS_VERSION = "~> 7.0".freeze end diff --git a/spec/rails_bootstrap_form_spec.rb b/spec/rails_bootstrap_form_spec.rb index 0a0ac99..10e7444 100644 --- a/spec/rails_bootstrap_form_spec.rb +++ b/spec/rails_bootstrap_form_spec.rb @@ -6,7 +6,7 @@ RSpec.describe RailsBootstrapForm do it "has a valid version number" do - expect(RailsBootstrapForm::VERSION).to eq("0.2.0") + expect(RailsBootstrapForm::VERSION).to eq("0.2.1") end it "has a valid rails version number" do