diff --git a/Gemfile.lock b/Gemfile.lock index 1eb2bf2..0508822 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,6 +83,7 @@ GEM crass (1.0.6) date (3.3.3) diff-lcs (1.5.0) + docile (1.4.0) erubi (1.12.0) execjs (2.8.1) ffi (1.15.5) @@ -176,6 +177,12 @@ GEM sprockets (> 3.0) sprockets-rails tilt + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -207,6 +214,7 @@ DEPENDENCIES rake (~> 13.0) rspec-rails sassc-rails + simplecov sprockets-rails sqlite3 (~> 1.4) diff --git a/demo/app/views/users/_vertical_form.html.erb b/demo/app/views/users/_vertical_form.html.erb index aa51aae..f060233 100644 --- a/demo/app/views/users/_vertical_form.html.erb +++ b/demo/app/views/users/_vertical_form.html.erb @@ -4,7 +4,7 @@
<%= bootstrap_form_for @user, bootstrap_form: {} do |form| %> - <%= form.text_field :name, autocomplete: "new-name", bootstrap_form: {} %> + <%= form.text_field :name, autocomplete: "new-name", class: "dsds", bootstrap_form: {} %> <%= form.text_field :email, autocomplete: "new-email", bootstrap_form: {} %> <%= form.text_field :password, autocomplete: "new-password" %> <%= form.phone_field :mobile_number %> diff --git a/gemfiles/common.gemfile b/gemfiles/common.gemfile index e083c0b..e390100 100644 --- a/gemfiles/common.gemfile +++ b/gemfiles/common.gemfile @@ -18,6 +18,9 @@ gem "bootstrap", "~> 5.3.0.alpha3" # Use sqlite3 as the database for Active Record gem "sqlite3", "~> 1.4" +# Library to show coverage of the code. +gem "simplecov" + group :development do gem "puma" end diff --git a/lib/rails_bootstrap_form/bootstrap_form_options.rb b/lib/rails_bootstrap_form/bootstrap_form_options.rb index e857c6a..aa2236f 100644 --- a/lib/rails_bootstrap_form/bootstrap_form_options.rb +++ b/lib/rails_bootstrap_form/bootstrap_form_options.rb @@ -90,6 +90,14 @@ class BootstrapFormOptions # Default is `false`. attr_accessor :switch + # Controls the HTML attributes and options that will be added to the field wrapper. + # Default is `{}`. + attr_accessor :wrapper_options + + # Option to specify the size of input groups and fields. + # The valid values are `sm` and `lg`. The default value is `nil`. + attr_accessor :size + def initialize(options = {}) set_defaults set_bootstrap_form_options(options) @@ -107,10 +115,6 @@ def vertical? @layout.to_s == "vertical" end - def floating? - @layout.to_s == "floating" - end - # This will return a copy of `BootstrapFormOptions` object with new options set # that don't affect original object. This way we can have options specific # to a given form field. For example, we can change grid just for one field: @@ -152,6 +156,10 @@ def set_defaults @static_field_class = "form-control-plaintext" @switch = false + + @wrapper_options = {} + + @size = nil end private :set_defaults diff --git a/lib/rails_bootstrap_form/components/check_box.rb b/lib/rails_bootstrap_form/components/check_box.rb index 27b8675..bf4d2b5 100644 --- a/lib/rails_bootstrap_form/components/check_box.rb +++ b/lib/rails_bootstrap_form/components/check_box.rb @@ -27,6 +27,12 @@ def check_box_label(attribute, checked_value, options, bootstrap_options, &block end end + def check_box_wrapper_options(bootstrap_options) + {}.tap do |option| + option[:class] = check_box_wrapper_class(bootstrap_options) + end.merge(bootstrap_options.wrapper_options) + end + def check_box_label_text(attribute, options, bootstrap_options, &block) block ? capture(&block) : label_text(attribute, bootstrap_options) end @@ -55,7 +61,7 @@ def check_box_label_class(attribute, bootstrap_options, options) def check_box_wrapper_class(bootstrap_options) classes = Array("form-check") classes << "form-switch" if bootstrap_options.switch - classes << "form-check-inline" if bootstrap_options.inline? + classes << (bootstrap_options.inline? ? "form-check-inline" : "mb-3") classes.flatten.compact end diff --git a/lib/rails_bootstrap_form/components/labels.rb b/lib/rails_bootstrap_form/components/labels.rb index 5a6bfa5..e031fac 100644 --- a/lib/rails_bootstrap_form/components/labels.rb +++ b/lib/rails_bootstrap_form/components/labels.rb @@ -8,12 +8,15 @@ module Labels extend ActiveSupport::Concern def self.included(base_class) - def draw_label(attribute, bootstrap_options) + def draw_label(attribute, options, bootstrap_options) unless bootstrap_options.skip_label - label_class = label_classes(attribute, bootstrap_options) + label_options = { + class: label_classes(attribute, bootstrap_options) + } + label_options[:for] = options[:id] if options[:id].present? label_text = label_text(attribute, bootstrap_options) - label(attribute, label_text, class: label_class) + label(attribute, label_text, label_options) end end diff --git a/lib/rails_bootstrap_form/components/radio_button.rb b/lib/rails_bootstrap_form/components/radio_button.rb index 6882b03..43e77a0 100644 --- a/lib/rails_bootstrap_form/components/radio_button.rb +++ b/lib/rails_bootstrap_form/components/radio_button.rb @@ -28,6 +28,12 @@ def radio_button_label(attribute, value, options, bootstrap_options) end end + def radio_button_wrapper_options(bootstrap_options) + {}.tap do |option| + option[:class] = radio_button_wrapper_class(bootstrap_options) + end.merge(bootstrap_options.wrapper_options) + end + def radio_button_value(attribute, value) # label's `for` attribute needs to match checkbox tag's id, # IE sanitized value, IE @@ -51,7 +57,7 @@ def radio_button_label_class(attribute, bootstrap_options, options) def radio_button_wrapper_class(bootstrap_options) classes = Array("form-check") - classes << "form-check-inline" if bootstrap_options.inline? + classes << (bootstrap_options.inline? ? "form-check-inline" : "mb-3") classes.flatten.compact end diff --git a/lib/rails_bootstrap_form/field_wrapper_builder.rb b/lib/rails_bootstrap_form/field_wrapper_builder.rb index 795e290..ab9b37f 100644 --- a/lib/rails_bootstrap_form/field_wrapper_builder.rb +++ b/lib/rails_bootstrap_form/field_wrapper_builder.rb @@ -13,11 +13,11 @@ def field_wrapper_builder(attribute, options, html_options = nil, &block) end def field_wrapper(attribute, bootstrap_options, options, &block) - label = draw_label(attribute, bootstrap_options) + label = draw_label(attribute, options, bootstrap_options) help_text = help_text(attribute, bootstrap_options) if bootstrap_options.floating - tag.div(class: field_wrapper_classes) do + tag.div(**field_wrapper_options(bootstrap_options)) do concat(input_group_wrapper(attribute, bootstrap_options) do tag.div(class: floating_label_classes(attribute)) do concat(capture(&block)) @@ -27,7 +27,7 @@ def field_wrapper(attribute, bootstrap_options, options, &block) concat(help_text) end else - tag.div(class: field_wrapper_classes) do + tag.div(**field_wrapper_options(bootstrap_options)) do concat(label) concat(input_group_wrapper(attribute, bootstrap_options) do capture(&block) @@ -37,14 +37,17 @@ def field_wrapper(attribute, bootstrap_options, options, &block) end end + def field_wrapper_options(bootstrap_options) + {}.tap do |option| + option[:class] = field_wrapper_classes + end.merge(bootstrap_options.wrapper_options) + 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 @@ -52,14 +55,17 @@ def form_wrapper_default_class def field_css_options(attribute, bootstrap_options, options, html_options) css_options = (html_options || options) - field_classes = [ + field_classes = Array(options[:class]) + field_classes << [ bootstrap_options.field_class, bootstrap_options.additional_field_class ] field_classes << "is-invalid" if is_invalid?(attribute) + if is_size_valid?(bootstrap_options) + field_classes << "#{bootstrap_options.field_class}-#{bootstrap_options.size}" + end css_options[:class] = field_classes.flatten.compact - css_options.merge!(required_field_options(attribute, options)) if bootstrap_options.floating diff --git a/lib/rails_bootstrap_form/input_group_builder.rb b/lib/rails_bootstrap_form/input_group_builder.rb index b9be842..2289f61 100644 --- a/lib/rails_bootstrap_form/input_group_builder.rb +++ b/lib/rails_bootstrap_form/input_group_builder.rb @@ -26,7 +26,10 @@ def input_group_wrapper(attribute, bootstrap_options, &block) end def input_group_classes(attribute, bootstrap_options) - classes = ["input-group", bootstrap_options.additional_input_group_class] + classes = Array("input-group") << bootstrap_options.additional_input_group_class + if is_size_valid?(bootstrap_options) + classes << "input-group-#{bootstrap_options.size}" + end # Require `has-validation` class if field has errors. classes << "has-validation" if is_invalid?(attribute) classes.flatten.compact diff --git a/lib/rails_bootstrap_form/inputs.rb b/lib/rails_bootstrap_form/inputs.rb index 931e636..a030a94 100644 --- a/lib/rails_bootstrap_form/inputs.rb +++ b/lib/rails_bootstrap_form/inputs.rb @@ -45,7 +45,7 @@ module Inputs end DATE_SELECT_HELPERS.each do |field_tag_name| - define_method(field_tag_name) do |attribute, options = {}, html_options = {}, &block| + define_method(field_tag_name) do |attribute, options = {}, html_options = {}| options = {bootstrap_form: {field_class: "form-select"}}.deep_merge!(options) field_wrapper_builder(attribute, options, html_options) do @@ -137,7 +137,7 @@ def check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0 check_box_label = check_box_label(attribute, checked_value, options, bootstrap_options, &block) - check_box_html = tag.div(class: check_box_wrapper_class(bootstrap_options)) do + check_box_html = tag.div(**check_box_wrapper_options(bootstrap_options)) do concat(check_box_field) concat(check_box_label) concat(check_box_help_text) unless bootstrap_options.inline? @@ -157,7 +157,7 @@ def radio_button(attribute, value, options = {}) radio_button_label = radio_button_label(attribute, value, options, bootstrap_options) - radio_button_html = tag.div(class: radio_button_wrapper_class(bootstrap_options)) do + radio_button_html = tag.div(**radio_button_wrapper_options(bootstrap_options)) do concat(radio_button_field) concat(radio_button_label) concat(radio_button_help_text) unless bootstrap_options.inline? diff --git a/lib/rails_bootstrap_form/inputs/base.rb b/lib/rails_bootstrap_form/inputs/base.rb index 5bb314e..4b27014 100644 --- a/lib/rails_bootstrap_form/inputs/base.rb +++ b/lib/rails_bootstrap_form/inputs/base.rb @@ -17,7 +17,11 @@ def control_specific_class(field_tag_name) "rails-bootstrap-forms-#{field_tag_name.to_s.tr("_", "-")}" end - private :collection_input_checked?, :control_specific_class + def is_size_valid?(bootstrap_options) + bootstrap_options.size && %i(sm lg).include?(bootstrap_options.size) + end + + private :collection_input_checked?, :control_specific_class, :is_size_valid? end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 618fbcc..9522ded 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,6 +5,7 @@ ENV["RAILS_ENV"] ||= "test" require_relative "../demo/config/environment" +require "simplecov" def spec_root Pathname.new(File.expand_path(__dir__)) @@ -14,6 +15,13 @@ def test_directory_path spec_root / "test" end +SimpleCov.start "rails" do + add_filter "spec/" + add_filter ".github/" + add_filter "lib/generators/templates/" + add_filter "lib/rails_bootstrap_form/version" +end + RSpec.configure do |config| config.color = true config.formatter = :documentation