From 42d2c5a03234c104b0d7aca5753cc3214e7b771f Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sat, 3 Feb 2018 12:12:15 -0800 Subject: [PATCH 01/31] Test case for #417. --- test/bootstrap_form_group_test.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/bootstrap_form_group_test.rb b/test/bootstrap_form_group_test.rb index fd4e171cb..d96dda8ed 100644 --- a/test/bootstrap_form_group_test.rb +++ b/test/bootstrap_form_group_test.rb @@ -147,6 +147,32 @@ class BootstrapFormGroupTest < ActionView::TestCase assert_equivalent_xml expected, @builder.text_field(:email, prepend: '$', append: '.00') end + test "adding both prepend and append text with validation error" do + @user.email = nil + assert @user.invalid? + + expected = <<-HTML.strip_heredoc +
+ +
+ +
+
+ $
+
+ +
+ .00 +
+
can't be blank, is too short (minimum is 5 characters) +
+
+
+ HTML + # TODO: We should build the @builder properly from `bootstrap_form_for`, so it's easier to test errors. + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.text_field :email, prepend: '$', append: '.00' } + end + test "help messages for default forms" do expected = <<-HTML.strip_heredoc
From d7ef709e2cd8f651bfc1764e7a30996a91f551e5 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sat, 3 Feb 2018 12:45:03 -0800 Subject: [PATCH 02/31] Undoing mess created on wrong branch. --- lib/bootstrap_form/form_builder.rb | 4 ++-- lib/bootstrap_form/helpers/bootstrap.rb | 12 +++++++++- test/bootstrap_checkbox_test.rb | 32 ++++++++++++++++++++++++- test/bootstrap_radio_button_test.rb | 10 ++++---- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 16d6c9639..69cb5bb65 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -38,7 +38,7 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}| form_group_builder(name, options) do - prepend_and_append_input(options) do + prepend_and_append_input(name, options) do send(without_method_name, name, options) end end @@ -71,7 +71,7 @@ def file_field_with_bootstrap(name, options = {}) def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block) form_group_builder(method, options, html_options) do - prepend_and_append_input(options) do + prepend_and_append_input(method, options) do select_without_bootstrap(method, choices, options, html_options, &block) end end diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index 342bb0abc..4ff7862f7 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -66,7 +66,15 @@ def custom_control(*args, &block) form_group_builder(name, options, &block) end - def prepend_and_append_input(options, &block) + ## + # Add prepend and append, if any, and error if any. + # If anything is added, the whole thing is wrapped in an input-group. + def prepend_and_append_and_error_input(name, options, &block) + puts "options[:help]: #{options[:help]}" + prepend_and_append_input(name, options, error_text: generate_help(name, options[:help]).to_s, &block) + end + + def prepend_and_append_input(name, options, error_text: nil, &block) options = options.extract!(:prepend, :append, :input_group_class) input_group_class = ["input-group", options[:input_group_class]].compact.join(' ') @@ -74,6 +82,8 @@ def prepend_and_append_input(options, &block) input = content_tag(:div, input_group_content(options[:prepend]), class: 'input-group-prepend') + input if options[:prepend] input << content_tag(:div, input_group_content(options[:append]), class: 'input-group-append') if options[:append] + input << error_text + # FIXME: TBC The following isn't right yet. Wrap if there were errors. Maybe??? input = content_tag(:div, input, class: input_group_class) unless options.empty? input end diff --git a/test/bootstrap_checkbox_test.rb b/test/bootstrap_checkbox_test.rb index 048621d36..87d0702dc 100644 --- a/test/bootstrap_checkbox_test.rb +++ b/test/bootstrap_checkbox_test.rb @@ -144,8 +144,8 @@ class BootstrapCheckboxTest < ActionView::TestCase
+ With a help!
- With a help!
HTML @@ -451,4 +451,34 @@ class BootstrapCheckboxTest < ActionView::TestCase HTML assert_equivalent_xml expected, @builder.check_box(:terms, {label: 'I agree to the terms', inline: true, disabled: true, custom: true}) end + + test 'collection_check_boxes renders error after last check box' do + collection = [Address.new(id: 1, street: 'Foo'), Address.new(id: 2, street: 'Bar')] + @user.errors.add(:misc, "a box must be checked") + + expected = <<-HTML.strip_heredoc +
+ + +
+ +
+ + +
+
+ + +
a box must be checked
+
+
+
+ HTML + + actual = bootstrap_form_for(@user) do |f| + f.collection_check_boxes(:misc, collection, :id, :street) + end + + assert_equivalent_xml expected, actual + end end diff --git a/test/bootstrap_radio_button_test.rb b/test/bootstrap_radio_button_test.rb index 229526e72..3808dd858 100644 --- a/test/bootstrap_radio_button_test.rb +++ b/test/bootstrap_radio_button_test.rb @@ -99,8 +99,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase + With a help! - With a help! HTML @@ -172,8 +172,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -188,8 +188,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -242,8 +242,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -258,8 +258,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML From 187aa6939ea04a259caf11a68a85b8689d083a0b Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sat, 3 Feb 2018 16:08:11 -0800 Subject: [PATCH 03/31] Remove test that accidentally leaked in from another branch. --- test/bootstrap_checkbox_test.rb | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/test/bootstrap_checkbox_test.rb b/test/bootstrap_checkbox_test.rb index 87d0702dc..9d159108f 100644 --- a/test/bootstrap_checkbox_test.rb +++ b/test/bootstrap_checkbox_test.rb @@ -451,34 +451,4 @@ class BootstrapCheckboxTest < ActionView::TestCase HTML assert_equivalent_xml expected, @builder.check_box(:terms, {label: 'I agree to the terms', inline: true, disabled: true, custom: true}) end - - test 'collection_check_boxes renders error after last check box' do - collection = [Address.new(id: 1, street: 'Foo'), Address.new(id: 2, street: 'Bar')] - @user.errors.add(:misc, "a box must be checked") - - expected = <<-HTML.strip_heredoc -
- - -
- -
- - -
-
- - -
a box must be checked
-
-
-
- HTML - - actual = bootstrap_form_for(@user) do |f| - f.collection_check_boxes(:misc, collection, :id, :street) - end - - assert_equivalent_xml expected, actual - end end From b25ab775dccd47c028c2a4c9b45db83814a1b745 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sat, 3 Feb 2018 16:14:05 -0800 Subject: [PATCH 04/31] Working but needs cleanup #417. --- lib/bootstrap_form/form_builder.rb | 19 ++++++++----- lib/bootstrap_form/helpers/bootstrap.rb | 6 +++-- test/bootstrap_form_group_test.rb | 36 ++++++++++++++----------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 69cb5bb65..7930a945e 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -38,7 +38,7 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}| form_group_builder(name, options) do - prepend_and_append_input(name, options) do + prepend_and_append_and_error_input(name, options) do send(without_method_name, name, options) end end @@ -71,7 +71,7 @@ def file_field_with_bootstrap(name, options = {}) def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block) form_group_builder(method, options, html_options) do - prepend_and_append_input(method, options) do + prepend_and_append_and_error_input(method, options) do select_without_bootstrap(method, choices, options, html_options, &block) end end @@ -128,12 +128,15 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ end label_class = options[:label_class] + error_text = generate_help(name, options.delete(:help)).to_s if options[:custom] div_class = ["custom-control", "custom-checkbox"] div_class.append("custom-control-inline") if options[:inline] content_tag(:div, class: div_class.compact.join(" ")) do - checkbox_html.concat(label(label_name, label_description, class: ["custom-control-label", label_class].compact.join(" "))) + checkbox_html + .concat(label(label_name, label_description, class: ["custom-control-label", label_class].compact.join(" "))) + .concat(error_text) end else wrapper_class = "form-check" @@ -143,6 +146,7 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ .concat(label(label_name, label_description, { class: ["form-check-label", label_class].compact.join(" ") }.merge(options[:id].present? ? { for: options[:id] } : {}))) + .concat(error_text) end end end @@ -162,12 +166,15 @@ def radio_button_with_bootstrap(name, value, *args) disabled_class = " disabled" if options[:disabled] label_class = options[:label_class] + error_text = generate_help(name, options.delete(:help)).to_s if options[:custom] div_class = ["custom-control", "custom-radio"] div_class.append("custom-control-inline") if options[:inline] content_tag(:div, class: div_class.compact.join(" ")) do - radio_html.concat(label(name, options[:label], value: value, class: ["custom-control-label", label_class].compact.join(" "))) + radio_html + .concat(label(name, options[:label], value: value, class: ["custom-control-label", label_class].compact.join(" "))) + .concat(error_text) end else wrapper_class = "form-check" @@ -176,6 +183,7 @@ def radio_button_with_bootstrap(name, value, *args) content_tag(:div, class: "#{wrapper_class}#{disabled_class}") do radio_html .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) + .concat(error_text) end end end @@ -211,7 +219,6 @@ def form_group(*args, &block) content_tag(:div, options.except(:id, :label, :help, :icon, :label_col, :control_col, :layout)) do label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label] control = capture(&block).to_s - control.concat(generate_help(name, options[:help]).to_s) if get_group_layout(options[:layout]) == :horizontal control_class = options[:control_col] || control_col @@ -324,7 +331,7 @@ def form_group_builder(method, options, html_options = nil) wrapper_class = css_options.delete(:wrapper_class) wrapper_options = css_options.delete(:wrapper) - help = options.delete(:help) + help = options[:help] icon = options.delete(:icon) label_col = options.delete(:label_col) control_col = options.delete(:control_col) diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index 4ff7862f7..0385439fc 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -69,9 +69,11 @@ def custom_control(*args, &block) ## # Add prepend and append, if any, and error if any. # If anything is added, the whole thing is wrapped in an input-group. + # FIXME: I think this has to be the other way around, i.e. we need to be + # able to render fields with error or help, but only sometimes with + # prepend and append. def prepend_and_append_and_error_input(name, options, &block) - puts "options[:help]: #{options[:help]}" - prepend_and_append_input(name, options, error_text: generate_help(name, options[:help]).to_s, &block) + prepend_and_append_input(name, options, error_text: generate_help(name, options.delete(:help)).to_s, &block) end def prepend_and_append_input(name, options, error_text: nil, &block) diff --git a/test/bootstrap_form_group_test.rb b/test/bootstrap_form_group_test.rb index d96dda8ed..346bc8347 100644 --- a/test/bootstrap_form_group_test.rb +++ b/test/bootstrap_form_group_test.rb @@ -329,22 +329,26 @@ class BootstrapFormGroupTest < ActionView::TestCase assert_equivalent_xml expected, output end - test 'form_group renders the "error" class and message corrrectly when object is invalid' do - @user.email = nil - assert @user.invalid? - - output = @builder.form_group :email do - %{

Bar

}.html_safe - end - - expected = <<-HTML.strip_heredoc -
-

Bar

-
can't be blank, is too short (minimum is 5 characters)
-
- HTML - assert_equivalent_xml expected, output - end + # test 'form_group renders the "error" class and message corrrectly when object is invalid' do + # # It could be said that the meaning of "form-group" has changed in Bootstrap 4, + # # and that's why it shouldn't be outputting the error message anymore. Which + # # would make this test case no longer valid. + # # THIS TEST WAS REMOVED FROM v2.7. + # @user.email = nil + # assert @user.invalid? + # + # output = @builder.form_group :email do + # %{

Bar

}.html_safe + # end + # + # expected = <<-HTML.strip_heredoc + #
+ #

Bar

+ #
can't be blank, is too short (minimum is 5 characters)
+ #
+ # HTML + # assert_equivalent_xml expected, output + # end test "adds class to wrapped form_group by a field" do expected = <<-HTML.strip_heredoc From 463486e7b2a495e80781124add377a2f5d942cc5 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sat, 3 Feb 2018 16:53:17 -0800 Subject: [PATCH 05/31] Partially cleaned up. Added method for error and help and optionally prepend and append. --- lib/bootstrap_form/helpers/bootstrap.rb | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index 0385439fc..e0134c987 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -77,16 +77,28 @@ def prepend_and_append_and_error_input(name, options, &block) end def prepend_and_append_input(name, options, error_text: nil, &block) - options = options.extract!(:prepend, :append, :input_group_class) + control_error_help(name, + options, + prepend: options.delete(:prepend), + append: options.delete(:append), + error_text: error_text, + &block) + end + + ## + # Render a block, and add its error or help. + # Add prepend and append if provided. + def control_error_help(name, options, prepend: nil, append: nil, error_text: nil, &block) + options = options.extract!(:input_group_class) input_group_class = ["input-group", options[:input_group_class]].compact.join(' ') input = capture(&block) - input = content_tag(:div, input_group_content(options[:prepend]), class: 'input-group-prepend') + input if options[:prepend] - input << content_tag(:div, input_group_content(options[:append]), class: 'input-group-append') if options[:append] + input = content_tag(:div, input_group_content(prepend), class: 'input-group-prepend') + input if prepend + input << content_tag(:div, input_group_content(append), class: 'input-group-append') if append input << error_text # FIXME: TBC The following isn't right yet. Wrap if there were errors. Maybe??? - input = content_tag(:div, input, class: input_group_class) unless options.empty? + input = content_tag(:div, input, class: input_group_class) unless options.empty? && prepend.nil? && append.nil? input end From 9e667061958cd373be47b10d66eae80df4370ea4 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sat, 3 Feb 2018 16:58:37 -0800 Subject: [PATCH 06/31] Remove unneeded method and parameters. --- lib/bootstrap_form/form_builder.rb | 4 ++-- lib/bootstrap_form/helpers/bootstrap.rb | 16 +++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 7930a945e..54f0e0c8b 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -38,7 +38,7 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}| form_group_builder(name, options) do - prepend_and_append_and_error_input(name, options) do + prepend_and_append_input(name, options) do send(without_method_name, name, options) end end @@ -71,7 +71,7 @@ def file_field_with_bootstrap(name, options = {}) def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block) form_group_builder(method, options, html_options) do - prepend_and_append_and_error_input(method, options) do + prepend_and_append_input(method, options) do select_without_bootstrap(method, choices, options, html_options, &block) end end diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index e0134c987..3e12a5925 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -69,26 +69,20 @@ def custom_control(*args, &block) ## # Add prepend and append, if any, and error if any. # If anything is added, the whole thing is wrapped in an input-group. - # FIXME: I think this has to be the other way around, i.e. we need to be - # able to render fields with error or help, but only sometimes with - # prepend and append. - def prepend_and_append_and_error_input(name, options, &block) - prepend_and_append_input(name, options, error_text: generate_help(name, options.delete(:help)).to_s, &block) - end - - def prepend_and_append_input(name, options, error_text: nil, &block) + def prepend_and_append_input(name, options, &block) control_error_help(name, options, prepend: options.delete(:prepend), append: options.delete(:append), - error_text: error_text, &block) end ## # Render a block, and add its error or help. - # Add prepend and append if provided. - def control_error_help(name, options, prepend: nil, append: nil, error_text: nil, &block) + # Add prepend and append if provided, and wrap if they were, or if + # an input_group_class was provided. + def control_error_help(name, options, prepend: nil, append: nil, &block) + error_text = generate_help(name, options.delete(:help)).to_s options = options.extract!(:input_group_class) input_group_class = ["input-group", options[:input_group_class]].compact.join(' ') From e83bf64b9f1ea00e6cb8d8aa7858a140729a5e24 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 4 Feb 2018 16:27:28 -0800 Subject: [PATCH 07/31] Test selects error. --- test/bootstrap_selects_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index 216119e21..cd6832c20 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -24,6 +24,21 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) assert_equivalent_xml expected, @builder.time_zone_select(:misc) end + test "time zone selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + expected = <<-HTML.strip_heredoc +
+ +
+ + +
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.time_zone_select(:misc) } + end + test "selects are wrapped correctly" do expected = <<-HTML.strip_heredoc
From a2b45868d81ce422b06da5d991cbe3362458c5ae Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 4 Feb 2018 16:27:28 -0800 Subject: [PATCH 08/31] Test selects error. --- test/bootstrap_selects_test.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index 216119e21..cd6832c20 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -24,6 +24,21 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) assert_equivalent_xml expected, @builder.time_zone_select(:misc) end + test "time zone selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + expected = <<-HTML.strip_heredoc +
+ +
+ + +
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.time_zone_select(:misc) } + end + test "selects are wrapped correctly" do expected = <<-HTML.strip_heredoc
From e48451d2cf461c6d306f8304baaaad56461d1817 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 4 Feb 2018 16:35:28 -0800 Subject: [PATCH 09/31] time_zone_select works for new error placement. --- lib/bootstrap_form/form_builder.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 54f0e0c8b..c5c65c8b2 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -97,7 +97,9 @@ def grouped_collection_select_with_bootstrap(method, collection, group_method, g def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {}, html_options = {}) form_group_builder(method, options, html_options) do - time_zone_select_without_bootstrap(method, priority_zones, options, html_options) + control_error_help(method, options) do + time_zone_select_without_bootstrap(method, priority_zones, options, html_options) + end end end From b2d832a9d6347c4f773899f803f6b7db8a3e35f9 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 4 Feb 2018 16:46:51 -0800 Subject: [PATCH 10/31] Add tests for date, time, datetime selects. --- test/bootstrap_selects_test.rb | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index cd6832c20..9c95defdb 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -245,6 +245,33 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) end end + test "date selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + Timecop.freeze(Time.utc(2012, 2, 3)) do + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + + +
+
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.date_select(:misc) } + end + end + test "date selects with options are wrapped correctly" do Timecop.freeze(Time.utc(2012, 2, 3)) do expected = <<-HTML.strip_heredoc @@ -319,6 +346,34 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) end end + test "time selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + + + + : + +
+
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.time_select(:misc) } + end + end + test "time selects with options are wrapped correctly" do Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do expected = <<-HTML.strip_heredoc @@ -399,6 +454,41 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) end end + test "datetime selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + + + — + + : + +
+
error for test
+
+
+ HTML + assert_equivalent_xml expected, @builder.datetime_select(:misc) + end + end + test "datetime selects with options are wrapped correctly" do Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do expected = <<-HTML.strip_heredoc From 073a1e3862aa3cdd0a1da2926ea108365b71a357 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 4 Feb 2018 16:46:51 -0800 Subject: [PATCH 11/31] Add tests for date, time, datetime selects. --- test/bootstrap_selects_test.rb | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index cd6832c20..9c95defdb 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -245,6 +245,33 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) end end + test "date selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + Timecop.freeze(Time.utc(2012, 2, 3)) do + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + + +
+
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.date_select(:misc) } + end + end + test "date selects with options are wrapped correctly" do Timecop.freeze(Time.utc(2012, 2, 3)) do expected = <<-HTML.strip_heredoc @@ -319,6 +346,34 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) end end + test "time selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + + + + : + +
+
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.time_select(:misc) } + end + end + test "time selects with options are wrapped correctly" do Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do expected = <<-HTML.strip_heredoc @@ -399,6 +454,41 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) end end + test "datetime selects are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + + + — + + : + +
+
error for test
+
+
+ HTML + assert_equivalent_xml expected, @builder.datetime_select(:misc) + end + end + test "datetime selects with options are wrapped correctly" do Timecop.freeze(Time.utc(2012, 2, 3, 12, 0, 0)) do expected = <<-HTML.strip_heredoc From 844e1335a2eb206dcbc8bd1971ccbffee426d5d9 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 4 Feb 2018 16:52:09 -0800 Subject: [PATCH 12/31] date, time, datetime tests pass with old implementation. --- test/bootstrap_selects_test.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index 9c95defdb..a746ad24a 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -253,14 +253,14 @@ def options_range(start: 1, stop: 31, selected: nil, months: false)
-
- #{options_range(start: 2007, stop: 2017, selected: 2012)} - #{options_range(start: 1, stop: 12, selected: 2, months: true)} - #{options_range(start: 1, stop: 31, selected: 3)}
@@ -354,15 +354,15 @@ def options_range(start: 1, stop: 31, selected: nil, months: false)
-
+
- #{options_range(start: "00", stop: "23", selected: "12")} : - #{options_range(start: "00", stop: "59", selected: "00")}
@@ -462,22 +462,22 @@ def options_range(start: 1, stop: 31, selected: nil, months: false)
-
- #{options_range(start: 2007, stop: 2017, selected: 2012)} - #{options_range(start: 1, stop: 12, selected: 2, months: true)} - #{options_range(start: 1, stop: 31, selected: 3)} — - #{options_range(start: "00", stop: "23", selected: "12")} : - #{options_range(start: "00", stop: "59", selected: "00")}
@@ -485,7 +485,7 @@ def options_range(start: 1, stop: 31, selected: nil, months: false)
HTML - assert_equivalent_xml expected, @builder.datetime_select(:misc) + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.datetime_select(:misc) } end end From 0a73344c00b89c28e2c33653ed7f77917e95abdc Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 5 Feb 2018 08:01:14 -0800 Subject: [PATCH 13/31] Date, time, and datetime for new implementation. --- lib/bootstrap_form/form_builder.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index c5c65c8b2..46183aea3 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -53,7 +53,9 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}, html_options = {}| form_group_builder(name, options, html_options) do - content_tag(:div, send(without_method_name, name, options, html_options), class: control_specific_class(method_name)) + control_error_help(name, options) do + content_tag(:div, send(without_method_name, name, options, html_options), class: control_specific_class(method_name)) + end end end From 365dbf21e718cae9d7b3892e78124f583d19ce9c Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 5 Feb 2018 08:33:03 -0800 Subject: [PATCH 14/31] Tests for file and collection selects. --- test/bootstrap_fields_test.rb | 15 +++++++++++++++ test/bootstrap_selects_test.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/test/bootstrap_fields_test.rb b/test/bootstrap_fields_test.rb index 60c61fff7..98f13801b 100644 --- a/test/bootstrap_fields_test.rb +++ b/test/bootstrap_fields_test.rb @@ -65,6 +65,21 @@ class BootstrapFieldsTest < ActionView::TestCase assert_equivalent_xml expected, @builder.file_field(:misc) end + test "file fields are wrapped correctly with error" do + @user.errors.add(:misc, "error for test") + expected = <<-HTML.strip_heredoc +
+ +
+ + +
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.file_field(:misc) } + end + test "hidden fields are supported" do expected = %{} assert_equivalent_xml expected, @builder.hidden_field(:misc) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index a746ad24a..2ccfa7c8c 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -165,6 +165,21 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) assert_equivalent_xml expected, @builder.collection_select(:status, [], :id, :name) end + test "collection_selects are wrapped correctly with error" do + @user.errors.add(:status, "error for test") + expected = <<-HTML.strip_heredoc +
+ +
+ + +
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.collection_select(:status, [], :id, :name) } + end + test "collection_selects with options are wrapped correctly" do expected = <<-HTML.strip_heredoc
@@ -199,6 +214,21 @@ def options_range(start: 1, stop: 31, selected: nil, months: false) assert_equivalent_xml expected, @builder.grouped_collection_select(:status, [], :last, :first, :to_s, :to_s) end + test "grouped_collection_selects are wrapped correctly with error" do + @user.errors.add(:status, "error for test") + expected = <<-HTML.strip_heredoc +
+ +
+ + +
error for test
+
+
+ HTML + assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.grouped_collection_select(:status, [], :last, :first, :to_s, :to_s) } + end + test "grouped_collection_selects with options are wrapped correctly" do expected = <<-HTML.strip_heredoc
From a15d06d0d577af306b1d32a04012401eb28a8a52 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 5 Feb 2018 08:59:08 -0800 Subject: [PATCH 15/31] File and collection selects with new implementation. --- lib/bootstrap_form/form_builder.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 46183aea3..dfe298b3b 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -65,7 +65,9 @@ def initialize(object_name, object, template, options) def file_field_with_bootstrap(name, options = {}) options = options.reverse_merge(control_class: 'form-control-file') form_group_builder(name, options) do - file_field_without_bootstrap(name, options) + control_error_help(name, options) do + file_field_without_bootstrap(name, options) + end end end @@ -83,7 +85,9 @@ def select_with_bootstrap(method, choices = nil, options = {}, html_options = {} def collection_select_with_bootstrap(method, collection, value_method, text_method, options = {}, html_options = {}) form_group_builder(method, options, html_options) do - collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options) + control_error_help(method, options) do + collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options) + end end end @@ -91,7 +95,9 @@ def collection_select_with_bootstrap(method, collection, value_method, text_meth def grouped_collection_select_with_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) form_group_builder(method, options, html_options) do - grouped_collection_select_without_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) + control_error_help(method, options) do + grouped_collection_select_without_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) + end end end From 4d7248cd5b6a1ec7302d5d1a083f6420f534b0a9 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 18 Feb 2018 08:07:50 -0800 Subject: [PATCH 16/31] Keep tests but revert lib to try another approach. --- lib/bootstrap_form/form_builder.rb | 33 +++++++------------------ lib/bootstrap_form/helpers/bootstrap.rb | 28 ++++----------------- 2 files changed, 14 insertions(+), 47 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index b76c2f8da..bcc70c66d 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -38,7 +38,7 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}| form_group_builder(name, options) do - prepend_and_append_input(name, options) do + prepend_and_append_input(options) do send(without_method_name, name, options) end end @@ -53,9 +53,7 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}, html_options = {}| form_group_builder(name, options, html_options) do - control_error_help(name, options) do - content_tag(:div, send(without_method_name, name, options, html_options), class: control_specific_class(method_name)) - end + content_tag(:div, send(without_method_name, name, options, html_options), class: control_specific_class(method_name)) end end @@ -65,9 +63,7 @@ def initialize(object_name, object, template, options) def file_field_with_bootstrap(name, options = {}) options = options.reverse_merge(control_class: 'form-control-file') form_group_builder(name, options) do - control_error_help(name, options) do - file_field_without_bootstrap(name, options) - end + file_field_without_bootstrap(name, options) end end @@ -75,7 +71,7 @@ def file_field_with_bootstrap(name, options = {}) def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block) form_group_builder(method, options, html_options) do - prepend_and_append_input(method, options) do + prepend_and_append_input(options) do select_without_bootstrap(method, choices, options, html_options, &block) end end @@ -85,9 +81,7 @@ def select_with_bootstrap(method, choices = nil, options = {}, html_options = {} def collection_select_with_bootstrap(method, collection, value_method, text_method, options = {}, html_options = {}) form_group_builder(method, options, html_options) do - control_error_help(method, options) do - collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options) - end + collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options) end end @@ -95,9 +89,7 @@ def collection_select_with_bootstrap(method, collection, value_method, text_meth def grouped_collection_select_with_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) form_group_builder(method, options, html_options) do - control_error_help(method, options) do - grouped_collection_select_without_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) - end + grouped_collection_select_without_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) end end @@ -105,9 +97,7 @@ def grouped_collection_select_with_bootstrap(method, collection, group_method, g def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {}, html_options = {}) form_group_builder(method, options, html_options) do - control_error_help(method, options) do - time_zone_select_without_bootstrap(method, priority_zones, options, html_options) - end + time_zone_select_without_bootstrap(method, priority_zones, options, html_options) end end @@ -141,7 +131,6 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ label_classes = [options[:label_class]] label_classes << hide_class if options[:hide_label] - error_text = generate_help(name, options.delete(:help)).to_s if options[:custom] div_class = ["custom-control", "custom-checkbox"] @@ -154,7 +143,6 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ # TODO: Notice we don't seem to pass the ID into the custom control. checkbox_html.concat(label(label_name, label_description, class: label_class)) end - .concat(error_text) end else wrapper_class = "form-check" @@ -169,7 +157,6 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ label_description, { class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) end - .concat(error_text) end end end @@ -192,7 +179,6 @@ def radio_button_with_bootstrap(name, value, *args) disabled_class = " disabled" if options[:disabled] label_classes = [options[:label_class]] label_classes << hide_class if options[:hide_label] - error_text = generate_help(name, options.delete(:help)).to_s if options[:custom] div_class = ["custom-control", "custom-radio"] @@ -205,7 +191,6 @@ def radio_button_with_bootstrap(name, value, *args) # TODO: Notice we don't seem to pass the ID into the custom control. radio_html.concat(label(name, options[:label], value: value, class: label_class)) end - .concat(error_text) end else wrapper_class = "form-check" @@ -218,7 +203,6 @@ def radio_button_with_bootstrap(name, value, *args) radio_html .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) end - .concat(error_text) end end end @@ -254,6 +238,7 @@ def form_group(*args, &block) content_tag(:div, options.except(:id, :label, :help, :icon, :label_col, :control_col, :layout)) do label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label] control = capture(&block).to_s + control.concat(generate_help(name, options[:help]).to_s) if get_group_layout(options[:layout]) == :horizontal control_class = options[:control_col] || control_col @@ -366,7 +351,7 @@ def form_group_builder(method, options, html_options = nil) wrapper_class = css_options.delete(:wrapper_class) wrapper_options = css_options.delete(:wrapper) - help = options[:help] + help = options.delete(:help) icon = options.delete(:icon) label_col = options.delete(:label_col) control_col = options.delete(:control_col) diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index 030301b42..058c9dc05 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -66,33 +66,15 @@ def custom_control(*args, &block) form_group_builder(name, options, &block) end - ## - # Add prepend and append, if any, and error if any. - # If anything is added, the whole thing is wrapped in an input-group. - def prepend_and_append_input(name, options, &block) - control_error_help(name, - options, - prepend: options.delete(:prepend), - append: options.delete(:append), - &block) - end - - ## - # Render a block, and add its error or help. - # Add prepend and append if provided, and wrap if they were, or if - # an input_group_class was provided. - def control_error_help(name, options, prepend: nil, append: nil, &block) - error_text = generate_help(name, options.delete(:help)).to_s - options = options.extract!(:input_group_class) + def prepend_and_append_input(options, &block) + options = options.extract!(:prepend, :append, :input_group_class) input_group_class = ["input-group", options[:input_group_class]].compact.join(' ') input = capture(&block) - input = content_tag(:div, input_group_content(prepend), class: 'input-group-prepend') + input if prepend - input << content_tag(:div, input_group_content(append), class: 'input-group-append') if append - input << error_text - # FIXME: TBC The following isn't right yet. Wrap if there were errors. Maybe??? - input = content_tag(:div, input, class: input_group_class) unless options.empty? && prepend.nil? && append.nil? + input = content_tag(:div, input_group_content(options[:prepend]), class: 'input-group-prepend') + input if options[:prepend] + input << content_tag(:div, input_group_content(options[:append]), class: 'input-group-append') if options[:append] + input = content_tag(:div, input, class: input_group_class) unless options.empty? input end From 7c53f242310c244fbe82b15ed325c34491fef0e4 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 18 Feb 2018 12:41:02 -0800 Subject: [PATCH 17/31] form_group tests passing. --- lib/bootstrap_form/form_builder.rb | 19 +++++++++++------- lib/bootstrap_form/helpers/bootstrap.rb | 26 ++++++++++++++++--------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index bcc70c66d..9983049b4 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -38,9 +38,9 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}| form_group_builder(name, options) do - prepend_and_append_input(options) do + # prepend_and_append_input(name, options) do send(without_method_name, name, options) - end + # end end end @@ -71,9 +71,9 @@ def file_field_with_bootstrap(name, options = {}) def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block) form_group_builder(method, options, html_options) do - prepend_and_append_input(options) do + # prepend_and_append_input(method, options) do select_without_bootstrap(method, choices, options, html_options, &block) - end + # end end end @@ -235,10 +235,11 @@ def form_group(*args, &block) options[:class] << " row" if get_group_layout(options[:layout]) == :horizontal options[:class] << " #{feedback_class}" if options[:icon] - content_tag(:div, options.except(:id, :label, :help, :icon, :label_col, :control_col, :layout)) do + content_tag(:div, options.except(:append, :id, :label, :help, :icon, :input_group_class, :label_col, :control_col, :layout, :prepend)) do label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label] - control = capture(&block).to_s - control.concat(generate_help(name, options[:help]).to_s) + control = prepend_and_append_input(name, options, &block).to_s + puts "back from prepend_and_append_input control: #{control}" + # control.concat(generate_help(name, options[:help]).to_s) if get_group_layout(options[:layout]) == :horizontal control_class = options[:control_col] || control_col @@ -366,6 +367,10 @@ def form_group_builder(method, options, html_options = nil) class: wrapper_class } + form_group_options[:append] = options.delete(:append) if options[:append] + form_group_options[:prepend] = options.delete(:prepend) if options[:prepend] + form_group_options[:input_group_class] = options.delete(:input_group_class) if options[:input_group_class] + if wrapper_options.is_a?(Hash) form_group_options.merge!(wrapper_options) end diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index 058c9dc05..7436bdb94 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -66,15 +66,23 @@ def custom_control(*args, &block) form_group_builder(name, options, &block) end - def prepend_and_append_input(options, &block) - options = options.extract!(:prepend, :append, :input_group_class) - input_group_class = ["input-group", options[:input_group_class]].compact.join(' ') - - input = capture(&block) - - input = content_tag(:div, input_group_content(options[:prepend]), class: 'input-group-prepend') + input if options[:prepend] - input << content_tag(:div, input_group_content(options[:append]), class: 'input-group-append') if options[:append] - input = content_tag(:div, input, class: input_group_class) unless options.empty? + def prepend_and_append_input(name, options, &block) + local_options = options.extract!(:prepend, :append, :input_group_class) + puts "options: #{options}" + puts "local_options: #{local_options}" + input_group_class = ["input-group", local_options[:input_group_class]].compact.join(' ') + + input = capture(&block) || "".html_safe + puts "prepend_and_append_input input: #{input}" + + input = content_tag(:div, input_group_content(local_options[:prepend]), class: 'input-group-prepend') + input if local_options[:prepend] + puts "prepend_and_append_input input with prepend: #{input}" + input << content_tag(:div, input_group_content(local_options[:append]), class: 'input-group-append') if local_options[:append] + puts "prepend_and_append_input input with append: #{input}" + input << generate_help(name, options[:help]).to_s + puts "prepend_and_append_input input with help: #{input}" + input = content_tag(:div, input, class: input_group_class) unless local_options.empty? + puts "prepend_and_append_input input to be returned: #{input}" input end From 24def25ebe0e9ab818dc5ed0a11f0b0446f2de42 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 18 Feb 2018 12:48:53 -0800 Subject: [PATCH 18/31] Clean up and add back commented test. --- lib/bootstrap_form/form_builder.rb | 2 -- lib/bootstrap_form/helpers/bootstrap.rb | 7 ----- test/bootstrap_form_group_test.rb | 40 ++++++++++++------------- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 9983049b4..2351d6ea5 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -238,8 +238,6 @@ def form_group(*args, &block) content_tag(:div, options.except(:append, :id, :label, :help, :icon, :input_group_class, :label_col, :control_col, :layout, :prepend)) do label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label] control = prepend_and_append_input(name, options, &block).to_s - puts "back from prepend_and_append_input control: #{control}" - # control.concat(generate_help(name, options[:help]).to_s) if get_group_layout(options[:layout]) == :horizontal control_class = options[:control_col] || control_col diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index 7436bdb94..eb6759a90 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -68,21 +68,14 @@ def custom_control(*args, &block) def prepend_and_append_input(name, options, &block) local_options = options.extract!(:prepend, :append, :input_group_class) - puts "options: #{options}" - puts "local_options: #{local_options}" input_group_class = ["input-group", local_options[:input_group_class]].compact.join(' ') input = capture(&block) || "".html_safe - puts "prepend_and_append_input input: #{input}" input = content_tag(:div, input_group_content(local_options[:prepend]), class: 'input-group-prepend') + input if local_options[:prepend] - puts "prepend_and_append_input input with prepend: #{input}" input << content_tag(:div, input_group_content(local_options[:append]), class: 'input-group-append') if local_options[:append] - puts "prepend_and_append_input input with append: #{input}" input << generate_help(name, options[:help]).to_s - puts "prepend_and_append_input input with help: #{input}" input = content_tag(:div, input, class: input_group_class) unless local_options.empty? - puts "prepend_and_append_input input to be returned: #{input}" input end diff --git a/test/bootstrap_form_group_test.rb b/test/bootstrap_form_group_test.rb index 90a04017a..f4d8e9122 100644 --- a/test/bootstrap_form_group_test.rb +++ b/test/bootstrap_form_group_test.rb @@ -329,26 +329,26 @@ class BootstrapFormGroupTest < ActionView::TestCase assert_equivalent_xml expected, output end - # test 'form_group renders the "error" class and message corrrectly when object is invalid' do - # # It could be said that the meaning of "form-group" has changed in Bootstrap 4, - # # and that's why it shouldn't be outputting the error message anymore. Which - # # would make this test case no longer valid. - # # THIS TEST WAS REMOVED FROM v2.7. - # @user.email = nil - # assert @user.invalid? - # - # output = @builder.form_group :email do - # %{

Bar

}.html_safe - # end - # - # expected = <<-HTML.strip_heredoc - #
- #

Bar

- #
can't be blank, is too short (minimum is 5 characters)
- #
- # HTML - # assert_equivalent_xml expected, output - # end + test 'form_group renders the "error" class and message corrrectly when object is invalid' do + # It could be said that the meaning of "form-group" has changed in Bootstrap 4, + # and that's why it shouldn't be outputting the error message anymore. Which + # would make this test case no longer valid. + # THIS TEST WAS REMOVED FROM v2.7. + @user.email = nil + assert @user.invalid? + + output = @builder.form_group :email do + %{

Bar

}.html_safe + end + + expected = <<-HTML.strip_heredoc +
+

Bar

+
can't be blank, is too short (minimum is 5 characters)
+
+ HTML + assert_equivalent_xml expected, output + end test "adds class to wrapped form_group by a field" do expected = <<-HTML.strip_heredoc From f60ed6c911d2d64cc1314047f63a1053f2ca80ac Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 18 Feb 2018 12:52:07 -0800 Subject: [PATCH 19/31] checkbox and radio button tests still have old behaviour. --- test/bootstrap_checkbox_test.rb | 2 +- test/bootstrap_radio_button_test.rb | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/bootstrap_checkbox_test.rb b/test/bootstrap_checkbox_test.rb index e1d4b3cff..6798963ed 100644 --- a/test/bootstrap_checkbox_test.rb +++ b/test/bootstrap_checkbox_test.rb @@ -144,8 +144,8 @@ class BootstrapCheckboxTest < ActionView::TestCase
- With a help!
+ With a help!
HTML diff --git a/test/bootstrap_radio_button_test.rb b/test/bootstrap_radio_button_test.rb index 165691b73..8cb8a627c 100644 --- a/test/bootstrap_radio_button_test.rb +++ b/test/bootstrap_radio_button_test.rb @@ -99,8 +99,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase - With a help!
+ With a help!
HTML @@ -172,8 +172,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
- With a help!
+ With a help!
HTML @@ -188,8 +188,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
- With a help!
+ With a help!
HTML @@ -242,8 +242,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
- With a help!
+ With a help!
HTML @@ -258,8 +258,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
- With a help!
+ With a help!
HTML From c0aaf19951b01c6908a85b64db8938baf7f3a2f9 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Sun, 18 Feb 2018 21:06:17 -0800 Subject: [PATCH 20/31] Clean up and block append and prepend. --- lib/bootstrap_form/form_builder.rb | 17 +++++++++++------ lib/bootstrap_form/helpers/bootstrap.rb | 21 +++++++++++++++------ test/bootstrap_form_group_test.rb | 5 ----- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 2351d6ea5..13b791dae 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -38,9 +38,7 @@ def initialize(object_name, object, template, options) define_method(with_method_name) do |name, options = {}| form_group_builder(name, options) do - # prepend_and_append_input(name, options) do - send(without_method_name, name, options) - # end + send(without_method_name, name, options) end end @@ -52,6 +50,7 @@ def initialize(object_name, object, template, options) without_method_name = "#{method_name}_without_bootstrap" define_method(with_method_name) do |name, options = {}, html_options = {}| + prevent_prepend_and_append!(options) form_group_builder(name, options, html_options) do content_tag(:div, send(without_method_name, name, options, html_options), class: control_specific_class(method_name)) end @@ -61,6 +60,7 @@ def initialize(object_name, object, template, options) end def file_field_with_bootstrap(name, options = {}) + prevent_prepend_and_append!(options) options = options.reverse_merge(control_class: 'form-control-file') form_group_builder(name, options) do file_field_without_bootstrap(name, options) @@ -71,15 +71,14 @@ def file_field_with_bootstrap(name, options = {}) def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block) form_group_builder(method, options, html_options) do - # prepend_and_append_input(method, options) do - select_without_bootstrap(method, choices, options, html_options, &block) - # end + select_without_bootstrap(method, choices, options, html_options, &block) end end bootstrap_method_alias :select def collection_select_with_bootstrap(method, collection, value_method, text_method, options = {}, html_options = {}) + prevent_prepend_and_append!(options) form_group_builder(method, options, html_options) do collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options) end @@ -88,6 +87,7 @@ def collection_select_with_bootstrap(method, collection, value_method, text_meth bootstrap_method_alias :collection_select def grouped_collection_select_with_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) + prevent_prepend_and_append!(options) form_group_builder(method, options, html_options) do grouped_collection_select_without_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) end @@ -96,6 +96,7 @@ def grouped_collection_select_with_bootstrap(method, collection, group_method, g bootstrap_method_alias :grouped_collection_select def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {}, html_options = {}) + prevent_prepend_and_append!(options) form_group_builder(method, options, html_options) do time_zone_select_without_bootstrap(method, priority_zones, options, html_options) end @@ -104,6 +105,7 @@ def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {}, bootstrap_method_alias :time_zone_select def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_value = "0", &block) + prevent_prepend_and_append!(options) options = options.symbolize_keys! check_box_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) check_box_classes = [check_box_options[:class]] @@ -164,6 +166,7 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ bootstrap_method_alias :check_box def radio_button_with_bootstrap(name, value, *args) + prevent_prepend_and_append!(options) options = args.extract_options!.symbolize_keys! radio_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) radio_classes = [options[:class]] @@ -210,6 +213,7 @@ def radio_button_with_bootstrap(name, value, *args) bootstrap_method_alias :radio_button def collection_check_boxes_with_bootstrap(*args) + prevent_prepend_and_append!(options) html = inputs_collection(*args) do |name, value, options| options[:multiple] = true check_box(name, options, value, nil) @@ -220,6 +224,7 @@ def collection_check_boxes_with_bootstrap(*args) bootstrap_method_alias :collection_check_boxes def collection_radio_buttons_with_bootstrap(*args) + prevent_prepend_and_append!(options) inputs_collection(*args) do |name, value, options| radio_button(name, value, options) end diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index eb6759a90..f8fcd23a7 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -67,18 +67,27 @@ def custom_control(*args, &block) end def prepend_and_append_input(name, options, &block) - local_options = options.extract!(:prepend, :append, :input_group_class) - input_group_class = ["input-group", local_options[:input_group_class]].compact.join(' ') + help = options[:help] + options = options.extract!(:prepend, :append, :input_group_class) + input_group_class = ["input-group", options[:input_group_class]].compact.join(' ') input = capture(&block) || "".html_safe - input = content_tag(:div, input_group_content(local_options[:prepend]), class: 'input-group-prepend') + input if local_options[:prepend] - input << content_tag(:div, input_group_content(local_options[:append]), class: 'input-group-append') if local_options[:append] - input << generate_help(name, options[:help]).to_s - input = content_tag(:div, input, class: input_group_class) unless local_options.empty? + input = content_tag(:div, input_group_content(options[:prepend]), class: 'input-group-prepend') + input if options[:prepend] + input << content_tag(:div, input_group_content(options[:append]), class: 'input-group-append') if options[:append] + input << generate_help(name, help).to_s + input = content_tag(:div, input, class: input_group_class) unless options.empty? input end + # Some helpers don't currently accept prepend and append. However, it's not + # clear if that's corrent. In the meantime, strip to options before calling + # methods that don't accept prepend and append. + def prevent_prepend_and_append!(options) + options.delete(:append) + options.delete(:prepend) + end + def input_group_content(content) return content if content.match(/btn/) content_tag(:span, content, class: 'input-group-text') diff --git a/test/bootstrap_form_group_test.rb b/test/bootstrap_form_group_test.rb index f4d8e9122..11bfa46d0 100644 --- a/test/bootstrap_form_group_test.rb +++ b/test/bootstrap_form_group_test.rb @@ -169,7 +169,6 @@ class BootstrapFormGroupTest < ActionView::TestCase HTML - # TODO: We should build the @builder properly from `bootstrap_form_for`, so it's easier to test errors. assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| f.text_field :email, prepend: '$', append: '.00' } end @@ -330,10 +329,6 @@ class BootstrapFormGroupTest < ActionView::TestCase end test 'form_group renders the "error" class and message corrrectly when object is invalid' do - # It could be said that the meaning of "form-group" has changed in Bootstrap 4, - # and that's why it shouldn't be outputting the error message anymore. Which - # would make this test case no longer valid. - # THIS TEST WAS REMOVED FROM v2.7. @user.email = nil assert @user.invalid? From ab7532ab32bd23f4ce03f4ec95e9fc1fbdfed0ab Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 09:27:01 -0800 Subject: [PATCH 21/31] Tests for #418. --- test/bootstrap_checkbox_test.rb | 30 ++++++++++++++++++++++- test/bootstrap_radio_button_test.rb | 37 +++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/test/bootstrap_checkbox_test.rb b/test/bootstrap_checkbox_test.rb index 6798963ed..58d2d847b 100644 --- a/test/bootstrap_checkbox_test.rb +++ b/test/bootstrap_checkbox_test.rb @@ -144,8 +144,8 @@ class BootstrapCheckboxTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -493,4 +493,32 @@ class BootstrapCheckboxTest < ActionView::TestCase HTML assert_equivalent_xml expected, @builder.check_box(:terms, {label: 'I agree to the terms', custom: true, hide_label: true}) end + + test 'collection_check_boxes renders multiple check boxes with error correctly' do + @user.errors.add(:misc, "error for test") + collection = [Address.new(id: 1, street: 'Foo'), Address.new(id: 2, street: 'Bar')] + expected = <<-HTML.strip_heredoc +
+ + +
+ +
+ + +
+
+ + +
error for test
+
+
+
+ HTML + + actual = bootstrap_form_for(@user) do |f| + f.collection_check_boxes(:misc, collection, :id, :street, checked: collection) + end + assert_equivalent_xml expected, actual + end end diff --git a/test/bootstrap_radio_button_test.rb b/test/bootstrap_radio_button_test.rb index 8cb8a627c..f90349d2d 100644 --- a/test/bootstrap_radio_button_test.rb +++ b/test/bootstrap_radio_button_test.rb @@ -99,8 +99,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase + With a help! - With a help! HTML @@ -126,6 +126,33 @@ class BootstrapRadioButtonTest < ActionView::TestCase assert_equivalent_xml expected, @builder.collection_radio_buttons(:misc, collection, :id, :street) end + test 'collection_radio_buttons renders multiple radios with error correctly' do + @user.errors.add(:misc, "error for test") + collection = [Address.new(id: 1, street: 'Foo'), Address.new(id: 2, street: 'Bar')] + expected = <<-HTML.strip_heredoc +
+ +
+ +
+ + +
+
+ + +
error for test
+
+
+
+ HTML + + actual = bootstrap_form_for(@user) do |f| + f.collection_radio_buttons(:misc, collection, :id, :street) + end + assert_equivalent_xml expected, actual + end + test 'collection_radio_buttons renders inline radios correctly' do collection = [Address.new(id: 1, street: 'Foo'), Address.new(id: 2, street: 'Bar')] expected = <<-HTML.strip_heredoc @@ -172,8 +199,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -188,8 +215,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -242,8 +269,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML @@ -258,8 +285,8 @@ class BootstrapRadioButtonTest < ActionView::TestCase
+ With a help!
- With a help! HTML From bc435b473e7ff5563f0befca6758ad9b7bc276c4 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 11:03:37 -0800 Subject: [PATCH 22/31] Extract method wrapped_radio from radio_button. --- lib/bootstrap_form/form_builder.rb | 54 +++++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 13b791dae..3a4ceee16 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -179,33 +179,20 @@ def radio_button_with_bootstrap(name, value, *args) args << radio_options radio_html = radio_button_without_bootstrap(name, value, *args) - disabled_class = " disabled" if options[:disabled] label_classes = [options[:label_class]] label_classes << hide_class if options[:hide_label] - if options[:custom] - div_class = ["custom-control", "custom-radio"] - div_class.append("custom-control-inline") if options[:inline] - label_class = label_classes.prepend("custom-control-label").compact.join(" ") - content_tag(:div, class: div_class.compact.join(" ")) do - if options[:skip_label] - radio_html - else - # TODO: Notice we don't seem to pass the ID into the custom control. - radio_html.concat(label(name, options[:label], value: value, class: label_class)) - end - end - else - wrapper_class = "form-check" - wrapper_class += " form-check-inline" if options[:inline] - label_class = label_classes.prepend("form-check-label").compact.join(" ") - content_tag(:div, class: "#{wrapper_class}#{disabled_class}") do - if options[:skip_label] - radio_html - else - radio_html - .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) - end + wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + if options[:skip_label] + radio_html + elsif options[:custom] + label_class = label_classes.prepend("custom-control-label").compact.join(" ") + # TODO: Notice we don't seem to pass the ID into the custom control. + radio_html.concat(label(name, options[:label], value: value, class: label_class)) + else + label_class = label_classes.prepend("form-check-label").compact.join(" ") + radio_html + .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) end end end @@ -506,5 +493,24 @@ def get_help_text_by_i18n_key(name) help_text end end + + def unwrapped_radio(name, value, radio_html, *args) + radio_html + end + + def wrapped_radio(custom: false, disabled: false, inline: false) + if custom + wrapper_classes = ["custom-control", "custom-radio"] + wrapper_classes.append("custom-control-inline") if inline + else + wrapper_classes = ["form-check"] + wrapper_classes.append("form-check-inline") if inline + wrapper_classes.append("disabled") if disabled + end + wrapper_class = wrapper_classes.compact.join(" ") + content_tag(:div, class: wrapper_class) do + yield + end + end end end From 8b832376ee34b03e107359bcc367f255a883b299 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 11:34:25 -0800 Subject: [PATCH 23/31] Extract method unwrapped_radio. Some label code remains to be refactored. --- lib/bootstrap_form/form_builder.rb | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 3a4ceee16..c336693d2 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -168,21 +168,13 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ def radio_button_with_bootstrap(name, value, *args) prevent_prepend_and_append!(options) options = args.extract_options!.symbolize_keys! - radio_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) - radio_classes = [options[:class]] - radio_classes << "position-static" if options[:skip_label] || options[:hide_label] - if options[:custom] - radio_options[:class] = radio_classes.prepend("custom-control-input").compact.join(' ') - else - radio_options[:class] = radio_classes.prepend("form-check-input").compact.join(' ') - end - args << radio_options - radio_html = radio_button_without_bootstrap(name, value, *args) - - label_classes = [options[:label_class]] - label_classes << hide_class if options[:hide_label] wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + radio_html = unwrapped_radio(name, value, options, *args) + + label_classes = [options[:label_class]] + label_classes << hide_class if options[:hide_label] + if options[:skip_label] radio_html elsif options[:custom] @@ -494,8 +486,17 @@ def get_help_text_by_i18n_key(name) end end - def unwrapped_radio(name, value, radio_html, *args) - radio_html + def unwrapped_radio(name, value, options, *args) + radio_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) + radio_classes = [options[:class]] + radio_classes << "position-static" if options[:skip_label] || options[:hide_label] + if options[:custom] + radio_options[:class] = radio_classes.prepend("custom-control-input").compact.join(' ') + else + radio_options[:class] = radio_classes.prepend("form-check-input").compact.join(' ') + end + args << radio_options + radio_button_without_bootstrap(name, value, *args) end def wrapped_radio(custom: false, disabled: false, inline: false) From 85fd80d7a9f7aba55eb2f376a1ccb0bebbca1da1 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 11:40:47 -0800 Subject: [PATCH 24/31] Finish extract method unwrapped_radio. --- lib/bootstrap_form/form_builder.rb | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index c336693d2..3153ac97e 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -170,22 +170,7 @@ def radio_button_with_bootstrap(name, value, *args) options = args.extract_options!.symbolize_keys! wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do - radio_html = unwrapped_radio(name, value, options, *args) - - label_classes = [options[:label_class]] - label_classes << hide_class if options[:hide_label] - - if options[:skip_label] - radio_html - elsif options[:custom] - label_class = label_classes.prepend("custom-control-label").compact.join(" ") - # TODO: Notice we don't seem to pass the ID into the custom control. - radio_html.concat(label(name, options[:label], value: value, class: label_class)) - else - label_class = label_classes.prepend("form-check-label").compact.join(" ") - radio_html - .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) - end + unwrapped_radio(name, value, options, *args) end end @@ -496,7 +481,22 @@ def unwrapped_radio(name, value, options, *args) radio_options[:class] = radio_classes.prepend("form-check-input").compact.join(' ') end args << radio_options - radio_button_without_bootstrap(name, value, *args) + radio_html = radio_button_without_bootstrap(name, value, *args) + + label_classes = [options[:label_class]] + label_classes << hide_class if options[:hide_label] + + if options[:skip_label] + radio_html + elsif options[:custom] + label_class = label_classes.prepend("custom-control-label").compact.join(" ") + # TODO: Notice we don't seem to pass the ID into the custom control. + radio_html.concat(label(name, options[:label], value: value, class: label_class)) + else + label_class = label_classes.prepend("form-check-label").compact.join(" ") + radio_html + .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) + end end def wrapped_radio(custom: false, disabled: false, inline: false) From f334e77eb46e3674219a7a6703b64dc6bc51b7f5 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 15:00:09 -0800 Subject: [PATCH 25/31] radio errors in right place. --- lib/bootstrap_form/form_builder.rb | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 3153ac97e..1228c23ac 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -178,7 +178,7 @@ def radio_button_with_bootstrap(name, value, *args) def collection_check_boxes_with_bootstrap(*args) prevent_prepend_and_append!(options) - html = inputs_collection(*args) do |name, value, options| + html = inputs_collection(*args) do |name, value, options, i| options[:multiple] = true check_box(name, options, value, nil) end @@ -187,10 +187,16 @@ def collection_check_boxes_with_bootstrap(*args) bootstrap_method_alias :collection_check_boxes - def collection_radio_buttons_with_bootstrap(*args) - prevent_prepend_and_append!(options) - inputs_collection(*args) do |name, value, options| - radio_button(name, value, options) + def collection_radio_buttons_with_bootstrap(outer_name, collection, outer_value, text, outer_options = {}) + prevent_prepend_and_append!(outer_options) + # This next line is because the options get munged in the legacy code. + help = outer_options[:help] + inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| + wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + radio_html = unwrapped_radio(name, value, options) + radio_html.concat(generate_help(name, help)) if i == collection.size - 1 + radio_html + end end end @@ -427,7 +433,7 @@ def inputs_collection(name, collection, value, text, options = {}, &block) form_group_builder(name, options) do inputs = "" - collection.each do |obj| + collection.each_with_index do |obj, i| input_options = options.merge(label: text.respond_to?(:call) ? text.call(obj) : obj.send(text)) input_value = value.respond_to?(:call) ? value.call(obj) : obj.send(value) @@ -439,7 +445,7 @@ def inputs_collection(name, collection, value, text, options = {}, &block) end input_options.delete(:class) - inputs << block.call(name, input_value, input_options) + inputs << block.call(name, input_value, input_options, i) end inputs.html_safe From ee8f4bad20510b4627de6f556cd1a4c93f8954c0 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 15:40:41 -0800 Subject: [PATCH 26/31] Radio errors and help done. --- lib/bootstrap_form/form_builder.rb | 23 ++++++++++++++++++----- lib/bootstrap_form/helpers/bootstrap.rb | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 1228c23ac..b884d2ca9 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -191,12 +191,17 @@ def collection_radio_buttons_with_bootstrap(outer_name, collection, outer_value, prevent_prepend_and_append!(outer_options) # This next line is because the options get munged in the legacy code. help = outer_options[:help] - inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| - wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do - radio_html = unwrapped_radio(name, value, options) - radio_html.concat(generate_help(name, help)) if i == collection.size - 1 - radio_html + begin + self.in_radio_checkbox_collection = true + inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| + wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + radio_html = unwrapped_radio(name, value, options) + radio_html.concat(generate_help(name, help)) if i == collection.size - 1 + radio_html + end end + ensure + self.in_radio_checkbox_collection = false end end @@ -268,6 +273,14 @@ def default_control_col "col-sm-10" end + def in_radio_checkbox_collection? + @in_radio_checkbox_collection ||= false + end + + def in_radio_checkbox_collection=(state) + @in_radio_checkbox_collection = state + end + def hide_class "sr-only" # still accessible for screen readers end diff --git a/lib/bootstrap_form/helpers/bootstrap.rb b/lib/bootstrap_form/helpers/bootstrap.rb index f8fcd23a7..208c0cee9 100644 --- a/lib/bootstrap_form/helpers/bootstrap.rb +++ b/lib/bootstrap_form/helpers/bootstrap.rb @@ -75,7 +75,7 @@ def prepend_and_append_input(name, options, &block) input = content_tag(:div, input_group_content(options[:prepend]), class: 'input-group-prepend') + input if options[:prepend] input << content_tag(:div, input_group_content(options[:append]), class: 'input-group-append') if options[:append] - input << generate_help(name, help).to_s + input << generate_help(name, help).to_s unless in_radio_checkbox_collection? input = content_tag(:div, input, class: input_group_class) unless options.empty? input end From 2e43e1b31c522ec535de2934f372cc623ea506a7 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 16:08:47 -0800 Subject: [PATCH 27/31] Extract methods wrapped and unwrapped check box. --- lib/bootstrap_form/form_builder.rb | 111 +++++++++++++++-------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 3153ac97e..90f9ffc74 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -107,59 +107,9 @@ def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {}, def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_value = "0", &block) prevent_prepend_and_append!(options) options = options.symbolize_keys! - check_box_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) - check_box_classes = [check_box_options[:class]] - check_box_classes << "position-static" if options[:skip_label] || options[:hide_label] - if options[:custom] - validation = nil - validation = "is-invalid" if has_error?(name) - check_box_options[:class] = (["custom-control-input", validation] + check_box_classes).compact.join(' ') - else - check_box_options[:class] = (["form-check-input"] + check_box_classes).compact.join(' ') - end - - checkbox_html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value) - label_content = block_given? ? capture(&block) : options[:label] - label_description = label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize - - label_name = name - # label's `for` attribute needs to match checkbox tag's id, - # IE sanitized value, IE - # https://github.com/rails/rails/blob/c57e7239a8b82957bcb07534cb7c1a3dcef71864/actionview/lib/action_view/helpers/tags/base.rb#L116-L118 - if options[:multiple] - label_name = - "#{name}_#{checked_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}" - end - - label_classes = [options[:label_class]] - label_classes << hide_class if options[:hide_label] - if options[:custom] - div_class = ["custom-control", "custom-checkbox"] - div_class.append("custom-control-inline") if options[:inline] - label_class = label_classes.prepend("custom-control-label").compact.join(" ") - content_tag(:div, class: div_class.compact.join(" ")) do - if options[:skip_label] - checkbox_html - else - # TODO: Notice we don't seem to pass the ID into the custom control. - checkbox_html.concat(label(label_name, label_description, class: label_class)) - end - end - else - wrapper_class = "form-check" - wrapper_class += " form-check-inline" if options[:inline] - label_class = label_classes.prepend("form-check-label").compact.join(" ") - content_tag(:div, class: wrapper_class) do - if options[:skip_label] - checkbox_html - else - checkbox_html - .concat(label(label_name, - label_description, - { class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) - end - end + wrapped_check_box(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + unwrapped_check_box(name, options, checked_value, unchecked_value, &block) end end @@ -471,6 +421,49 @@ def get_help_text_by_i18n_key(name) end end + def unwrapped_check_box(name, options = {}, checked_value = "1", unchecked_value = "0", &block) + check_box_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) + check_box_classes = [check_box_options[:class]] + check_box_classes << "position-static" if options[:skip_label] || options[:hide_label] + if options[:custom] + validation = nil + validation = "is-invalid" if has_error?(name) + check_box_options[:class] = (["custom-control-input", validation] + check_box_classes).compact.join(' ') + else + check_box_options[:class] = (["form-check-input"] + check_box_classes).compact.join(' ') + end + + checkbox_html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value) + label_content = block_given? ? capture(&block) : options[:label] + label_description = label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize + + label_name = name + # label's `for` attribute needs to match checkbox tag's id, + # IE sanitized value, IE + # https://github.com/rails/rails/blob/c57e7239a8b82957bcb07534cb7c1a3dcef71864/actionview/lib/action_view/helpers/tags/base.rb#L116-L118 + if options[:multiple] + label_name = + "#{name}_#{checked_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}" + end + + label_classes = [options[:label_class]] + label_classes << hide_class if options[:hide_label] + + if options[:skip_label] + checkbox_html + elsif options[:custom] + label_class = label_classes.prepend("custom-control-label").compact.join(" ") + # TODO: Notice we don't seem to pass the ID into the custom control. + checkbox_html.concat(label(label_name, label_description, class: label_class)) + else + label_class = label_classes.prepend("form-check-label").compact.join(" ") + checkbox_html + .concat(label(label_name, + label_description, + { class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) + end + end + def unwrapped_radio(name, value, options, *args) radio_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) radio_classes = [options[:class]] @@ -499,6 +492,20 @@ def unwrapped_radio(name, value, options, *args) end end + def wrapped_check_box(custom: false, disabled: false, inline: false) + if custom + wrapper_classes = ["custom-control", "custom-checkbox"] + wrapper_classes.append("custom-control-inline") if inline + else + wrapper_classes = ["form-check"] + wrapper_classes << "form-check-inline" if inline + end + wrapper_class = wrapper_classes.compact.join(" ") + content_tag(:div, class: wrapper_class) do + yield + end + end + def wrapped_radio(custom: false, disabled: false, inline: false) if custom wrapper_classes = ["custom-control", "custom-radio"] From 7734cc37ca5cf9fa60d525261ef256bca8119d6a Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Mon, 19 Feb 2018 16:26:27 -0800 Subject: [PATCH 28/31] Check box errors and help done. --- lib/bootstrap_form/form_builder.rb | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index ca8e65b73..f75a193f1 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -126,13 +126,24 @@ def radio_button_with_bootstrap(name, value, *args) bootstrap_method_alias :radio_button - def collection_check_boxes_with_bootstrap(*args) - prevent_prepend_and_append!(options) - html = inputs_collection(*args) do |name, value, options, i| - options[:multiple] = true - check_box(name, options, value, nil) + def collection_check_boxes_with_bootstrap(outer_name, collection, outer_value, text, outer_options = {}) + prevent_prepend_and_append!(outer_options) + # This next line is because the options get munged in the legacy code. + help = outer_options[:help] + begin + self.in_radio_checkbox_collection = true + html = inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| + options[:multiple] = true + wrapped_check_box(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + check_box_html = unwrapped_check_box(name, options, value, nil) + check_box_html.concat(generate_help(name, help)) if i == collection.size - 1 + check_box_html + end + end + ensure + self.in_radio_checkbox_collection = false end - hidden_field(args.first,{value: "", multiple: true}).concat(html) + hidden_field(outer_name, value: "", multiple: true).concat(html) end bootstrap_method_alias :collection_check_boxes From eda293fa2f51357826666e40b3399fca69a2973c Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Tue, 20 Feb 2018 08:47:38 -0800 Subject: [PATCH 29/31] Move code to make it easier to see diffs. --- lib/bootstrap_form/form_builder.rb | 206 +++++++++++++++-------------- 1 file changed, 106 insertions(+), 100 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index f75a193f1..5bd5d26be 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -115,6 +115,65 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ bootstrap_method_alias :check_box + private + def wrapped_check_box(custom: false, disabled: false, inline: false) + if custom + wrapper_classes = ["custom-control", "custom-checkbox"] + wrapper_classes.append("custom-control-inline") if inline + else + wrapper_classes = ["form-check"] + wrapper_classes << "form-check-inline" if inline + end + wrapper_class = wrapper_classes.compact.join(" ") + content_tag(:div, class: wrapper_class) do + yield + end + end + + def unwrapped_check_box(name, options = {}, checked_value = "1", unchecked_value = "0", &block) + check_box_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) + check_box_classes = [check_box_options[:class]] + check_box_classes << "position-static" if options[:skip_label] || options[:hide_label] + if options[:custom] + validation = nil + validation = "is-invalid" if has_error?(name) + check_box_options[:class] = (["custom-control-input", validation] + check_box_classes).compact.join(' ') + else + check_box_options[:class] = (["form-check-input"] + check_box_classes).compact.join(' ') + end + + checkbox_html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value) + label_content = block_given? ? capture(&block) : options[:label] + label_description = label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize + + label_name = name + # label's `for` attribute needs to match checkbox tag's id, + # IE sanitized value, IE + # https://github.com/rails/rails/blob/c57e7239a8b82957bcb07534cb7c1a3dcef71864/actionview/lib/action_view/helpers/tags/base.rb#L116-L118 + if options[:multiple] + label_name = + "#{name}_#{checked_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}" + end + + label_classes = [options[:label_class]] + label_classes << hide_class if options[:hide_label] + + if options[:skip_label] + checkbox_html + elsif options[:custom] + label_class = label_classes.prepend("custom-control-label").compact.join(" ") + # TODO: Notice we don't seem to pass the ID into the custom control. + checkbox_html.concat(label(label_name, label_description, class: label_class)) + else + label_class = label_classes.prepend("form-check-label").compact.join(" ") + checkbox_html + .concat(label(label_name, + label_description, + { class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) + end + end + public + def radio_button_with_bootstrap(name, value, *args) prevent_prepend_and_append!(options) options = args.extract_options!.symbolize_keys! @@ -126,10 +185,56 @@ def radio_button_with_bootstrap(name, value, *args) bootstrap_method_alias :radio_button + private + def wrapped_radio(custom: false, disabled: false, inline: false) + if custom + wrapper_classes = ["custom-control", "custom-radio"] + wrapper_classes.append("custom-control-inline") if inline + else + wrapper_classes = ["form-check"] + wrapper_classes.append("form-check-inline") if inline + wrapper_classes.append("disabled") if disabled + end + wrapper_class = wrapper_classes.compact.join(" ") + content_tag(:div, class: wrapper_class) do + yield + end + end + + def unwrapped_radio(name, value, options, *args) + radio_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) + radio_classes = [options[:class]] + radio_classes << "position-static" if options[:skip_label] || options[:hide_label] + if options[:custom] + radio_options[:class] = radio_classes.prepend("custom-control-input").compact.join(' ') + else + radio_options[:class] = radio_classes.prepend("form-check-input").compact.join(' ') + end + args << radio_options + radio_html = radio_button_without_bootstrap(name, value, *args) + + label_classes = [options[:label_class]] + label_classes << hide_class if options[:hide_label] + + if options[:skip_label] + radio_html + elsif options[:custom] + label_class = label_classes.prepend("custom-control-label").compact.join(" ") + # TODO: Notice we don't seem to pass the ID into the custom control. + radio_html.concat(label(name, options[:label], value: value, class: label_class)) + else + label_class = label_classes.prepend("form-check-label").compact.join(" ") + radio_html + .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) + end + end + public + def collection_check_boxes_with_bootstrap(outer_name, collection, outer_value, text, outer_options = {}) prevent_prepend_and_append!(outer_options) # This next line is because the options get munged in the legacy code. help = outer_options[:help] + # Use begin..ensure so block returns the html and resets the in...collection flag. begin self.in_radio_checkbox_collection = true html = inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| @@ -152,6 +257,7 @@ def collection_radio_buttons_with_bootstrap(outer_name, collection, outer_value, prevent_prepend_and_append!(outer_options) # This next line is because the options get munged in the legacy code. help = outer_options[:help] + # Use begin..ensure so block returns the html and resets the in...collection flag. begin self.in_radio_checkbox_collection = true inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| @@ -450,105 +556,5 @@ def get_help_text_by_i18n_key(name) help_text end end - - def unwrapped_check_box(name, options = {}, checked_value = "1", unchecked_value = "0", &block) - check_box_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) - check_box_classes = [check_box_options[:class]] - check_box_classes << "position-static" if options[:skip_label] || options[:hide_label] - if options[:custom] - validation = nil - validation = "is-invalid" if has_error?(name) - check_box_options[:class] = (["custom-control-input", validation] + check_box_classes).compact.join(' ') - else - check_box_options[:class] = (["form-check-input"] + check_box_classes).compact.join(' ') - end - - checkbox_html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value) - label_content = block_given? ? capture(&block) : options[:label] - label_description = label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize - - label_name = name - # label's `for` attribute needs to match checkbox tag's id, - # IE sanitized value, IE - # https://github.com/rails/rails/blob/c57e7239a8b82957bcb07534cb7c1a3dcef71864/actionview/lib/action_view/helpers/tags/base.rb#L116-L118 - if options[:multiple] - label_name = - "#{name}_#{checked_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}" - end - - label_classes = [options[:label_class]] - label_classes << hide_class if options[:hide_label] - - if options[:skip_label] - checkbox_html - elsif options[:custom] - label_class = label_classes.prepend("custom-control-label").compact.join(" ") - # TODO: Notice we don't seem to pass the ID into the custom control. - checkbox_html.concat(label(label_name, label_description, class: label_class)) - else - label_class = label_classes.prepend("form-check-label").compact.join(" ") - checkbox_html - .concat(label(label_name, - label_description, - { class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) - end - end - - def unwrapped_radio(name, value, options, *args) - radio_options = options.except(:label, :label_class, :help, :inline, :custom, :hide_label, :skip_label) - radio_classes = [options[:class]] - radio_classes << "position-static" if options[:skip_label] || options[:hide_label] - if options[:custom] - radio_options[:class] = radio_classes.prepend("custom-control-input").compact.join(' ') - else - radio_options[:class] = radio_classes.prepend("form-check-input").compact.join(' ') - end - args << radio_options - radio_html = radio_button_without_bootstrap(name, value, *args) - - label_classes = [options[:label_class]] - label_classes << hide_class if options[:hide_label] - - if options[:skip_label] - radio_html - elsif options[:custom] - label_class = label_classes.prepend("custom-control-label").compact.join(" ") - # TODO: Notice we don't seem to pass the ID into the custom control. - radio_html.concat(label(name, options[:label], value: value, class: label_class)) - else - label_class = label_classes.prepend("form-check-label").compact.join(" ") - radio_html - .concat(label(name, options[:label], { value: value, class: label_class }.merge(options[:id].present? ? { for: options[:id] } : {}))) - end - end - - def wrapped_check_box(custom: false, disabled: false, inline: false) - if custom - wrapper_classes = ["custom-control", "custom-checkbox"] - wrapper_classes.append("custom-control-inline") if inline - else - wrapper_classes = ["form-check"] - wrapper_classes << "form-check-inline" if inline - end - wrapper_class = wrapper_classes.compact.join(" ") - content_tag(:div, class: wrapper_class) do - yield - end - end - - def wrapped_radio(custom: false, disabled: false, inline: false) - if custom - wrapper_classes = ["custom-control", "custom-radio"] - wrapper_classes.append("custom-control-inline") if inline - else - wrapper_classes = ["form-check"] - wrapper_classes.append("form-check-inline") if inline - wrapper_classes.append("disabled") if disabled - end - wrapper_class = wrapper_classes.compact.join(" ") - content_tag(:div, class: wrapper_class) do - yield - end - end end end From 5ab63b50cbef952197f0ca2f16c0265a0bc21982 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Tue, 20 Feb 2018 09:01:55 -0800 Subject: [PATCH 30/31] Add comments. --- lib/bootstrap_form/form_builder.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 5bd5d26be..665ac376b 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -236,6 +236,9 @@ def collection_check_boxes_with_bootstrap(outer_name, collection, outer_value, t help = outer_options[:help] # Use begin..ensure so block returns the html and resets the in...collection flag. begin + # The following is an ugly way to prevent `form_group` from outputting + # the error on the wrapper, when Bootstrap 4 wants it to be in the last + # element. self.in_radio_checkbox_collection = true html = inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| options[:multiple] = true @@ -259,6 +262,9 @@ def collection_radio_buttons_with_bootstrap(outer_name, collection, outer_value, help = outer_options[:help] # Use begin..ensure so block returns the html and resets the in...collection flag. begin + # The following is an ugly way to prevent `form_group` from outputting + # the error on the wrapper, when Bootstrap 4 wants it to be in the last + # element. self.in_radio_checkbox_collection = true inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do From 63c09331e6a9874a0e308900e6053adb4c650649 Mon Sep 17 00:00:00 2001 From: Larry Reid Date: Wed, 21 Feb 2018 15:22:28 -0800 Subject: [PATCH 31/31] Improve testing and fix defect. --- lib/bootstrap_form/form_builder.rb | 32 +++++++++++++++++++++++------ test/bootstrap_checkbox_test.rb | 19 +++++++++++++++++ test/bootstrap_radio_button_test.rb | 18 ++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index 665ac376b..c7f74053a 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -108,7 +108,7 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_ prevent_prepend_and_append!(options) options = options.symbolize_keys! - wrapped_check_box(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + wrapped_check_box(custom: options[:custom], disabled: options[:disabled], inline: layout_inline?(options[:inline])) do unwrapped_check_box(name, options, checked_value, unchecked_value, &block) end end @@ -178,7 +178,7 @@ def radio_button_with_bootstrap(name, value, *args) prevent_prepend_and_append!(options) options = args.extract_options!.symbolize_keys! - wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: layout_inline?(options[:inline])) do unwrapped_radio(name, value, options, *args) end end @@ -242,7 +242,7 @@ def collection_check_boxes_with_bootstrap(outer_name, collection, outer_value, t self.in_radio_checkbox_collection = true html = inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| options[:multiple] = true - wrapped_check_box(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + wrapped_check_box(custom: options[:custom], disabled: options[:disabled], inline: layout_inline?(options[:inline])) do check_box_html = unwrapped_check_box(name, options, value, nil) check_box_html.concat(generate_help(name, help)) if i == collection.size - 1 check_box_html @@ -267,7 +267,7 @@ def collection_radio_buttons_with_bootstrap(outer_name, collection, outer_value, # element. self.in_radio_checkbox_collection = true inputs_collection(outer_name, collection, outer_value, text, outer_options) do |name, value, options, i| - wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: options[:inline]) do + wrapped_radio(custom: options[:custom], disabled: options[:disabled], inline: layout_inline?(options[:inline])) do radio_html = unwrapped_radio(name, value, options) radio_html.concat(generate_help(name, help)) if i == collection.size - 1 radio_html @@ -326,8 +326,28 @@ def fields_for_with_bootstrap(record_name, record_object = nil, fields_options = private - def horizontal? - layout == :horizontal + def layout_default?(field_layout = nil) + [:default, nil].include? layout_in_effect(field_layout) + end + + def layout_horizontal?(field_layout = nil) + layout_in_effect(field_layout) == :horizontal + end + + def layout_inline?(field_layout = nil) + layout_in_effect(field_layout) == :inline + end + + def field_inline_override?(field_layout = nil) + field_layout == :inline && layout != :inline + end + + # true and false should only come from check_box and radio_button, + # and those don't have a :horizontal layout + def layout_in_effect(field_layout) + field_layout = :inline if field_layout == true + field_layout = :default if field_layout == false + field_layout || layout end def get_group_layout(group_layout) diff --git a/test/bootstrap_checkbox_test.rb b/test/bootstrap_checkbox_test.rb index 58d2d847b..80938c3db 100644 --- a/test/bootstrap_checkbox_test.rb +++ b/test/bootstrap_checkbox_test.rb @@ -109,6 +109,25 @@ class BootstrapCheckboxTest < ActionView::TestCase assert_equivalent_xml expected, @builder.check_box(:terms, label: 'I agree to the terms', inline: true) end + test "inline checkboxes from form layout" do + expected = <<-HTML.strip_heredoc +
+ +
+ + + +
+
+ HTML + actual = bootstrap_form_for(@user, layout: :inline) do |f| + f.check_box(:terms, label: 'I agree to the terms') + end + assert_equivalent_xml expected, actual + end + test "disabled inline check_box" do expected = <<-HTML.strip_heredoc
diff --git a/test/bootstrap_radio_button_test.rb b/test/bootstrap_radio_button_test.rb index f90349d2d..a6bf7c7bc 100644 --- a/test/bootstrap_radio_button_test.rb +++ b/test/bootstrap_radio_button_test.rb @@ -65,6 +65,24 @@ class BootstrapRadioButtonTest < ActionView::TestCase assert_equivalent_xml expected, @builder.radio_button(:misc, '1', label: 'This is a radio button', inline: true) end + test "radio_button inline label is set correctly from form level" do + expected = <<-HTML.strip_heredoc +
+ +
+ + +
+
+ HTML + actual = bootstrap_form_for(@user, layout: :inline) do |f| + f.radio_button(:misc, '1', label: 'This is a radio button') + end + assert_equivalent_xml expected, actual + end + test "radio_button disabled inline label is set correctly" do expected = <<-HTML.strip_heredoc