diff --git a/lib/simple_form/action_view_extensions/builder.rb b/lib/simple_form/action_view_extensions/builder.rb index ad1342a4..d366a27b 100644 --- a/lib/simple_form/action_view_extensions/builder.rb +++ b/lib/simple_form/action_view_extensions/builder.rb @@ -145,7 +145,7 @@ module SimpleForm end def render_collection(attribute, collection, value_method, text_method, options={}, html_options={}) #:nodoc: - item_wrapper_tag = options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag) + item_wrapper_tag = options.fetch(:item_wrapper_tag, :span) rendered_collection = collection.map do |item| value = value_for_collection(item, value_method) @@ -164,11 +164,11 @@ module SimpleForm value.respond_to?(:call) ? value.call(item) : item.send(value) end - def wrap_rendered_collection(collection, options) #:nodoc: - wrapper_tag = options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag) + def wrap_rendered_collection(collection, options) + wrapper_tag = options[:collection_wrapper_tag] if wrapper_tag - wrapper_class = [SimpleForm.collection_wrapper_class, options[:collection_wrapper_class]].compact.presence + wrapper_class = options[:collection_wrapper_class] @template.content_tag(wrapper_tag, collection, :class => wrapper_class) else collection diff --git a/lib/simple_form/inputs/collection_input.rb b/lib/simple_form/inputs/collection_input.rb index ff9b963f..a724ce87 100644 --- a/lib/simple_form/inputs/collection_input.rb +++ b/lib/simple_form/inputs/collection_input.rb @@ -21,6 +21,7 @@ module SimpleForm def input_options options = super options[:include_blank] = true unless skip_include_blank? + apply_default_collection_options!(options) if check_boxes? || radio? options end @@ -36,7 +37,7 @@ module SimpleForm # Checkbox components does not use the required html tag. # See more info here - https://github.com/plataformatec/simple_form/issues/340#issuecomment-2871956 def has_required? - super && (input_options[:include_blank] || multiple?) && input_type != :check_boxes + super && (input_options[:include_blank] || multiple?) && !check_boxes? end # Check if :include_blank must be included by default. @@ -48,6 +49,26 @@ module SimpleForm !!options[:input_html].try(:[], :multiple) end + def check_boxes? + input_type == :check_boxes + end + + def radio? + input_type == :radio + end + + def apply_default_collection_options!(options) + unless options.key?(:item_wrapper_tag) + options[:item_wrapper_tag] = SimpleForm.item_wrapper_tag + end + unless options.key?(:collection_wrapper_tag) + options[:collection_wrapper_tag] = SimpleForm.collection_wrapper_tag + end + options[:collection_wrapper_class] = [ + options[:collection_wrapper_class], SimpleForm.collection_wrapper_class + ].compact.presence + end + # Detect the right method to find the label and value for a collection. # If no label or value method are defined, will attempt to find them based # on default label and value methods that can be configured through diff --git a/test/action_view_extensions/builder_test.rb b/test/action_view_extensions/builder_test.rb index c5b14953..f44dfa3b 100644 --- a/test/action_view_extensions/builder_test.rb +++ b/test/action_view_extensions/builder_test.rb @@ -80,109 +80,47 @@ class BuilderTest < ActionView::TestCase assert_select 'form input[type=radio][value=false].radio#user_active_false' end - test 'collection radio wraps the collection in the configured collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_radio @user, :active, [true, false], :to_s, :to_s - - assert_select 'form ul input[type=radio][value=true]#user_active_true' - assert_select 'form ul input[type=radio][value=false]#user_active_false' - end - end - test 'collection radio wraps the collection in the given collection wrapper tag' do with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => :ul - assert_select 'form ul input[type=radio][value=true]#user_active_true' - assert_select 'form ul input[type=radio][value=false]#user_active_false' + assert_select 'form ul input[type=radio]', :count => 2 end - test 'collection radio does not wrap the collection in the explicitly false collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false - - assert_no_select 'form ul' - assert_no_select 'form ul' - end - end - - test 'collection radio does not wrap the collection in the explicitly nil collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => nil - - assert_no_select 'form ul' - assert_no_select 'form ul' - end - end - - test 'collection radio does not wrap the collection by default' do + test 'collection radio does not render any wrapper tag by default' do with_collection_radio @user, :active, [true, false], :to_s, :to_s + assert_select 'form input[type=radio]', :count => 2 assert_no_select 'form ul' end - test 'collection radio uses the configured class for collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do - with_collection_radio @user, :active, [true, false], :to_s, :to_s + test 'collection radio does not wrap the collection when given falsy values' do + with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false - assert_select 'form ul.inputs-list input[type=radio][value=true]#user_active_true' - assert_select 'form ul.inputs-list input[type=radio][value=false]#user_active_false' - end + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form ul' end test 'collection radio uses the given class for collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_class => 'items-list' + with_collection_radio @user, :active, [true, false], :to_s, :to_s, + :collection_wrapper_tag => :ul, :collection_wrapper_class => "items-list" - assert_select 'form ul.items-list input[type=radio][value=true]#user_active_true' - assert_select 'form ul.items-list input[type=radio][value=false]#user_active_false' - end + assert_select 'form ul.items-list input[type=radio]', :count => 2 end - test 'collection radio uses both configured and given classes for collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_class => 'items-list' + test 'collection radio uses no class for collection wrapper tag when no wrapper tag is given' do + with_collection_radio @user, :active, [true, false], :to_s, :to_s, + :collection_wrapper_class => "items-list" - assert_select 'form ul.inputs-list.items-list input[type=radio][value=true]#user_active_true' - assert_select 'form ul.inputs-list.items-list input[type=radio][value=false]#user_active_false' - end + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form ul' + assert_no_select '.items-list' end test 'collection radio uses no class for collection wrapper tag by default' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_radio @user, :active, [true, false], :to_s, :to_s + with_collection_radio @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => :ul - assert_no_select 'form ul[class]' - end - end - - test 'collection radio wraps each label/radio in the configured item wrapper tag' do - swap SimpleForm, :item_wrapper_tag => :li do - with_collection_radio @user, :active, [true, false], :to_s, :to_s - - assert_select 'form li input[type=radio][value=true]#user_active_true' - assert_select 'form li input[type=radio][value=false]#user_active_false' - end - end - - test 'collection radio wraps each label/radio in the given item wrapper tag' do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => :li - - assert_select 'form li input[type=radio][value=true]#user_active_true' - assert_select 'form li input[type=radio][value=false]#user_active_false' - end - - test 'collection radio does not wrap each label/radio in the explicitly false item wrapper tag' do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false - - assert_no_select 'form span input[type=radio][value=true]#user_active_true' - assert_no_select 'form span input[type=radio][value=false]#user_active_false' - end - - test 'collection radio does not wrap each label/radio in the explicitly nil item wrapper tag' do - with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => nil - - assert_no_select 'form span input[type=radio][value=true]#user_active_true' - assert_no_select 'form span input[type=radio][value=false]#user_active_false' + assert_select 'form ul' + assert_no_select 'form ul[class]' end test 'collection radio wrap items in a span tag by default' do @@ -192,6 +130,19 @@ class BuilderTest < ActionView::TestCase assert_select 'form span input[type=radio][value=false]#user_active_false + label' end + test 'collection radio wraps each item in the given item wrapper tag' do + with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => :li + + assert_select 'form li input[type=radio]', :count => 2 + end + + test 'collection radio does not wrap each item when given explicitly falsy value' do + with_collection_radio @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false + + assert_select 'form input[type=radio]' + assert_no_select 'form span input[type=radio]' + end + test 'collection radio does not wrap input inside the label' do with_collection_radio @user, :active, [true, false], :to_s, :to_s @@ -307,98 +258,66 @@ class BuilderTest < ActionView::TestCase assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_2]', 'Tag 2' end - test 'collection check box wraps the collection in the configured collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s - - assert_select 'form ul input[type=checkbox][value=true]#user_active_true' - assert_select 'form ul input[type=checkbox][value=false]#user_active_false' - end - end - - test 'collection check box wraps the collection in the given collection wrapper tag' do + test 'collection check boxes wraps the collection in the given collection wrapper tag' do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => :ul - assert_select 'form ul input[type=checkbox][value=true]#user_active_true' - assert_select 'form ul input[type=checkbox][value=false]#user_active_false' + assert_select 'form ul input[type=checkbox]', :count => 2 end - test 'collection check box does not wrap the collection in the explicitly false collection wrapper tag' do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false, :item_wrapper_tag => false - - assert_select 'form > input[type=checkbox][value=true]#user_active_true' - assert_select 'form > input[type=checkbox][value=false]#user_active_false' - end - - test 'collection check box does not wrap the collection by default' do + test 'collection check boxes does not render any wrapper tag by default' do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s + assert_select 'form input[type=checkbox]', :count => 2 assert_no_select 'form ul' end - test 'collection check box uses the configured class for collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s + test 'collection check boxes does not wrap the collection when given falsy values' do + with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false - assert_select 'form ul.inputs-list input[type=checkbox][value=true]#user_active_true' - assert_select 'form ul.inputs-list input[type=checkbox][value=false]#user_active_false' - end + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form ul' end - test 'collection check box uses the given class for collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_class => 'items-list' + test 'collection check boxes uses the given class for collection wrapper tag' do + with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, + :collection_wrapper_tag => :ul, :collection_wrapper_class => "items-list" - assert_select 'form ul.items-list input[type=checkbox][value=true]#user_active_true' - assert_select 'form ul.items-list input[type=checkbox][value=false]#user_active_false' - end + assert_select 'form ul.items-list input[type=checkbox]', :count => 2 end - test 'collection check box uses both configured and given classes for collection wrapper tag' do - swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_class => 'items-list' + test 'collection check boxes uses no class for collection wrapper tag when no wrapper tag is given' do + with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, + :collection_wrapper_class => "items-list" - assert_select 'form ul.inputs-list.items-list input[type=checkbox][value=true]#user_active_true' - assert_select 'form ul.inputs-list.items-list input[type=checkbox][value=false]#user_active_false' - end + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form ul' + assert_no_select '.items-list' end - test 'collection check box uses no class for collection wrapper tag by default' do - swap SimpleForm, :collection_wrapper_tag => :ul do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s + test 'collection check boxes uses no class for collection wrapper tag by default' do + with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => :ul - assert_no_select 'form ul[class]' - end + assert_select 'form ul' + assert_no_select 'form ul[class]' end - test 'collection check box wraps each label/radio in the configured item wrapper tag' do - swap SimpleForm, :item_wrapper_tag => :li do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s - - assert_select 'form li input[type=checkbox][value=true]#user_active_true' - assert_select 'form li input[type=checkbox][value=false]#user_active_false' - end - end - - test 'collection check box wraps each label/radio in the given item wrapper tag' do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => :li - - assert_select 'form li input[type=checkbox][value=true]#user_active_true' - assert_select 'form li input[type=checkbox][value=false]#user_active_false' - end - - test 'collection check box does not wrapp each label/radio in the explicitly false item wrapper tag' do - with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false - - assert_select 'form > input[type=checkbox][value=true]#user_active_true' - assert_select 'form > input[type=checkbox][value=false]#user_active_false' - end - - test 'collection check box wrap items in a span tag by default' do + test 'collection check boxes wrap items in a span tag by default' do with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s - assert_select 'form span input[type=checkbox][value=true]#user_active_true + label' - assert_select 'form span input[type=checkbox][value=false]#user_active_false + label' + assert_select 'form span input[type=checkbox]', :count => 2 + end + + test 'collection check boxes wraps each item in the given item wrapper tag' do + with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => :li + + assert_select 'form li input[type=checkbox]', :count => 2 + end + + test 'collection check boxes does not wrap each item when given explicitly falsy value' do + with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false + + assert_select 'form input[type=checkbox]' + assert_no_select 'form span input[type=checkbox]' end test 'collection check box does not wrap input inside the label' do diff --git a/test/inputs/collection_input_test.rb b/test/inputs/collection_input_test.rb index 85c5a1d3..29f57b51 100644 --- a/test/inputs/collection_input_test.rb +++ b/test/inputs/collection_input_test.rb @@ -391,4 +391,218 @@ class CollectionInputTest < ActionView::TestCase assert_select 'select option[value=Antonio]', 'ANTONIO' assert_no_select 'select option[value=Antonio][selected]' end + + test 'input radio does not wrap the collection by default' do + with_input_for @user, :active, :radio + + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form ul' + end + + test 'input radio wraps the collection in the configured collection wrapper tag' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :radio + + assert_select 'form ul input[type=radio]', :count => 2 + end + end + + test 'input radio does not wrap the collection when configured with falsy values' do + swap SimpleForm, :collection_wrapper_tag => false do + with_input_for @user, :active, :radio + + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form ul' + end + end + + test 'input radio allows overriding the collection wrapper tag at input level' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :radio, :collection_wrapper_tag => :section + + assert_select 'form section input[type=radio]', :count => 2 + assert_no_select 'form ul' + end + end + + test 'input radio allows disabling the collection wrapper tag at input level' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :radio, :collection_wrapper_tag => false + + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form ul' + end + end + + test 'input radio renders the wrapper tag with the configured wrapper class' do + swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do + with_input_for @user, :active, :radio + + assert_select 'form ul.inputs-list input[type=radio]', :count => 2 + end + end + + test 'input radio allows giving wrapper class at input level only' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :radio, :collection_wrapper_class => 'items-list' + + assert_select 'form ul.items-list input[type=radio]', :count => 2 + end + end + + test 'input radio uses both configured and given wrapper classes for wrapper tag' do + swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do + with_input_for @user, :active, :radio, :collection_wrapper_class => 'items-list' + + assert_select 'form ul.inputs-list.items-list input[type=radio]', :count => 2 + end + end + + test 'input radio wraps each item in the configured item wrapper tag' do + swap SimpleForm, :item_wrapper_tag => :li do + with_input_for @user, :active, :radio + + assert_select 'form li input[type=radio]', :count => 2 + end + end + + test 'input radio does not wrap items when configured with falsy values' do + swap SimpleForm, :item_wrapper_tag => false do + with_input_for @user, :active, :radio + + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form li' + end + end + + test 'input radio allows overriding the item wrapper tag at input level' do + swap SimpleForm, :item_wrapper_tag => :li do + with_input_for @user, :active, :radio, :item_wrapper_tag => :dl + + assert_select 'form dl input[type=radio]', :count => 2 + assert_no_select 'form li' + end + end + + test 'input radio allows disabling the item wrapper tag at input level' do + swap SimpleForm, :item_wrapper_tag => :ul do + with_input_for @user, :active, :radio, :item_wrapper_tag => false + + assert_select 'form input[type=radio]', :count => 2 + assert_no_select 'form li' + end + end + + test 'input radio wraps items in a span tag by default' do + with_input_for @user, :active, :radio + + assert_select 'form span input[type=radio]', :count => 2 + end + + test 'input check boxes does not wrap the collection by default' do + with_input_for @user, :active, :check_boxes + + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form ul' + end + + test 'input check boxes wraps the collection in the configured collection wrapper tag' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :check_boxes + + assert_select 'form ul input[type=checkbox]', :count => 2 + end + end + + test 'input check boxes does not wrap the collection when configured with falsy values' do + swap SimpleForm, :collection_wrapper_tag => false do + with_input_for @user, :active, :check_boxes + + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form ul' + end + end + + test 'input check boxes allows overriding the collection wrapper tag at input level' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :check_boxes, :collection_wrapper_tag => :section + + assert_select 'form section input[type=checkbox]', :count => 2 + assert_no_select 'form ul' + end + end + + test 'input check boxes allows disabling the collection wrapper tag at input level' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :check_boxes, :collection_wrapper_tag => false + + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form ul' + end + end + + test 'input check boxes renders the wrapper tag with the configured wrapper class' do + swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do + with_input_for @user, :active, :check_boxes + + assert_select 'form ul.inputs-list input[type=checkbox]', :count => 2 + end + end + + test 'input check boxes allows giving wrapper class at input level only' do + swap SimpleForm, :collection_wrapper_tag => :ul do + with_input_for @user, :active, :check_boxes, :collection_wrapper_class => 'items-list' + + assert_select 'form ul.items-list input[type=checkbox]', :count => 2 + end + end + + test 'input check boxes uses both configured and given wrapper classes for wrapper tag' do + swap SimpleForm, :collection_wrapper_tag => :ul, :collection_wrapper_class => 'inputs-list' do + with_input_for @user, :active, :check_boxes, :collection_wrapper_class => 'items-list' + + assert_select 'form ul.inputs-list.items-list input[type=checkbox]', :count => 2 + end + end + + test 'input check boxes wraps each item in the configured item wrapper tag' do + swap SimpleForm, :item_wrapper_tag => :li do + with_input_for @user, :active, :check_boxes + + assert_select 'form li input[type=checkbox]', :count => 2 + end + end + + test 'input check boxes does not wrap items when configured with falsy values' do + swap SimpleForm, :item_wrapper_tag => false do + with_input_for @user, :active, :check_boxes + + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form li' + end + end + + test 'input check boxes allows overriding the item wrapper tag at input level' do + swap SimpleForm, :item_wrapper_tag => :li do + with_input_for @user, :active, :check_boxes, :item_wrapper_tag => :dl + + assert_select 'form dl input[type=checkbox]', :count => 2 + assert_no_select 'form li' + end + end + + test 'input check boxes allows disabling the item wrapper tag at input level' do + swap SimpleForm, :item_wrapper_tag => :ul do + with_input_for @user, :active, :check_boxes, :item_wrapper_tag => false + + assert_select 'form input[type=checkbox]', :count => 2 + assert_no_select 'form li' + end + end + + test 'input check boxes wraps items in a span tag by default' do + with_input_for @user, :active, :check_boxes + + assert_select 'form span input[type=checkbox]', :count => 2 + end end