Skip to content

Commit

Permalink
Merge pull request heartcombo#622 from stephenprater/classes_on_use
Browse files Browse the repository at this point in the history
add html classes to inputs with the wrappers API

Conflicts:
	lib/simple_form/wrappers/builder.rb
	test/support/misc_helpers.rb
  • Loading branch information
rafaelfranca authored and butsjoh committed Nov 28, 2013
1 parent 3d0ab5c commit d16a81e
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 17 deletions.
5 changes: 5 additions & 0 deletions lib/simple_form/components/label_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ module LabelInput
end

def label_input
[:input_html, :label_html].each do |key|
if options.has_key? key
options[key].merge! options.fetch(:label_input_html, {})
end
end
options[:label] == false ? input : (label + input)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/simple_form/components/labels.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def label_html_options
if options.key?(:input_html) && options[:input_html].key?(:id)
label_options[:for] = options[:input_html][:id]
end
label_options
@label_options = label_options
end

protected
Expand Down
10 changes: 8 additions & 2 deletions lib/simple_form/inputs/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,20 @@ def initialize(builder, attribute_name, column, input_type, options = {})
@html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }

@input_html_classes = @html_classes.dup
@input_html_options = {}

if SimpleForm.input_class && !input_html_classes.empty?
input_html_classes << SimpleForm.input_class
end
end

@input_html_options = html_options_for(:input, input_html_classes).tap do |o|
def input_html_options
html_options = html_options_for(:input, input_html_classes).tap do |o|
o[:readonly] = true if has_readonly?
o[:disabled] = true if has_disabled?
o[:autofocus] = true if has_autofocus?
end
@input_html_options.merge! html_options
end

def input
Expand Down Expand Up @@ -130,8 +135,9 @@ def reflection_or_attribute_name
def html_options_for(namespace, css_classes)
html_options = options[:"#{namespace}_html"]
html_options = html_options ? html_options.dup : {}
html_options.reverse_merge!(@builder.wrapper.options[:"#{namespace}_html"] || {})
css_classes << html_options[:class] if html_options.key?(:class)
html_options[:class] = css_classes unless css_classes.empty?
html_options[:class] = css_classes.uniq unless css_classes.empty?
html_options
end

Expand Down
22 changes: 10 additions & 12 deletions lib/simple_form/wrappers/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,24 @@ module Wrappers
# In the example above, hint defaults to false, which means it won't automatically
# do the lookup anymore. It will only be triggered when :hint is explicitly set.
class Builder

def initialize(options)
@options = options
@components = []
end

def use(name, options=nil, &block)
if block_given?
ActiveSupport::Deprecation.warn "Passing a block to use is deprecated. " \
"Please use wrapper instead of use."
return wrapper(name, options, &block)
end

if options && options.keys != [:wrap_with]
ActiveSupport::Deprecation.warn "Passing :tag, :class and others to use is deprecated. " \
"Please invoke b.use #{name.inspect}, :wrap_with => #{options.inspect} instead."
options = { :wrap_with => options }
if options && (SimpleForm::FormBuilder::ATTRIBUTE_COMPONENTS.include?(name) \
&& !(options.except(:wrap_with).keys.empty?))
raise ArgumentError, "Invalid options #{options.except(:wrap_with).keys.inspect} passed to #{name}."
end

if options && wrapper = options[:wrap_with]
@components << Single.new(name, wrapper)
if options && options[:wrap_with]
@options[:"#{name}_html"] = options.except(:wrap_with)
@components << Single.new(name, options[:wrap_with])
elsif options
@options[:"#{name}_html"] = options
@components << name
else
@components << name
end
Expand Down
58 changes: 58 additions & 0 deletions test/form_builder/wrapper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ class WrapperTest < ActionView::TestCase
assert_select "section.custom_wrapper div.another_wrapper input.string"
end

test 'wrappers with use classes on input basis with arrays' do
swap_wrapper :default do
with_form_for @user, :name
assert_select "section.custom_wrapper div.class1.class2 input.class3.class4"

output_buffer.replace ""

with_form_for @user, :name, wrapper: custom_wrapper_with_no_wrapping_tag
assert_select "div.custom_wrapper div.elem input.input_class_yo.other_class_yo"
end
end

test 'access wrappers with indifferent access' do
swap_wrapper :another do
with_form_for @user, :name, :wrapper => "another"
Expand All @@ -172,6 +184,52 @@ class WrapperTest < ActionView::TestCase
end
end

test 'single element without wrap_with applies options to component tags' do
swap_wrapper :default, custom_wrapper_with_no_wrapping_tag do
with_form_for @user, :name
assert_select "div.custom_wrapper div.elem input.input_class_yo"
assert_select "div.custom_wrapper div.elem input.other_class_yo"
assert_select "div.custom_wrapper div.elem input.string"
assert_select "div.custom_wrapper div.elem label[data-yo='yo']"
assert_select "div.custom_wrapper div.elem span.custom_yo", :text => "custom"
assert_select "div.custom_wrapper div.elem label.both_yo"
assert_select "div.custom_wrapper div.elem input.both_yo"
end
end

test 'single element with wrap with and component options applies to both' do
swap_wrapper :default, custom_wrapper_with_wrapping_tag_and_component_options do
with_form_for @user, :name
assert_no_select "div.custom_wrapper > input"
assert_select "div.custom_wrapper div.wrap input.input_class_yo"
assert_select "div.custom_wrapper div.wrap input.other_class_yo"
end
end

test 'adding any option to tag components on the input ignores them' do
with_concat_form_for @user do |f|
concat f.input :name, :invalid => 'thing'
end
assert_no_select "input[invalid]"
end

test 'adding any option to tag components in wrapper makes html attributes' do
swap_wrapper :default, custom_wrapper_with_wrapping_tag_and_invalid_attributes do
with_input_for @user, :name, :string, :other_invalid => 'other_thing'
assert_select "input.input_class_yo"
assert_select "input[invalid='thing']"
assert_no_select "input[other_invalid]"
end
end

test 'adding invalid options to non-tag components raises an exception' do
assert_raise ArgumentError, "Invalid options [:class] passed to placeholder." do
swap_wrapper :default, custom_wrapper_with_invalid_options do
with_form_for @user, :name
end
end
end

test 'do not duplicate label classes for different inputs' do
swap_wrapper :default, self.custom_wrapper_with_label_html_option do
with_concat_form_for(@user) do |f|
Expand Down
52 changes: 50 additions & 2 deletions test/support/misc_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,48 @@ def custom_wrapper
ba.use :label
ba.use :input
end
b.wrapper :error_wrapper, :tag => :div, :class => "error_wrapper" do |be|
be.use :error, :wrap_with => { :tag => :span, :class => "omg_error" }
b.wrapper :arrays, class: ["class1", "class2"] do |ba|
ba.use :input, class: ["class3", "class4"]
ba.use :label
end
b.wrapper :error_wrapper, tag: :div, class: "error_wrapper" do |be|
be.use :error, wrap_with: { tag: :span, class: "omg_error" }
end
b.use :hint, :wrap_with => { :class => "omg_hint" }
end
end

def custom_wrapper_with_no_wrapping_tag
SimpleForm.build :tag => :div, :class => "custom_wrapper" do |b|
b.wrapper :tag => :div, :class => 'elem' do |component|
component.use :input, :class => ['input_class_yo', 'other_class_yo']
component.use :label, :"data-yo" => 'yo'
component.use :label_input, :class => 'both_yo'
component.use :custom_component, :class => 'custom_yo'
end
end
end

def custom_wrapper_with_wrapping_tag_and_component_options
SimpleForm.build :tag => :div, :class => 'custom_wrapper' do |b|
b.use :input, :class => ['input_class_yo', 'other_class_yo'],
:wrap_with => { :tag => :div, :class => 'wrap' }
end
end

def custom_wrapper_with_wrapping_tag_and_invalid_attributes
SimpleForm.build :tag => :div, :class => "custom_wrapper" do |b|
b.use :input, :class => 'input_class_yo', :invalid => 'thing'
end
end

def custom_wrapper_with_invalid_options
SimpleForm.build :tag => :div, :class => "custom_wrapper" do |b|
b.use :placeholder, :class => 'no_effect'
b.use :input
end
end

def custom_wrapper_with_wrapped_input
SimpleForm.build :tag => :div, :class => "custom_wrapper" do |b|
b.wrapper :tag => :div, :class => 'elem' do |component|
Expand Down Expand Up @@ -136,3 +171,16 @@ def input(attribute_name, *args, &block)
class CustomMapTypeFormBuilder < SimpleForm::FormBuilder
map_type :custom_type, :to => SimpleForm::Inputs::StringInput
end

module SimpleForm::Components::CustomComponent
def custom_component
@custom_component ||= begin
custom_options = options[:custom_component_html]
template.content_tag(:span, custom_options) do
"custom".html_safe
end
end
end
end

SimpleForm::Inputs::Base.send(:include, SimpleForm::Components::CustomComponent)

0 comments on commit d16a81e

Please sign in to comment.