Skip to content

Commit

Permalink
Add collection wrapper tag and item wrapper tag configs
Browse files Browse the repository at this point in the history
These configurations allow us to wrap the entire or each item in the
collection of radio/check boxes using the specified tags, respectively.
  • Loading branch information
carlosantoniodasilva committed Nov 21, 2010
1 parent c0e196e commit af622e4
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 11 deletions.
14 changes: 10 additions & 4 deletions lib/generators/simple_form/templates/simple_form.rb
Expand Up @@ -37,18 +37,24 @@
# CSS class to add to the wrapper if the field has errors.
# config.wrapper_error_class = :field_with_errors

# How the label text should be generated altogether with the required text.
# config.label_text = lambda { |label, required| "#{required} #{label}" }
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
# config.collection_wrapper_tag = nil

# Whether attributes are required by default (or not). Default is true.
# config.required_by_default = true
# You can wrap each item in a collection of radio/check boxes with a tag, defaulting to none.
# config.item_wrapper_tag = nil

# Series of attemps to detect a default label method for collection.
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]

# Series of attemps to detect a default value method for collection.
# config.collection_value_methods = [ :id, :to_s ]

# How the label text should be generated altogether with the required text.
# config.label_text = lambda { |label, required| "#{required} #{label}" }

# Whether attributes are required by default (or not). Default is true.
# config.required_by_default = true

# Collection of methods to detect if a file type was given.
# config.file_methods = [ :file?, :public_filename ]

Expand Down
10 changes: 9 additions & 1 deletion lib/simple_form.rb
Expand Up @@ -55,6 +55,14 @@ module SimpleForm
mattr_accessor :collection_value_methods
@@collection_value_methods = [ :id, :to_s ]

# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
mattr_accessor :collection_wrapper_tag
@@collection_wrapper_tag = nil

# You can wrap each item in a collection of radio/check boxes with a tag, defaulting to none.
mattr_accessor :item_wrapper_tag
@@item_wrapper_tag = nil

# You can wrap all inputs in a pre-defined tag. Default is a div.
mattr_accessor :wrapper_tag
@@wrapper_tag = :div
Expand All @@ -63,7 +71,7 @@ module SimpleForm
mattr_accessor :wrapper_class
@@wrapper_class = :input

# You can define the class to add to the wrapper when the field has errors. Default is fieldWithErrors.
# You can define the class to add to the wrapper when the field has errors. Default is field_with_errors.
mattr_accessor :wrapper_error_class
@@wrapper_error_class = :field_with_errors

Expand Down
31 changes: 26 additions & 5 deletions lib/simple_form/action_view_extensions/builder.rb
Expand Up @@ -29,15 +29,26 @@ module Builder
# * disabled => the value or values that should be disabled. Accepts a single
# item or an array of items.
#
# * collection_wrapper_tag => the tag to wrap the entire collection.
#
# * item_wrapper_tag => the tag to wrap each item in the collection.
#
def collection_radio(attribute, collection, value_method, text_method, options={}, html_options={})
collection.map do |item|
collection_wrapper_tag = options[:collection_wrapper_tag] || SimpleForm.collection_wrapper_tag
item_wrapper_tag = options[:item_wrapper_tag] || SimpleForm.item_wrapper_tag

rendered_collection = collection.map do |item|
value = value_for_collection(item, value_method)
text = value_for_collection(item, text_method)
default_html_options = default_html_options_for_collection(item, value, options, html_options)

radio = radio_button(attribute, value, default_html_options)
collection_label(attribute, value, radio, text, :class => "collection_radio")
label = collection_label(attribute, value, radio, text, :class => "collection_radio")

item_wrapper_tag ? @template.content_tag(item_wrapper_tag, label) : label
end.join.html_safe

collection_wrapper_tag ? @template.content_tag(collection_wrapper_tag, rendered_collection) : rendered_collection
end

# Creates a collection of check boxes for each item in the collection, associated
Expand Down Expand Up @@ -67,16 +78,27 @@ def collection_radio(attribute, collection, value_method, text_method, options={
# * disabled => the value or values that should be disabled. Accepts a single
# item or an array of items.
#
# * collection_wrapper_tag => the tag to wrap the entire collection.
#
# * item_wrapper_tag => the tag to wrap each item in the collection.
#
def collection_check_boxes(attribute, collection, value_method, text_method, options={}, html_options={})
collection.map do |item|
collection_wrapper_tag = options[:collection_wrapper_tag] || SimpleForm.collection_wrapper_tag
item_wrapper_tag = options[:item_wrapper_tag] || SimpleForm.item_wrapper_tag

rendered_collection = collection.map do |item|
value = value_for_collection(item, value_method)
text = value_for_collection(item, text_method)
default_html_options = default_html_options_for_collection(item, value, options, html_options)
default_html_options[:multiple] = true

check_box = check_box(attribute, default_html_options, value, '')
collection_label(attribute, value, check_box, text, :class => "collection_check_boxes")
label = collection_label(attribute, value, check_box, text, :class => "collection_check_boxes")

item_wrapper_tag ? @template.content_tag(item_wrapper_tag, label) : label
end.join.html_safe

collection_wrapper_tag ? @template.content_tag(collection_wrapper_tag, rendered_collection) : rendered_collection
end

# Wrapper for using simple form inside a default rails form.
Expand Down Expand Up @@ -125,7 +147,6 @@ def sanitize_attribute_name(attribute, value)
"#{attribute}_#{value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}"
end


def value_for_collection(item, value) #:nodoc:
value.respond_to?(:call) ? value.call(item) : item.send(value)
end
Expand Down
91 changes: 90 additions & 1 deletion test/action_view_extensions/builder_test.rb
Expand Up @@ -71,12 +71,57 @@ def with_collection_check_boxes(object, attribute, collection, value_method, tex
end

test 'collection radio accepts html options as input' do
with_collection_radio @user, :active, [[1, true], [0, false]], :last, :first, {}, :class => 'radio'
collection = [[1, true], [0, false]]
with_collection_radio @user, :active, collection, :last, :first, {}, :class => 'radio'

assert_select 'form input[type=radio][value=true].radio#user_active_true'
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'
end

test 'collection radio does not wrap the collection by default' do
with_collection_radio @user, :active, [true, false], :to_s, :to_s

assert_no_select 'form ul'
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 items by default' do
with_collection_radio @user, :active, [true, false], :to_s, :to_s

assert_no_select 'form li'
end

# COLLECTION CHECK BOX
test 'collection check box accepts a collection and generate a serie of checkboxes for value method' do
collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
Expand Down Expand Up @@ -176,6 +221,50 @@ def with_collection_check_boxes(object, attribute, collection, value_method, tex
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
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'
end

test 'collection check box does not wrap the collection by default' do
with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s

assert_no_select 'form ul'
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 wrap items by default' do
with_collection_check_boxes @user, :active, [true, false], :to_s, :to_s

assert_no_select 'form li'
end

# SIMPLE FIELDS
test 'simple fields for is available and yields an instance of FormBuilder' do
with_concat_form_for(@user) do |f|
Expand Down

0 comments on commit af622e4

Please sign in to comment.