simple_form 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/.gitignore +2 -0
  2. data/.gitmodules +3 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.rdoc +109 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +82 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.rdoc +180 -53
  9. data/Rakefile +27 -0
  10. data/lib/generators/simple_form/USAGE +1 -1
  11. data/lib/generators/simple_form/install_generator.rb +5 -6
  12. data/lib/generators/simple_form/templates/_form.html.erb +2 -12
  13. data/lib/generators/simple_form/templates/_form.html.haml +10 -0
  14. data/lib/generators/simple_form/templates/_form.html.slim +10 -0
  15. data/lib/generators/simple_form/templates/en.yml +14 -0
  16. data/lib/generators/simple_form/templates/simple_form.rb +66 -12
  17. data/lib/simple_form/action_view_extensions/builder.rb +99 -40
  18. data/lib/simple_form/action_view_extensions/form_helper.rb +29 -6
  19. data/lib/simple_form/components/errors.rb +16 -6
  20. data/lib/simple_form/components/hints.rb +2 -2
  21. data/lib/simple_form/components/label_input.rb +13 -0
  22. data/lib/simple_form/components/labels.rb +5 -7
  23. data/lib/simple_form/components/placeholders.rb +22 -0
  24. data/lib/simple_form/components/wrapper.rb +19 -2
  25. data/lib/simple_form/components.rb +6 -4
  26. data/lib/simple_form/error_notification.rb +42 -0
  27. data/lib/simple_form/form_builder.rb +187 -72
  28. data/lib/simple_form/has_errors.rb +14 -0
  29. data/lib/simple_form/inputs/base.rb +106 -24
  30. data/lib/simple_form/inputs/block_input.rb +3 -2
  31. data/lib/simple_form/inputs/boolean_input.rb +22 -0
  32. data/lib/simple_form/inputs/collection_input.rb +46 -17
  33. data/lib/simple_form/inputs/date_time_input.rb +11 -5
  34. data/lib/simple_form/inputs/hidden_input.rb +11 -2
  35. data/lib/simple_form/inputs/mapping_input.rb +12 -6
  36. data/lib/simple_form/inputs/numeric_input.rb +55 -6
  37. data/lib/simple_form/inputs/priority_input.rb +5 -1
  38. data/lib/simple_form/inputs/string_input.rb +25 -11
  39. data/lib/simple_form/inputs.rb +1 -0
  40. data/lib/simple_form/map_type.rb +9 -6
  41. data/lib/simple_form/version.rb +1 -1
  42. data/lib/simple_form.rb +92 -8
  43. data/simple_form.gemspec +22 -0
  44. data/test/action_view_extensions/builder_test.rb +187 -51
  45. data/test/action_view_extensions/form_helper_test.rb +17 -5
  46. data/test/components/error_test.rb +23 -12
  47. data/test/components/hint_test.rb +4 -8
  48. data/test/components/label_test.rb +79 -11
  49. data/test/components/wrapper_test.rb +63 -0
  50. data/test/discovery_inputs.rb +21 -0
  51. data/test/error_notification_test.rb +62 -0
  52. data/test/form_builder_test.rb +332 -35
  53. data/test/inputs_test.rb +516 -53
  54. data/test/support/misc_helpers.rb +32 -4
  55. data/test/support/mock_controller.rb +4 -4
  56. data/test/support/models.rb +75 -11
  57. data/test/test_helper.rb +28 -12
  58. metadata +51 -11
@@ -1,3 +1,3 @@
1
1
  To copy a SimpleForm initializer to your Rails App, with some configuration values, just do:
2
2
 
3
- script/generate simple_form_install
3
+ rails generate simple_form:install
@@ -2,10 +2,8 @@ module SimpleForm
2
2
  module Generators
3
3
  class InstallGenerator < Rails::Generators::Base
4
4
  desc "Copy SimpleForm default files"
5
-
6
- def self.source_root
7
- @_source_root = File.expand_path('../templates', __FILE__)
8
- end
5
+ source_root File.expand_path('../templates', __FILE__)
6
+ class_option :template_engine
9
7
 
10
8
  def copy_initializers
11
9
  copy_file 'simple_form.rb', 'config/initializers/simple_form.rb'
@@ -16,8 +14,9 @@ module SimpleForm
16
14
  end
17
15
 
18
16
  def copy_scaffold_template
19
- copy_file '_form.html.erb', 'lib/templates/erb/scaffold/_form.html.erb'
17
+ engine = options[:template_engine]
18
+ copy_file "_form.html.#{engine}", "lib/templates/#{engine}/scaffold/_form.html.#{engine}"
20
19
  end
21
20
  end
22
21
  end
23
- end
22
+ end
@@ -1,15 +1,5 @@
1
- <%%= simple_form_for(@<%= singular_name %>) do |f| %>
2
- <%% if @<%= singular_name %>.errors.any? %>
3
- <div id="error_explanation">
4
- <h2><%%= pluralize(@<%= singular_name %>.errors.count, "error") %> prohibited this <%= singular_name %> from being saved:</h2>
5
-
6
- <ul>
7
- <%% @<%= singular_name %>.errors.full_messages.each do |msg| %>
8
- <li><%%= msg %></li>
9
- <%% end %>
10
- </ul>
11
- </div>
12
- <%% end %>
1
+ <%%= simple_form_for(@<%= singular_table_name %>) do |f| %>
2
+ <%%= f.error_notification %>
13
3
 
14
4
  <div class="inputs">
15
5
  <%- attributes.each do |attribute| -%>
@@ -0,0 +1,10 @@
1
+ = simple_form_for(@<%= singular_table_name %>) do |f|
2
+ = f.error_notification
3
+
4
+ .inputs
5
+ <%- attributes.each do |attribute| -%>
6
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
7
+ <%- end -%>
8
+
9
+ .actions
10
+ = f.button :submit
@@ -0,0 +1,10 @@
1
+ = simple_form_for(@<%= singular_table_name %>) do |f|
2
+ = f.error_notification
3
+
4
+ .inputs
5
+ | <%- attributes.each do |attribute| -%>
6
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
7
+ | <%- end -%>
8
+
9
+ .actions
10
+ = f.button :submit
@@ -8,3 +8,17 @@ en:
8
8
  # You can uncomment the line below if you need to overwrite the whole required html.
9
9
  # When using html, text and mark won't be used.
10
10
  # html: '<abbr title="required">*</abbr>'
11
+ error_notification:
12
+ default_message: "Some errors were found, please take a look:"
13
+ # Labels and hints examples
14
+ # labels:
15
+ # password: 'Password'
16
+ # user:
17
+ # new:
18
+ # email: 'E-mail para efetuar o sign in.'
19
+ # edit:
20
+ # email: 'E-mail.'
21
+ # hints:
22
+ # username: 'User name to sign in.'
23
+ # password: 'No special characters, please.'
24
+
@@ -1,32 +1,83 @@
1
1
  # Use this setup block to configure all options available in SimpleForm.
2
2
  SimpleForm.setup do |config|
3
-
4
- # Components used by the form builder to generate a complete input. You can
5
- # remove any of them, change the order, or even add your own components in the
6
- # stack. By inheriting your component from SimpleForm::Components::Base you'll
7
- # have some extra helpers for free.
8
- # config.components = [ :label, :input, :hint, :error ]
3
+ # Components used by the form builder to generate a complete input. You can remove
4
+ # any of them, change the order, or even add your own components to the stack.
5
+ # config.components = [ :placeholder, :label_input, :hint, :error ]
9
6
 
10
7
  # Default tag used on hints.
11
8
  # config.hint_tag = :span
12
9
 
10
+ # CSS class to add to all hint tags.
11
+ # config.hint_class = :hint
12
+
13
+ # CSS class used on errors.
14
+ # config.error_class = :error
15
+
13
16
  # Default tag used on errors.
14
17
  # config.error_tag = :span
15
18
 
19
+ # Method used to tidy up errors.
20
+ # config.error_method = :first
21
+
22
+ # Default tag used for error notification helper.
23
+ # config.error_notification_tag = :p
24
+
25
+ # CSS class to add for error notification helper.
26
+ # config.error_notification_class = :error_notification
27
+
28
+ # ID to add for error notification helper.
29
+ # config.error_notification_id = nil
30
+
16
31
  # You can wrap all inputs in a pre-defined tag.
17
32
  # config.wrapper_tag = :div
18
33
 
19
- # How the label text should be generated altogether with the required text.
20
- # config.label_text = lambda { |label, required| "#{required} #{label}" }
34
+ # CSS class to add to all wrapper tags.
35
+ # config.wrapper_class = :input
36
+
37
+ # CSS class to add to the wrapper if the field has errors.
38
+ # config.wrapper_error_class = :field_with_errors
39
+
40
+ # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
41
+ # config.collection_wrapper_tag = nil
21
42
 
22
- # Series of attemps to detect a default label method for collection
43
+ # You can wrap each item in a collection of radio/check boxes with a tag, defaulting to span.
44
+ # config.item_wrapper_tag = :span
45
+
46
+ # Series of attemps to detect a default label method for collection.
23
47
  # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
24
48
 
25
- # Series of attemps to detect a default value method for collection
49
+ # Series of attemps to detect a default value method for collection.
26
50
  # config.collection_value_methods = [ :id, :to_s ]
27
51
 
52
+ # How the label text should be generated altogether with the required text.
53
+ # config.label_text = lambda { |label, required| "#{required} #{label}" }
54
+
55
+ # You can define the class to use on all labels. Default is nil.
56
+ # config.label_class = nil
57
+
58
+ # You can define the class to use on all forms. Default is simple_form.
59
+ # config.form_class = :simple_form
60
+
61
+ # Whether attributes are required by default (or not). Default is true.
62
+ # config.required_by_default = true
63
+
64
+ # Tell browsers whether to use default HTML5 validations (novalidate option).
65
+ # Default is enabled.
66
+ # config.browser_validations = true
67
+
68
+ # Determines whether HTML5 types (:email, :url, :search, :tel) and attributes
69
+ # (e.g. required) are used or not. True by default.
70
+ # Having this on in non-HTML5 compliant sites can cause odd behavior in
71
+ # HTML5-aware browsers such as Chrome.
72
+ # config.html5 = true
73
+
74
+ # Custom mappings for input types. This should be a hash containing a regexp
75
+ # to match as key, and the input type that will be used when the field name
76
+ # matches the regexp as value.
77
+ # config.input_mappings = { /count/ => :integer }
78
+
28
79
  # Collection of methods to detect if a file type was given.
29
- # config.file_methods = [ :file?, :public_filename ]
80
+ # config.file_methods = [ :mounted_as, :file?, :public_filename ]
30
81
 
31
82
  # Default priority for time_zone inputs.
32
83
  # config.time_zone_priority = nil
@@ -34,6 +85,9 @@ SimpleForm.setup do |config|
34
85
  # Default priority for country inputs.
35
86
  # config.country_priority = nil
36
87
 
37
- # Default size for text inputs
88
+ # Default size for text inputs.
38
89
  # config.default_input_size = 50
90
+
91
+ # When false, do not use translations for labels, hints or placeholders.
92
+ # config.translate = true
39
93
  end
@@ -7,7 +7,9 @@ module SimpleForm
7
7
  # Create a collection of radio inputs for the attribute. Basically this
8
8
  # helper will create a radio input associated with a label for each
9
9
  # text/value option in the collection, using value_method and text_method
10
- # to convert these text/value. Based on collection_select.
10
+ # to convert these text/value. You can give a symbol or a proc to both
11
+ # value_method and text_method, that will be evaluated for each item in
12
+ # the collection.
11
13
  #
12
14
  # == Examples
13
15
  #
@@ -29,34 +31,37 @@ module SimpleForm
29
31
  # * disabled => the value or values that should be disabled. Accepts a single
30
32
  # item or an array of items.
31
33
  #
34
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
35
+ #
36
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
37
+ #
32
38
  def collection_radio(attribute, collection, value_method, text_method, options={}, html_options={})
33
- collection.map do |item|
34
- value = item.send value_method
35
- text = item.send text_method
36
-
37
- default_html_options = default_html_options_for_collection(item, value, options, html_options)
38
-
39
- radio_button(attribute, value, default_html_options) <<
40
- label("#{attribute}_#{value}", text, :class => "collection_radio")
41
- end.join.html_safe
39
+ render_collection(
40
+ attribute, collection, value_method, text_method, options, html_options
41
+ ) do |value, text, default_html_options|
42
+ radio_button(attribute, value, default_html_options) +
43
+ label(sanitize_attribute_name(attribute, value), text, :class => "collection_radio")
44
+ end
42
45
  end
43
46
 
44
- # Creates a collection of check boxes for each item in the collection, associated
45
- # with a clickable label. Use value_method and text_method to convert items in
46
- # the collection for use as text/value in check boxes.
47
+ # Creates a collection of check boxes for each item in the collection,
48
+ # associated with a clickable label. Use value_method and text_method to
49
+ # convert items in the collection for use as text/value in check boxes.
50
+ # You can give a symbol or a proc to both value_method and text_method,
51
+ # that will be evaluated for each item in the collection.
47
52
  #
48
53
  # == Examples
49
54
  #
50
55
  # form_for @user do |f|
51
- # f.collection_check_box :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
56
+ # f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
52
57
  # end
53
58
  #
54
59
  # <input name="user[options][]" type="hidden" value="" />
55
60
  # <input id="user_options_true" name="user[options][]" type="checkbox" value="true" />
56
- # <label class="collection_check_box" for="user_options_true">Yes</label>
61
+ # <label class="collection_check_boxes" for="user_options_true">Yes</label>
57
62
  # <input name="user[options][]" type="hidden" value="" />
58
63
  # <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
59
- # <label class="collection_check_box" for="user_options_false">No</label>
64
+ # <label class="collection_check_boxes" for="user_options_false">No</label>
60
65
  #
61
66
  # == Options
62
67
  #
@@ -68,17 +73,19 @@ module SimpleForm
68
73
  # * disabled => the value or values that should be disabled. Accepts a single
69
74
  # item or an array of items.
70
75
  #
76
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
77
+ #
78
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
79
+ #
71
80
  def collection_check_boxes(attribute, collection, value_method, text_method, options={}, html_options={})
72
- collection.map do |item|
73
- value = item.send value_method
74
- text = item.send text_method
75
-
76
- default_html_options = default_html_options_for_collection(item, value, options, html_options)
81
+ render_collection(
82
+ attribute, collection, value_method, text_method, options, html_options
83
+ ) do |value, text, default_html_options|
77
84
  default_html_options[:multiple] = true
78
85
 
79
- check_box(attribute, default_html_options, value, '') <<
80
- label("#{attribute}_#{value}", text, :class => "collection_check_boxes")
81
- end.join.html_safe
86
+ check_box(attribute, default_html_options, value, '') +
87
+ label(sanitize_attribute_name(attribute, value), text, :class => "collection_check_boxes")
88
+ end
82
89
  end
83
90
 
84
91
  # Wrapper for using simple form inside a default rails form.
@@ -92,31 +99,83 @@ module SimpleForm
92
99
  # end
93
100
  def simple_fields_for(*args, &block)
94
101
  options = args.extract_options!
95
- options[:builder] = SimpleForm::FormBuilder
102
+ if self.class < ActionView::Helpers::FormBuilder
103
+ options[:builder] ||= self.class
104
+ else
105
+ options[:builder] ||= SimpleForm::FormBuilder
106
+ end
96
107
  fields_for(*(args << options), &block)
97
108
  end
98
109
 
99
- private
110
+ private
100
111
 
101
- # Generate default options for collection helpers, such as :checked and
102
- # :disabled.
103
- def default_html_options_for_collection(item, value, options, html_options) #:nodoc:
104
- returning(html_options.dup) do |default_html_options|
105
- [:checked, :disabled].each do |option|
106
- next unless options[option]
112
+ # Generate default options for collection helpers, such as :checked and
113
+ # :disabled.
114
+ def default_html_options_for_collection(item, value, options, html_options) #:nodoc:
115
+ html_options = html_options.dup
107
116
 
108
- accept = if options[option].is_a?(Proc)
109
- options[option].call(item)
110
- else
111
- Array(options[option]).include?(value)
112
- end
117
+ [:checked, :disabled].each do |option|
118
+ next unless options[option]
113
119
 
114
- default_html_options[option] = true if accept
115
- end
120
+ accept = if options[option].is_a?(Proc)
121
+ options[option].call(item)
122
+ else
123
+ Array(options[option]).include?(value)
116
124
  end
125
+
126
+ html_options[option] = true if accept
117
127
  end
128
+
129
+ html_options
130
+ end
131
+
132
+ def sanitize_attribute_name(attribute, value)
133
+ "#{attribute}_#{value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}"
134
+ end
135
+
136
+ def render_collection(attribute, collection, value_method, text_method, options={}, html_options={}) #:nodoc:
137
+ collection_wrapper_tag = options[:collection_wrapper_tag] || SimpleForm.collection_wrapper_tag
138
+ item_wrapper_tag = options[:item_wrapper_tag] || SimpleForm.item_wrapper_tag
139
+
140
+ rendered_collection = collection.map do |item|
141
+ value = value_for_collection(item, value_method)
142
+ text = value_for_collection(item, text_method)
143
+ default_html_options = default_html_options_for_collection(item, value, options, html_options)
144
+
145
+ rendered_item = yield value, text, default_html_options
146
+
147
+ item_wrapper_tag ? @template.content_tag(item_wrapper_tag, rendered_item) : rendered_item
148
+ end.join.html_safe
149
+
150
+ collection_wrapper_tag ? @template.content_tag(collection_wrapper_tag, rendered_collection) : rendered_collection
151
+ end
152
+
153
+ def value_for_collection(item, value) #:nodoc:
154
+ value.respond_to?(:call) ? value.call(item) : item.send(value)
155
+ end
118
156
  end
119
157
  end
120
158
  end
121
159
 
122
- ActionView::Helpers::FormBuilder.send :include, SimpleForm::ActionViewExtensions::Builder
160
+ class ActionView::Helpers::FormBuilder
161
+ include SimpleForm::ActionViewExtensions::Builder
162
+
163
+ # Override default Rails collection_select helper to handle lambdas/procs in
164
+ # text and value methods, so it works the same way as collection_radio and
165
+ # collection_check_boxes in SimpleForm. If none of text/value methods is a
166
+ # callable object, then it just delegates back to original collection select.
167
+ #
168
+ alias :original_collection_select :collection_select
169
+ def collection_select(attribute, collection, value_method, text_method, options={}, html_options={})
170
+ if value_method.respond_to?(:call) || text_method.respond_to?(:call)
171
+ collection = collection.map do |item|
172
+ value = value_for_collection(item, value_method)
173
+ text = value_for_collection(item, text_method)
174
+ [value, text]
175
+ end
176
+ value_method, text_method = :first, :last
177
+ end
178
+
179
+ original_collection_select(attribute, collection, value_method, text_method, options, html_options)
180
+ end
181
+ end
@@ -1,7 +1,6 @@
1
1
  module SimpleForm
2
2
  module ActionViewExtensions
3
- # This modules create simple form wrappers around default form_for,
4
- # fields_for and remote_form_for.
3
+ # This module creates simple form wrappers around default form_for and fields_for.
5
4
  #
6
5
  # Example:
7
6
  #
@@ -10,19 +9,43 @@ module SimpleForm
10
9
  # end
11
10
  #
12
11
  module FormHelper
13
- [:form_for, :fields_for, :remote_form_for].each do |helper|
12
+ # based on what is done in formtastic
13
+ # http://github.com/justinfrench/formtastic/blob/master/lib/formtastic.rb#L1706
14
+ @@default_field_error_proc = nil
15
+
16
+ # Override the default ActiveRecordHelper behaviour of wrapping the input.
17
+ # This gets taken care of semantically by adding an error class to the wrapper tag
18
+ # containing the input.
19
+ #
20
+ FIELD_ERROR_PROC = proc do |html_tag, instance_tag|
21
+ html_tag
22
+ end
23
+
24
+ def with_custom_field_error_proc(&block)
25
+ @@default_field_error_proc = ::ActionView::Base.field_error_proc
26
+ ::ActionView::Base.field_error_proc = FIELD_ERROR_PROC
27
+ result = yield
28
+ ::ActionView::Base.field_error_proc = @@default_field_error_proc
29
+ result
30
+ end
31
+
32
+ [:form_for, :fields_for].each do |helper|
14
33
  class_eval <<-METHOD, __FILE__, __LINE__
15
34
  def simple_#{helper}(record_or_name_or_array, *args, &block)
16
35
  options = args.extract_options!
17
- options[:builder] = SimpleForm::FormBuilder
36
+ options[:builder] ||= SimpleForm::FormBuilder
18
37
  css_class = case record_or_name_or_array
19
38
  when String, Symbol then record_or_name_or_array.to_s
20
39
  when Array then dom_class(record_or_name_or_array.last)
21
40
  else dom_class(record_or_name_or_array)
22
41
  end
23
42
  options[:html] ||= {}
24
- options[:html][:class] = "simple_form \#{css_class} \#{options[:html][:class]}".strip
25
- #{helper}(record_or_name_or_array, *(args << options), &block)
43
+ options[:html][:novalidate] = !SimpleForm.browser_validations
44
+ options[:html][:class] = "\#{SimpleForm.form_class} \#{css_class} \#{options[:html][:class]}".strip
45
+
46
+ with_custom_field_error_proc do
47
+ #{helper}(record_or_name_or_array, *(args << options), &block)
48
+ end
26
49
  end
27
50
  METHOD
28
51
  end
@@ -1,8 +1,10 @@
1
1
  module SimpleForm
2
2
  module Components
3
3
  module Errors
4
+ include SimpleForm::HasErrors
5
+
4
6
  def error
5
- template.content_tag(error_tag, error_text, error_html_options) if object && errors.present?
7
+ template.content_tag(error_tag, error_text, error_html_options) if has_errors?
6
8
  end
7
9
 
8
10
  def error_tag
@@ -10,11 +12,19 @@ module SimpleForm
10
12
  end
11
13
 
12
14
  def error_text
13
- errors.to_sentence
15
+ if options[:error_prefix]
16
+ options[:error_prefix] + " " + errors.send(error_method)
17
+ else
18
+ errors.send(error_method)
19
+ end
20
+ end
21
+
22
+ def error_method
23
+ options[:error_method] || SimpleForm.error_method
14
24
  end
15
25
 
16
26
  def error_html_options
17
- html_options_for(:error, :error)
27
+ html_options_for(:error, [SimpleForm.error_class])
18
28
  end
19
29
 
20
30
  protected
@@ -24,12 +34,12 @@ module SimpleForm
24
34
  end
25
35
 
26
36
  def errors_on_attribute
27
- Array(object.errors[attribute_name])
37
+ object.errors[attribute_name]
28
38
  end
29
39
 
30
40
  def errors_on_association
31
- reflection ? Array(object.errors[reflection.name]) : []
41
+ reflection ? object.errors[reflection.name] : []
32
42
  end
33
43
  end
34
44
  end
35
- end
45
+ end
@@ -14,8 +14,8 @@ module SimpleForm
14
14
  end
15
15
 
16
16
  def hint_html_options
17
- html_options_for(:hint, :hint)
17
+ html_options_for(:hint, [SimpleForm.hint_class])
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -0,0 +1,13 @@
1
+ module SimpleForm
2
+ module Components
3
+ module LabelInput
4
+ def self.included(base)
5
+ base.send :include, SimpleForm::Components::Labels
6
+ end
7
+
8
+ def label_input
9
+ (options[:label] == false ? "" : label) + input
10
+ end
11
+ end
12
+ end
13
+ end
@@ -36,8 +36,8 @@ module SimpleForm
36
36
  end
37
37
 
38
38
  def label_html_options
39
- label_options = html_options_for(:label, input_type, required_class)
40
- label_options[:for] = options[:input_html][:id] if options.key?(:input_html)
39
+ label_options = html_options_for(:label, [input_type, required_class, SimpleForm.label_class])
40
+ label_options[:for] = options[:input_html][:id] if options.key?(:input_html) && options[:input_html].key?(:id)
41
41
  label_options
42
42
  end
43
43
 
@@ -52,16 +52,14 @@ module SimpleForm
52
52
  attribute_required? ? self.class.translate_required_html.dup : ''
53
53
  end
54
54
 
55
- # First check human attribute name and then labels.
55
+ # First check labels translation and then human attribute name.
56
56
  def label_translation #:nodoc:
57
- default = if object.class.respond_to?(:human_attribute_name)
57
+ translate(:labels) || if object.class.respond_to?(:human_attribute_name)
58
58
  object.class.human_attribute_name(reflection_or_attribute_name.to_s)
59
59
  else
60
60
  attribute_name.to_s.humanize
61
61
  end
62
-
63
- translate(:labels, default)
64
62
  end
65
63
  end
66
64
  end
67
- end
65
+ end
@@ -0,0 +1,22 @@
1
+ module SimpleForm
2
+ module Components
3
+ module Placeholders
4
+ def placeholder
5
+ input_html_options[:placeholder] ||= placeholder_text if has_placeholder?
6
+ nil
7
+ end
8
+
9
+ def has_placeholder?
10
+ false
11
+ end
12
+
13
+ def placeholder_present?
14
+ options[:placeholder] != false && placeholder_text.present?
15
+ end
16
+
17
+ def placeholder_text
18
+ @placeholder ||= options[:placeholder] || translate(:placeholders)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -13,9 +13,26 @@ module SimpleForm
13
13
  options[:wrapper_tag] || SimpleForm.wrapper_tag
14
14
  end
15
15
 
16
+ def wrapper_class
17
+ options[:wrapper_class] || SimpleForm.wrapper_class
18
+ end
19
+
20
+ def wrapper_error_class
21
+ options[:wrapper_error_class] || SimpleForm.wrapper_error_class
22
+ end
23
+
16
24
  def wrapper_html_options
17
- html_options_for(:wrapper, "input", input_type, required_class)
25
+ css_classes = input_html_classes.unshift(wrapper_class)
26
+ css_classes << wrapper_error_class if has_errors?
27
+ css_classes << disabled_class if disabled?
28
+ html_options_for(:wrapper, css_classes)
29
+ end
30
+
31
+ private
32
+
33
+ def disabled_class
34
+ 'disabled'
18
35
  end
19
36
  end
20
37
  end
21
- end
38
+ end
@@ -1,8 +1,10 @@
1
1
  module SimpleForm
2
2
  module Components
3
- autoload :Errors, 'simple_form/components/errors'
4
- autoload :Hints, 'simple_form/components/hints'
5
- autoload :Labels, 'simple_form/components/labels'
6
- autoload :Wrapper, 'simple_form/components/wrapper'
3
+ autoload :Errors, 'simple_form/components/errors'
4
+ autoload :Hints, 'simple_form/components/hints'
5
+ autoload :LabelInput, 'simple_form/components/label_input'
6
+ autoload :Labels, 'simple_form/components/labels'
7
+ autoload :Placeholders, 'simple_form/components/placeholders'
8
+ autoload :Wrapper, 'simple_form/components/wrapper'
7
9
  end
8
10
  end
@@ -0,0 +1,42 @@
1
+ module SimpleForm
2
+ class ErrorNotification
3
+ delegate :object, :object_name, :template, :to => :@builder
4
+ include SimpleForm::HasErrors
5
+
6
+ def initialize(builder, options)
7
+ @builder = builder
8
+ @message = options.delete(:message)
9
+ @options = options
10
+ end
11
+
12
+ def render
13
+ if has_errors?
14
+ template.content_tag(error_notification_tag, error_message, html_options)
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ def error_message
21
+ @message || translate_error_notification
22
+ end
23
+
24
+ def error_notification_tag
25
+ SimpleForm.error_notification_tag
26
+ end
27
+
28
+ def html_options
29
+ @options[:class] = "#{SimpleForm.error_notification_class} #{@options[:class]}".strip
30
+ @options[:id] = SimpleForm.error_notification_id if SimpleForm.error_notification_id
31
+ @options
32
+ end
33
+
34
+ def translate_error_notification
35
+ lookups = []
36
+ lookups << :"#{object_name}"
37
+ lookups << :default_message
38
+ lookups << "Some errors were found, please take a look:"
39
+ I18n.t(lookups.shift, :scope => :"simple_form.error_notification", :default => lookups)
40
+ end
41
+ end
42
+ end