simple_form 1.4.0 → 1.5.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 (54) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +10 -1
  3. data/CHANGELOG.rdoc +36 -0
  4. data/Gemfile +6 -5
  5. data/README.rdoc +25 -4
  6. data/Rakefile +1 -1
  7. data/lib/generators/simple_form/install_generator.rb +2 -6
  8. data/lib/generators/simple_form/templates/{simple_form.rb → config/initializers/simple_form.rb} +2 -2
  9. data/lib/simple_form/action_view_extensions/builder.rb +12 -5
  10. data/lib/simple_form/action_view_extensions/form_helper.rb +29 -18
  11. data/lib/simple_form/components/errors.rb +10 -2
  12. data/lib/simple_form/components/hints.rb +10 -0
  13. data/lib/simple_form/components/label_input.rb +5 -3
  14. data/lib/simple_form/components/labels.rb +10 -4
  15. data/lib/simple_form/components/placeholders.rb +10 -4
  16. data/lib/simple_form/components.rb +1 -1
  17. data/lib/simple_form/error_notification.rb +1 -1
  18. data/lib/simple_form/form_builder.rb +13 -10
  19. data/lib/simple_form/helpers/has_errors.rb +15 -0
  20. data/lib/simple_form/helpers/maxlength.rb +24 -0
  21. data/lib/simple_form/helpers/pattern.rb +28 -0
  22. data/lib/simple_form/helpers/required.rb +36 -0
  23. data/lib/simple_form/helpers/validators.rb +44 -0
  24. data/lib/simple_form/helpers.rb +9 -0
  25. data/lib/simple_form/inputs/base.rb +30 -45
  26. data/lib/simple_form/inputs/boolean_input.rb +1 -1
  27. data/lib/simple_form/inputs/collection_input.rb +1 -1
  28. data/lib/simple_form/inputs/date_time_input.rb +1 -1
  29. data/lib/simple_form/inputs/file_input.rb +9 -0
  30. data/lib/simple_form/inputs/hidden_input.rb +1 -1
  31. data/lib/simple_form/inputs/numeric_input.rb +20 -13
  32. data/lib/simple_form/inputs/password_input.rb +13 -0
  33. data/lib/simple_form/inputs/range_input.rb +16 -0
  34. data/lib/simple_form/inputs/string_input.rb +7 -24
  35. data/lib/simple_form/inputs/text_input.rb +12 -0
  36. data/lib/simple_form/inputs.rb +5 -2
  37. data/lib/simple_form/version.rb +1 -1
  38. data/lib/simple_form.rb +1 -1
  39. data/simple_form.gemspec +3 -0
  40. data/test/action_view_extensions/builder_test.rb +59 -0
  41. data/test/action_view_extensions/form_helper_test.rb +33 -0
  42. data/test/components/label_test.rb +19 -0
  43. data/test/discovery_inputs.rb +2 -2
  44. data/test/form_builder_test.rb +100 -6
  45. data/test/inputs_test.rb +193 -20
  46. data/test/support/mock_controller.rb +9 -0
  47. data/test/support/models.rb +28 -2
  48. data/test/test_helper.rb +1 -0
  49. metadata +47 -12
  50. data/Gemfile.lock +0 -82
  51. data/init.rb +0 -1
  52. data/lib/simple_form/has_errors.rb +0 -14
  53. data/lib/simple_form/inputs/mapping_input.rb +0 -29
  54. /data/lib/generators/simple_form/templates/{en.yml → config/locales/simple_form.en.yml} +0 -0
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .bundle/
2
2
  pkg/
3
+ Gemfile.lock
data/.travis.yml CHANGED
@@ -1,6 +1,15 @@
1
- script: "git submodule update --init && rake test"
1
+ script: "git submodule update --init && bundle exec rake test"
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
+ - 1.9.3
6
+ - ruby-head
5
7
  - ree
6
8
  - jruby
9
+ - rbx
10
+ - rbx-2.0
11
+ notifications:
12
+ recipients:
13
+ - jose.valim@plataformatec.com.br
14
+ - carlos@plataformatec.com.br
15
+ - rafael.franca@plataformatec.com.br
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,39 @@
1
+ == 1.5.0
2
+
3
+ * enhancements
4
+ * Simplified generator by using directory action (by github.com/rupert654)
5
+ * Support for `maxlength` on string inputs inferred from validation (by github.com/srbartlett)
6
+ * Change form css class handling to only add the dom class when one is not given to the form call (by github.com/patrick99e99)
7
+ * Support for required attributes when action validations are present (by github.com/csegura)
8
+ * Don't generate `size` attribute for numeric input (by github.com/jasonmp85)
9
+ * Support for `maxlength` on text area inputs inferred from validation
10
+ * Support for `pattern` on text field inferred from validation when :pattern is true
11
+ * Break Text, Password and File into their own inputs
12
+ * Support easy enabling and disabling of components for specific inputs
13
+ * Add HTML5 range input
14
+
15
+ * bug fix
16
+ * Fix bug when simple_fields_for is used with a hash like models and Rails 3.1
17
+ * Fix bug that doesn't remove the item_wrapper_tag or the collection_wrapper_tag on collection inputs when nil or false value is passed to these options (by gitbub.com/dw2)
18
+ * Fix bug that disable the entire select and wrapper when `disabled` option is a string or array
19
+ * Fix bug when using label/value methods as procs together with disabled/selected options as procs for select inputs
20
+
21
+ == 1.4.2
22
+
23
+ * enhancements
24
+ * Rails 3.1 support
25
+
26
+ == 1.4.1
27
+
28
+ * enhancements
29
+ * ignore required attribute when conditional validations are present
30
+
31
+ * bug fix
32
+ * Do not use required='required' when browser validations are turned off
33
+ * Sanitize HMTL attributes in error and hint helpers when options are present
34
+ * Improve i18n lookup by ignoring explicit child index given to form builder (tests by github.com/rywall)
35
+ * Fixes the form specific validation option if specified on the form itself (by github.com/medihack)
36
+
1
37
  == 1.4.0
2
38
 
3
39
  * enhancements
data/Gemfile CHANGED
@@ -1,8 +1,9 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "rails", "~> 3.0.7"
3
+ gemspec
4
4
 
5
- group :test do
6
- gem "mocha", :require => false
7
- gem "ruby-debug", :require => false, :platform => :ruby_18
8
- end
5
+ gem "rake", '0.9.3.beta1'
6
+ gem "rdoc"
7
+ gem "mocha"
8
+ gem "tzinfo"
9
+ gem "ruby-debug", :platform => :mri_18
data/README.rdoc CHANGED
@@ -158,7 +158,7 @@ Collection inputs accepts two other options beside collections:
158
158
 
159
159
  * value_method => the value method to be applied to the collection to retrieve the value
160
160
 
161
- Those methods are useful to manipulate the given collection. Both of these options also except lambda/procs in case you want to calculate the value or label in a special way eg. custom translation. All other options given are sent straight to the underlying helper. For example, you can give prompt as:
161
+ Those methods are useful to manipulate the given collection. Both of these options also accept lambda/procs in case you want to calculate the value or label in a special way eg. custom translation. All other options given are sent straight to the underlying helper. For example, you can give prompt as:
162
162
 
163
163
  f.input :age, :collection => 18..60, :prompt => "Select your age"
164
164
 
@@ -232,6 +232,16 @@ All web forms need buttons, right? SimpleForm wraps them in the DSL, acting like
232
232
 
233
233
  The above will simply call submit. You choose to use it or not, it's just a question of taste.
234
234
 
235
+ == Wrapping Rails Form Helpers
236
+
237
+ Say you wanted to use a rails form helper but still wrap it in SimpleForm goodness? You can, by calling input with a block like so:
238
+
239
+ <%= f.input :role do %>
240
+ <%= f.select :role, Role.all.map { |r| [r.name, r.id, { :class => r.company.id }] }, :include_blank => true %>
241
+ <% end %>
242
+
243
+ In the above example, we're taking advantage of Rails 3's select method that allows us to pass in a hash of additional attributes for each option.
244
+
235
245
  == Extra helpers
236
246
 
237
247
  SimpleForm also comes with some extra helpers you can use inside rails default forms without relying on simple_form_for helper. They are listed below.
@@ -275,6 +285,13 @@ Creates a collection of check boxes with labels associated (same API as collecti
275
285
  <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
276
286
  <label class="collection_check_box" for="user_options_false">No</label>
277
287
 
288
+ To use this with associations in your model, you can do the following:
289
+
290
+ form_for @user do |f|
291
+ f.collection_check_boxes :role_ids, Role.all, :id, :name # using :roles here is not going to work.
292
+ end
293
+
294
+
278
295
  == Mappings/Inputs available
279
296
 
280
297
  SimpleForm comes with a lot of default mappings:
@@ -294,6 +311,7 @@ SimpleForm comes with a lot of default mappings:
294
311
  integer number field integer
295
312
  float number field float
296
313
  decimal number field decimal
314
+ range range field -
297
315
  datetime datetime select datetime/timestamp
298
316
  date date select date
299
317
  time time select time
@@ -308,9 +326,9 @@ SimpleForm comes with a lot of default mappings:
308
326
  It is very easy to add custom inputs to SimpleForm. For instance, if you want to add a custom input that extends the string one, you just need to add this file:
309
327
 
310
328
  # app/inputs/currency_input.rb
311
- class CurrencyInput < SimpleForm::Inputs::StringInput
329
+ class CurrencyInput < SimpleForm::Inputs::Base
312
330
  def input
313
- "$ #{super}".html_safe
331
+ "$ #{@builder.text_field(attribute_name, input_html_options)}".html_safe
314
332
  end
315
333
  end
316
334
 
@@ -425,6 +443,10 @@ If you want to have all other HTML 5 features, such as the new field types, you
425
443
 
426
444
  This option adds a new `novalidate` property to the form, instructing it to skip all HTML 5 validation. The inputs will still be generated with the required and other attributes, that might help you to use some generic javascript validation.
427
445
 
446
+ You can also add `novalidate` to a specific form by setting the option on the form itself:
447
+
448
+ <%= simple_form_for(resource, :html => {:novalidate => true}) do |form| %>
449
+
428
450
  Please notice that any of the configurations above will disable the `placeholder` component, which is an HTML 5 feature. We believe most of the newest browsers are handling this attribute fine, and if they aren't, any plugin you use would take of using the placeholder attribute to do it. However, you can disable it if you want, by removing the placeholder component from the components list in SimpleForm configuration file.
429
451
 
430
452
  == Configuration
@@ -435,7 +457,6 @@ SimpleForm has several configuration values. You can read and change them in the
435
457
 
436
458
  == Maintainers
437
459
 
438
- * José Valim (https://github.com/josevalim)
439
460
  * Carlos Antonio da Silva (https://github.com/carlosantoniodasilva)
440
461
  * Rafael Mendonça França (https://github.com/rafaelfranca)
441
462
 
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'bundler'
4
4
  Bundler::GemHelper.install_tasks
5
5
 
6
6
  require 'rake/testtask'
7
- require 'rake/rdoctask'
7
+ require 'rdoc/task'
8
8
 
9
9
  desc 'Default: run unit tests.'
10
10
  task :default => :test
@@ -5,12 +5,8 @@ module SimpleForm
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
  class_option :template_engine
7
7
 
8
- def copy_initializers
9
- copy_file 'simple_form.rb', 'config/initializers/simple_form.rb'
10
- end
11
-
12
- def copy_locale_file
13
- copy_file 'en.yml', 'config/locales/simple_form.en.yml'
8
+ def copy_config
9
+ directory 'config'
14
10
  end
15
11
 
16
12
  def copy_scaffold_template
@@ -43,10 +43,10 @@ SimpleForm.setup do |config|
43
43
  # You can wrap each item in a collection of radio/check boxes with a tag, defaulting to span.
44
44
  # config.item_wrapper_tag = :span
45
45
 
46
- # Series of attemps to detect a default label method for collection.
46
+ # Series of attempts to detect a default label method for collection.
47
47
  # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
48
48
 
49
- # Series of attemps to detect a default value method for collection.
49
+ # Series of attempts to detect a default value method for collection.
50
50
  # config.collection_value_methods = [ :id, :to_s ]
51
51
 
52
52
  # How the label text should be generated altogether with the required text.
@@ -114,10 +114,10 @@ module SimpleForm
114
114
  def default_html_options_for_collection(item, value, options, html_options) #:nodoc:
115
115
  html_options = html_options.dup
116
116
 
117
- [:checked, :disabled].each do |option|
117
+ [:checked, :selected, :disabled].each do |option|
118
118
  next unless options[option]
119
119
 
120
- accept = if options[option].is_a?(Proc)
120
+ accept = if options[option].respond_to?(:call)
121
121
  options[option].call(item)
122
122
  else
123
123
  Array(options[option]).include?(value)
@@ -134,8 +134,8 @@ module SimpleForm
134
134
  end
135
135
 
136
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
137
+ collection_wrapper_tag = options.has_key?(:collection_wrapper_tag) ? options[:collection_wrapper_tag] : SimpleForm.collection_wrapper_tag
138
+ item_wrapper_tag = options.has_key?(:item_wrapper_tag) ? options[:item_wrapper_tag] : SimpleForm.item_wrapper_tag
139
139
 
140
140
  rendered_collection = collection.map do |item|
141
141
  value = value_for_collection(item, value_method)
@@ -171,8 +171,15 @@ class ActionView::Helpers::FormBuilder
171
171
  collection = collection.map do |item|
172
172
  value = value_for_collection(item, value_method)
173
173
  text = value_for_collection(item, text_method)
174
- [value, text]
174
+
175
+ default_html_options = default_html_options_for_collection(item, value, options, html_options)
176
+ disabled = value if default_html_options[:disabled]
177
+ selected = value if default_html_options[:selected]
178
+
179
+ [value, text, selected, disabled]
175
180
  end
181
+ options[:disabled] = collection.map(&:pop).compact
182
+ options[:selected] = collection.map(&:pop).compact
176
183
  value_method, text_method = :first, :last
177
184
  end
178
185
 
@@ -29,25 +29,36 @@ module SimpleForm
29
29
  result
30
30
  end
31
31
 
32
- [:form_for, :fields_for].each do |helper|
33
- class_eval <<-METHOD, __FILE__, __LINE__
34
- def simple_#{helper}(record_or_name_or_array, *args, &block)
35
- options = args.extract_options!
36
- options[:builder] ||= SimpleForm::FormBuilder
37
- css_class = case record_or_name_or_array
38
- when String, Symbol then record_or_name_or_array.to_s
39
- when Array then dom_class(record_or_name_or_array.last)
40
- else dom_class(record_or_name_or_array)
41
- end
42
- options[:html] ||= {}
43
- options[:html][:novalidate] = !SimpleForm.browser_validations
44
- options[:html][:class] = "\#{SimpleForm.form_class} \#{css_class} \#{options[:html][:class]}".strip
32
+ def simple_form_for(record, options={}, &block)
33
+ options[:builder] ||= SimpleForm::FormBuilder
34
+ options[:html] ||= {}
35
+ unless options[:html].key?(:novalidate)
36
+ options[:html][:novalidate] = !SimpleForm.browser_validations
37
+ end
38
+ options[:html][:class] = [SimpleForm.form_class, css_class(record, options[:html])].compact.join(" ")
39
+ with_custom_field_error_proc do
40
+ form_for(record, options, &block)
41
+ end
42
+ end
43
+
44
+ def css_class(record, html_options)
45
+ if html_options.key?(:class)
46
+ html_options[:class]
47
+ elsif record.is_a?(String) || record.is_a?(Symbol)
48
+ record
49
+ else
50
+ record = record.last if record.is_a?(Array)
51
+ dom_class(record)
52
+ end
53
+ end
54
+
55
+ def simple_fields_for(record_name, record_object = nil, options = {}, &block)
56
+ options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
57
+ options[:builder] ||= SimpleForm::FormBuilder
45
58
 
46
- with_custom_field_error_proc do
47
- #{helper}(record_or_name_or_array, *(args << options), &block)
48
- end
49
- end
50
- METHOD
59
+ with_custom_field_error_proc do
60
+ fields_for(record_name, record_object, options, &block)
61
+ end
51
62
  end
52
63
  end
53
64
  end
@@ -1,10 +1,10 @@
1
1
  module SimpleForm
2
2
  module Components
3
3
  module Errors
4
- include SimpleForm::HasErrors
4
+ include SimpleForm::Helpers::HasErrors
5
5
 
6
6
  def error
7
- template.content_tag(error_tag, error_text, error_html_options) if has_errors?
7
+ enabled_error
8
8
  end
9
9
 
10
10
  def error_tag
@@ -29,6 +29,14 @@ module SimpleForm
29
29
 
30
30
  protected
31
31
 
32
+ def enabled_error
33
+ template.content_tag(error_tag, error_text, error_html_options) if has_errors?
34
+ end
35
+
36
+ def disabled_error
37
+ nil
38
+ end
39
+
32
40
  def errors
33
41
  @errors ||= (errors_on_attribute + errors_on_association).compact
34
42
  end
@@ -2,9 +2,19 @@ module SimpleForm
2
2
  module Components
3
3
  module Hints
4
4
  def hint
5
+ enabled_hint
6
+ end
7
+
8
+ private
9
+
10
+ def enabled_hint
5
11
  template.content_tag(hint_tag, hint_text, hint_html_options) unless hint_text.blank?
6
12
  end
7
13
 
14
+ def disabled_hint
15
+ nil
16
+ end
17
+
8
18
  def hint_tag
9
19
  options[:hint_tag] || SimpleForm.hint_tag
10
20
  end
@@ -1,8 +1,10 @@
1
1
  module SimpleForm
2
2
  module Components
3
3
  module LabelInput
4
- def self.included(base)
5
- base.send :include, SimpleForm::Components::Labels
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include SimpleForm::Components::Labels
6
8
  end
7
9
 
8
10
  def label_input
@@ -10,4 +12,4 @@ module SimpleForm
10
12
  end
11
13
  end
12
14
  end
13
- end
15
+ end
@@ -1,9 +1,7 @@
1
1
  module SimpleForm
2
2
  module Components
3
3
  module Labels
4
- def self.included(base)
5
- base.extend ClassMethods
6
- end
4
+ extend ActiveSupport::Concern
7
5
 
8
6
  module ClassMethods #:nodoc:
9
7
  def translate_required_html
@@ -24,7 +22,7 @@ module SimpleForm
24
22
  end
25
23
 
26
24
  def label
27
- @builder.label(label_target, label_text, label_html_options)
25
+ enabled_label
28
26
  end
29
27
 
30
28
  def label_text
@@ -43,6 +41,14 @@ module SimpleForm
43
41
 
44
42
  protected
45
43
 
44
+ def enabled_label
45
+ @builder.label(label_target, label_text, label_html_options)
46
+ end
47
+
48
+ def disabled_label
49
+ ""
50
+ end
51
+
46
52
  def raw_label_text #:nodoc:
47
53
  options[:label] || label_translation
48
54
  end
@@ -2,12 +2,18 @@ module SimpleForm
2
2
  module Components
3
3
  module Placeholders
4
4
  def placeholder
5
- input_html_options[:placeholder] ||= placeholder_text if has_placeholder?
5
+ disabled_placeholder
6
+ end
7
+
8
+ private
9
+
10
+ def enabled_placeholder
11
+ input_html_options[:placeholder] ||= placeholder_text if placeholder_present?
6
12
  nil
7
13
  end
8
14
 
9
- def has_placeholder?
10
- false
15
+ def disabled_placeholder
16
+ nil
11
17
  end
12
18
 
13
19
  def placeholder_present?
@@ -15,7 +21,7 @@ module SimpleForm
15
21
  end
16
22
 
17
23
  def placeholder_text
18
- @placeholder ||= options[:placeholder] || translate(:placeholders)
24
+ @placeholder_text ||= options[:placeholder] || translate(:placeholders)
19
25
  end
20
26
  end
21
27
  end
@@ -7,4 +7,4 @@ module SimpleForm
7
7
  autoload :Placeholders, 'simple_form/components/placeholders'
8
8
  autoload :Wrapper, 'simple_form/components/wrapper'
9
9
  end
10
- end
10
+ end
@@ -1,7 +1,7 @@
1
1
  module SimpleForm
2
2
  class ErrorNotification
3
3
  delegate :object, :object_name, :template, :to => :@builder
4
- include SimpleForm::HasErrors
4
+ include SimpleForm::Helpers::HasErrors
5
5
 
6
6
  def initialize(builder, options)
7
7
  @builder = builder
@@ -5,13 +5,16 @@ module SimpleForm
5
5
  extend MapType
6
6
  include SimpleForm::Inputs
7
7
 
8
- map_type :text, :file, :to => SimpleForm::Inputs::MappingInput
9
- map_type :string, :password, :email, :search, :tel, :url, :to => SimpleForm::Inputs::StringInput
10
- map_type :integer, :decimal, :float, :to => SimpleForm::Inputs::NumericInput
11
- map_type :select, :radio, :check_boxes, :to => SimpleForm::Inputs::CollectionInput
12
- map_type :date, :time, :datetime, :to => SimpleForm::Inputs::DateTimeInput
13
- map_type :country, :time_zone, :to => SimpleForm::Inputs::PriorityInput
14
- map_type :boolean, :to => SimpleForm::Inputs::BooleanInput
8
+ map_type :text, :to => SimpleForm::Inputs::TextInput
9
+ map_type :file, :to => SimpleForm::Inputs::FileInput
10
+ map_type :string, :email, :search, :tel, :url, :to => SimpleForm::Inputs::StringInput
11
+ map_type :password, :to => SimpleForm::Inputs::PasswordInput
12
+ map_type :integer, :decimal, :float, :to => SimpleForm::Inputs::NumericInput
13
+ map_type :range, :to => SimpleForm::Inputs::RangeInput
14
+ map_type :select, :radio, :check_boxes, :to => SimpleForm::Inputs::CollectionInput
15
+ map_type :date, :time, :datetime, :to => SimpleForm::Inputs::DateTimeInput
16
+ map_type :country, :time_zone, :to => SimpleForm::Inputs::PriorityInput
17
+ map_type :boolean, :to => SimpleForm::Inputs::BooleanInput
15
18
 
16
19
  def self.discovery_cache
17
20
  @discovery_cache ||= {}
@@ -109,7 +112,7 @@ module SimpleForm
109
112
  # name="user[name]" size="100" type="text" value="Carlos" />
110
113
  #
111
114
  def input_field(attribute_name, options={})
112
- options[:input_html] = options.except(:as)
115
+ options[:input_html] = options.except(:as, :collection, :label_method, :value_method)
113
116
  options.merge!(:components => [:input], :wrapper => false)
114
117
  input(attribute_name, options)
115
118
  end
@@ -204,7 +207,7 @@ module SimpleForm
204
207
  # f.error :name, :id => "cool_error"
205
208
  #
206
209
  def error(attribute_name, options={})
207
- options[:error_html] = options.dup
210
+ options[:error_html] = options.except(:error_tag, :error_prefix, :error_method)
208
211
  column = find_attribute_column(attribute_name)
209
212
  input_type = default_input_type(attribute_name, column, options)
210
213
  SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options).error
@@ -238,7 +241,7 @@ module SimpleForm
238
241
  # f.hint "Don't forget to accept this"
239
242
  #
240
243
  def hint(attribute_name, options={})
241
- options[:hint_html] = options.dup
244
+ options[:hint_html] = options.except(:hint_tag)
242
245
  if attribute_name.is_a?(String)
243
246
  options[:hint] = attribute_name
244
247
  attribute_name, column, input_type = nil, nil, nil
@@ -0,0 +1,15 @@
1
+ module SimpleForm
2
+ module Helpers
3
+ module HasErrors
4
+ private
5
+
6
+ def errors
7
+ object.errors
8
+ end
9
+
10
+ def has_errors?
11
+ object && object.respond_to?(:errors) && errors.present?
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module SimpleForm
2
+ module Helpers
3
+ # Helper methods for maxlength.
4
+ module Maxlength #:nodoc:
5
+
6
+ private
7
+
8
+ def add_maxlength!
9
+ input_html_options[:maxlength] ||= maximum_length_from_validation || limit if SimpleForm.html5
10
+ end
11
+
12
+ def maximum_length_from_validation
13
+ return unless has_validators?
14
+
15
+ length_validator = find_length_validator or return
16
+ length_validator.options[:maximum]
17
+ end
18
+
19
+ def find_length_validator
20
+ find_validator(ActiveModel::Validations::LengthValidator)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ module SimpleForm
2
+ module Helpers
3
+ # Helper methods for pattern.
4
+ module Pattern #:nodoc:
5
+ private
6
+
7
+ def add_pattern!
8
+ input_html_options[:pattern] ||= pattern_source if options[:pattern]
9
+ end
10
+
11
+ def pattern_source
12
+ if options[:pattern] == true
13
+ if has_validators? && pattern_validator
14
+ pattern_validator.options[:with].source
15
+ else
16
+ raise "Could not find format validator for #{attribute_name}"
17
+ end
18
+ else
19
+ options[:pattern]
20
+ end
21
+ end
22
+
23
+ def pattern_validator
24
+ @pattern_validator ||= find_validator(ActiveModel::Validations::FormatValidator)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ module SimpleForm
2
+ module Helpers
3
+ module Required
4
+ private
5
+
6
+ def attribute_required?
7
+ @required
8
+ end
9
+
10
+ def calculate_required
11
+ if !options[:required].nil?
12
+ options[:required]
13
+ elsif has_validators?
14
+ (attribute_validators + reflection_validators).any? do |v|
15
+ v.kind == :presence && valid_validator?(v)
16
+ end
17
+ else
18
+ attribute_required_by_default?
19
+ end
20
+ end
21
+
22
+ # Whether this input is valid for HTML 5 required attribute.
23
+ def has_required?
24
+ attribute_required? && SimpleForm.html5 && SimpleForm.browser_validations
25
+ end
26
+
27
+ def attribute_required_by_default?
28
+ SimpleForm.required_by_default
29
+ end
30
+
31
+ def required_class
32
+ attribute_required? ? :required : :optional
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ module SimpleForm
2
+ module Helpers
3
+ module Validators
4
+ private
5
+
6
+ def has_validators?
7
+ attribute_name && object.class.respond_to?(:validators_on)
8
+ end
9
+
10
+ def attribute_validators
11
+ object.class.validators_on(attribute_name)
12
+ end
13
+
14
+ def reflection_validators
15
+ reflection ? object.class.validators_on(reflection.name) : []
16
+ end
17
+
18
+ def valid_validator?(validator)
19
+ !conditional_validators?(validator) && action_validator_match?(validator)
20
+ end
21
+
22
+ def conditional_validators?(validator)
23
+ validator.options.include?(:if) || validator.options.include?(:unless)
24
+ end
25
+
26
+ def action_validator_match?(validator)
27
+ return true if !validator.options.include?(:on)
28
+
29
+ case validator.options[:on]
30
+ when :save
31
+ true
32
+ when :create
33
+ !object.persisted?
34
+ when :update
35
+ object.persisted?
36
+ end
37
+ end
38
+
39
+ def find_validator(validator)
40
+ attribute_validators.find { |v| validator === v }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ module SimpleForm
2
+ module Helpers
3
+ autoload :HasErrors, 'simple_form/helpers/has_errors'
4
+ autoload :Maxlength, 'simple_form/helpers/maxlength'
5
+ autoload :Pattern, 'simple_form/helpers/pattern'
6
+ autoload :Validators, 'simple_form/helpers/validators'
7
+ autoload :Required, 'simple_form/helpers/required'
8
+ end
9
+ end