Skip to content

Commit

Permalink
When :input_html => { :id => 'foo' } is given, change also the label[@…
Browse files Browse the repository at this point in the history
…for] value.
  • Loading branch information
josevalim committed Aug 25, 2009
1 parent 5900aa4 commit cc9a601
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 15 deletions.
27 changes: 19 additions & 8 deletions lib/formtastic.rb
Expand Up @@ -90,7 +90,7 @@ def input(method, options = {})
options[:as] ||= default_input_type(method)

html_class = [ options[:as], (options[:required] ? :required : :optional) ]
html_class << 'error' if @object && @object.respond_to?(:errors) && @object.errors.on(method.to_s)
html_class << 'error' if @object && @object.respond_to?(:errors) && @object.errors[method.to_sym]

wrapper_html = options.delete(:wrapper_html) || {}
wrapper_html[:id] ||= generate_html_id(method)
Expand All @@ -100,6 +100,11 @@ def input(method, options = {})
::ActiveSupport::Deprecation.warn(":as => :#{options[:as]} is deprecated, use :as => :#{options[:as].to_s[8..-1]} instead", caller[3..-1])
end

if options[:input_html] && options[:input_html][:id]
options[:label_html] ||= {}
options[:label_html][:for] ||= options[:input_html][:id]
end

list_item_content = @@inline_order.map do |type|
send(:"inline_#{type}_for", method, options)
end.compact.join("\n")
Expand Down Expand Up @@ -378,13 +383,19 @@ def label(method, options_or_text=nil, options=nil)
def inline_errors_for(method, options=nil) #:nodoc:
return nil unless @object && @object.respond_to?(:errors) && [:sentence, :list].include?(@@inline_errors)

errors = @object.errors.on(method.to_s)
errors = @object.errors[method.to_sym]
send("error_#{@@inline_errors}", Array(errors)) unless errors.blank?
end
alias :errors_on :inline_errors_for

protected

# Prepare options to be sent to label
#
def options_for_label(options)
options.slice(:label, :required).merge!(options.fetch(:label_html, {}))
end

# Deals with :for option when it's supplied to inputs methods. Additional
# options to be passed down to :for should be supplied using :for_options
# key.
Expand Down Expand Up @@ -466,7 +477,7 @@ def input_simple(type, method, options)
html_options = options.delete(:input_html) || {}
html_options = default_string_options(method, type).merge(html_options) if STRING_MAPPINGS.include?(type)

self.label(method, options.slice(:label, :required)) +
self.label(method, options_for_label(options)) +
self.send(INPUT_MAPPINGS[type], method, html_options)
end

Expand Down Expand Up @@ -579,7 +590,7 @@ def select_input(method, options)
end

input_name = generate_association_input_name(method)
self.label(method, options.slice(:label, :required).merge(:input_name => input_name)) +
self.label(method, options_for_label(options).merge(:input_name => input_name)) +
self.select(input_name, collection, set_options(options), html_options)
end
alias :boolean_select_input :select_input
Expand All @@ -594,7 +605,7 @@ def select_input(method, options)
def time_zone_input(method, options)
html_options = options.delete(:input_html) || {}

self.label(method, options.slice(:label, :required)) +
self.label(method, options_for_label(options)) +
self.time_zone_select(method, options.delete(:priority_zones), set_options(options), html_options)
end

Expand Down Expand Up @@ -875,7 +886,7 @@ def country_input(method, options)
html_options = options.delete(:input_html) || {}
priority_countries = options.delete(:priority_countries) || @@priority_countries

self.label(method, options.slice(:label, :required)) +
self.label(method, options_for_label(options)) +
self.country_select(method, priority_countries, set_options(options), html_options)
end

Expand All @@ -891,7 +902,7 @@ def boolean_input(method, options)
options.delete(:checked_value) || '1', options.delete(:unchecked_value) || '0')

label = options.delete(:label) || humanized_attribute_name(method)
self.label(method, input + label, options.slice(:required))
self.label(method, input + label, options_for_label(options))
end

# Generates an input for the given method using the type supplied with :as.
Expand Down Expand Up @@ -989,7 +1000,7 @@ def field_set_and_list_wrapping_for_method(method, options, contents)
contents = contents.join if contents.respond_to?(:join)

template.content_tag(:fieldset,
%{<legend>#{self.label(method, options.slice(:label, :required).merge!(:as_span => true))}</legend>} +
%{<legend>#{self.label(method, options_for_label(options).merge!(:as_span => true))}</legend>} +
template.content_tag(:ol, contents)
)
end
Expand Down
21 changes: 14 additions & 7 deletions spec/formtastic_spec.rb
Expand Up @@ -62,7 +62,7 @@ class Author; end
@fred.stub!(:login).and_return('fred_smith')
@fred.stub!(:id).and_return(37)
@fred.stub!(:new_record?).and_return(false)
@fred.stub!(:errors).and_return(mock('errors', :on => nil))
@fred.stub!(:errors).and_return(mock('errors', :[] => nil))

@bob = mock('user')
@bob.stub!(:class).and_return(Author)
Expand All @@ -72,7 +72,7 @@ class Author; end
@bob.stub!(:posts).and_return([])
@bob.stub!(:post_ids).and_return([])
@bob.stub!(:new_record?).and_return(false)
@bob.stub!(:errors).and_return(mock('errors', :on => nil))
@bob.stub!(:errors).and_return(mock('errors', :[] => nil))

Author.stub!(:find).and_return([@fred, @bob])
Author.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
Expand All @@ -85,7 +85,7 @@ class Author; end
@new_post.stub!(:class).and_return(Post)
@new_post.stub!(:id).and_return(nil)
@new_post.stub!(:new_record?).and_return(true)
@new_post.stub!(:errors).and_return(mock('errors', :on => nil))
@new_post.stub!(:errors).and_return(mock('errors', :[] => nil))
@new_post.stub!(:author).and_return(nil)

@freds_post = mock('post')
Expand All @@ -97,7 +97,7 @@ class Author; end
@freds_post.stub!(:authors).and_return([@fred])
@freds_post.stub!(:author_ids).and_return([@fred.id])
@freds_post.stub!(:new_record?).and_return(false)
@freds_post.stub!(:errors).and_return(mock('errors', :on => nil))
@freds_post.stub!(:errors).and_return(mock('errors', :[] => nil))
@fred.stub!(:posts).and_return([@freds_post])
@fred.stub!(:post_ids).and_return([@freds_post.id])

Expand Down Expand Up @@ -336,8 +336,8 @@ def custom(arg1, arg2, options = {})
before(:each) do
@title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
@errors = mock('errors')
@errors.stub!(:on).with('title').and_return(@title_errors)
@errors.stub!(:on).with('body').and_return(nil)
@errors.stub!(:[]).with(:title).and_return(@title_errors)
@errors.stub!(:[]).with(:body).and_return(nil)
@new_post.stub!(:errors).and_return(@errors)
end

Expand Down Expand Up @@ -922,7 +922,7 @@ def custom(arg1, arg2, options = {})
before do
@title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
@errors = mock('errors')
@errors.stub!(:on).with('title').and_return(@title_errors)
@errors.stub!(:[]).with(:title).and_return(@title_errors)
@new_post.stub!(:errors).and_return(@errors)
end

Expand Down Expand Up @@ -1082,6 +1082,13 @@ def custom(arg1, arg2, options = {})
output_buffer.should have_tag("form li input.myclass")
end

it 'should consider input_html :id in labels' do
semantic_form_for(@new_post) do |builder|
concat(builder.input(:title, :as => type, :input_html => { :id => 'myid' }))
end
output_buffer.should have_tag('form li label[@for="myid"]')
end

it 'should generate input and labels even if no object is given' do
semantic_form_for(:project, :url => 'http://test.host/') do |builder|
concat(builder.input(:title, :as => type))
Expand Down

0 comments on commit cc9a601

Please sign in to comment.