Permalink
Browse files

Automatically wrap nested inputs() in an <li> tag to preserve HTML va…

…lidity. Fixes #487
  • Loading branch information...
1 parent 0ae3ba0 commit 925f42e435db527828dd41d793fab6b4dbfc49d1 @justinfrench committed Apr 10, 2011
Showing with 105 additions and 15 deletions.
  1. +2 −0 CHANGELOG
  2. +28 −15 lib/formtastic/helpers/inputs_helper.rb
  3. +75 −0 spec/inputs_spec.rb
View
@@ -16,6 +16,8 @@
* Added support for HTML5 required attribute on input, select and textarea tags
* Added support for HTML5 min/max/step attributes on NumericInput
* Added support for HTML5 placeholder attributes on Stringish inputs (string, email, phone, url, search, number, password)
+* Changed nested inputs() blocks to be automatically wrapped in an `<li>` tag to preserve HTML validity
+
1.2.4.beta (unreleased)
@@ -376,6 +376,10 @@ def input(method, options = {})
# All options except `:name`, `:title` and `:for` will be passed down to the fieldset as HTML
# attributes (id, class, style, etc).
#
+ # When nesting `inputs()` inside another `inputs()` block, the nested content will
+ # automatically be wrapped in an `<li>` tag to preserve the HTML validity (a `<fieldset>`
+ # cannot be a direct descendant of an `<ol>`.
+ #
#
# @option *args :for [Symbol, ActiveModel, Array]
# The contents of this option is passed down to Rails' fields_for() helper, so it accepts the same values.
@@ -487,28 +491,37 @@ def input(method, options = {})
# <% end %>
# <% end %>
def inputs(*args, &block)
+ wrap_it = @already_in_an_inputs_block ? true : false
+ @already_in_an_inputs_block = true
+
title = field_set_title_from_args(*args)
html_options = args.extract_options!
html_options[:class] ||= "inputs"
html_options[:name] = title
- if html_options[:for] # Nested form
- inputs_for_nested_attributes(*(args << html_options), &block)
- elsif block_given?
- field_set_and_list_wrapping(*(args << html_options), &block)
- else
- if @object && args.empty?
- args = association_columns(:belongs_to)
- args += content_columns
- args -= SKIPPED_COLUMNS
- args.compact!
+ out = begin
+ if html_options[:for] # Nested form
+ inputs_for_nested_attributes(*(args << html_options), &block)
+ elsif block_given?
+ field_set_and_list_wrapping(*(args << html_options), &block)
+ else
+ if @object && args.empty?
+ args = association_columns(:belongs_to)
+ args += content_columns
+ args -= SKIPPED_COLUMNS
+ args.compact!
+ end
+ legend = args.shift if args.first.is_a?(::String)
+ contents = args.collect { |method| input(method.to_sym) }
+ args.unshift(legend) if legend.present?
+
+ field_set_and_list_wrapping(*((args << html_options) << contents))
end
- legend = args.shift if args.first.is_a?(::String)
- contents = args.collect { |method| input(method.to_sym) }
- args.unshift(legend) if legend.present?
-
- field_set_and_list_wrapping(*((args << html_options) << contents))
end
+
+ out = template.content_tag(:li, out) if wrap_it
+ @already_in_an_inputs_block = false
+ out
end
# A thin wrapper around Rails' `fields_for` helper to set `:builder => Formtastic::FormBuilder`
View
@@ -436,4 +436,79 @@
end
end
+
+ describe 'nesting' do
+
+ context "when not nested" do
+ it "should not wrap the inputs in an li block" do
+ concat(semantic_form_for(@new_post) do |builder|
+ concat(builder.inputs do
+ end)
+ end)
+ output_buffer.should_not have_tag('form > li')
+ end
+ end
+
+ context "when nested (with block)" do
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
+ concat(semantic_form_for(@new_post) do |builder|
+ concat(builder.inputs do
+ concat(builder.inputs do
+ end)
+ end)
+ end)
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
+ end
+ end
+
+ context "when nested (with block and :for)" do
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
+ concat(semantic_form_for(@new_post) do |builder|
+ concat(builder.inputs do
+ concat(builder.inputs(:for => :author) do |author_builder|
+ end)
+ end)
+ end)
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
+ end
+ end
+
+ context "when nested (without block)" do
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
+ concat(semantic_form_for(@new_post) do |builder|
+ concat(builder.inputs do
+ concat(builder.inputs(:title))
+ end)
+ end)
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
+ end
+ end
+
+ context "when nested (without block, with :for)" do
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
+ concat(semantic_form_for(@new_post) do |builder|
+ concat(builder.inputs do
+ concat(builder.inputs(:name, :for => :author))
+ end)
+ end)
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol')
+ end
+ end
+
+ context "when double nested" do
+ it "should wrap the nested inputs in an li block to maintain HTML validity" do
+ concat(semantic_form_for(@new_post) do |builder|
+ concat(builder.inputs do
+ concat(builder.inputs do
+ concat(builder.inputs do
+ end)
+ end)
+ end)
+ end)
+ output_buffer.should have_tag('form > fieldset.inputs > ol > li > fieldset.inputs > ol > li > fieldset.inputs > ol')
+ end
+ end
+
+ end
+
end

0 comments on commit 925f42e

Please sign in to comment.