simple_form 3.0.4 → 5.0.3

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 (107) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +199 -33
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +453 -128
  5. data/lib/generators/simple_form/install_generator.rb +4 -3
  6. data/lib/generators/simple_form/templates/README +3 -5
  7. data/lib/generators/simple_form/templates/_form.html.erb +2 -0
  8. data/lib/generators/simple_form/templates/_form.html.haml +2 -0
  9. data/lib/generators/simple_form/templates/_form.html.slim +1 -0
  10. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +47 -16
  11. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +418 -23
  12. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +101 -5
  13. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
  14. data/lib/simple_form/action_view_extensions/builder.rb +2 -0
  15. data/lib/simple_form/action_view_extensions/form_helper.rb +10 -3
  16. data/lib/simple_form/components/errors.rb +39 -6
  17. data/lib/simple_form/components/hints.rb +3 -2
  18. data/lib/simple_form/components/html5.rb +16 -5
  19. data/lib/simple_form/components/label_input.rb +21 -2
  20. data/lib/simple_form/components/labels.rb +22 -11
  21. data/lib/simple_form/components/maxlength.rb +9 -5
  22. data/lib/simple_form/components/min_max.rb +2 -1
  23. data/lib/simple_form/components/minlength.rb +38 -0
  24. data/lib/simple_form/components/pattern.rb +2 -1
  25. data/lib/simple_form/components/placeholders.rb +4 -3
  26. data/lib/simple_form/components/readonly.rb +2 -1
  27. data/lib/simple_form/components.rb +2 -0
  28. data/lib/simple_form/error_notification.rb +1 -0
  29. data/lib/simple_form/form_builder.rb +220 -89
  30. data/lib/simple_form/helpers/autofocus.rb +1 -0
  31. data/lib/simple_form/helpers/disabled.rb +1 -0
  32. data/lib/simple_form/helpers/readonly.rb +1 -0
  33. data/lib/simple_form/helpers/required.rb +1 -0
  34. data/lib/simple_form/helpers/validators.rb +2 -1
  35. data/lib/simple_form/helpers.rb +6 -5
  36. data/lib/simple_form/i18n_cache.rb +1 -0
  37. data/lib/simple_form/inputs/base.rb +62 -16
  38. data/lib/simple_form/inputs/block_input.rb +2 -1
  39. data/lib/simple_form/inputs/boolean_input.rb +40 -16
  40. data/lib/simple_form/inputs/collection_check_boxes_input.rb +3 -2
  41. data/lib/simple_form/inputs/collection_input.rb +37 -14
  42. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +9 -13
  43. data/lib/simple_form/inputs/collection_select_input.rb +5 -2
  44. data/lib/simple_form/inputs/color_input.rb +14 -0
  45. data/lib/simple_form/inputs/date_time_input.rb +24 -9
  46. data/lib/simple_form/inputs/file_input.rb +5 -2
  47. data/lib/simple_form/inputs/grouped_collection_select_input.rb +16 -3
  48. data/lib/simple_form/inputs/hidden_input.rb +5 -2
  49. data/lib/simple_form/inputs/numeric_input.rb +6 -4
  50. data/lib/simple_form/inputs/password_input.rb +6 -3
  51. data/lib/simple_form/inputs/priority_input.rb +5 -6
  52. data/lib/simple_form/inputs/range_input.rb +2 -1
  53. data/lib/simple_form/inputs/rich_text_area_input.rb +12 -0
  54. data/lib/simple_form/inputs/string_input.rb +7 -4
  55. data/lib/simple_form/inputs/text_input.rb +6 -3
  56. data/lib/simple_form/inputs.rb +3 -0
  57. data/lib/simple_form/map_type.rb +1 -0
  58. data/lib/simple_form/railtie.rb +8 -0
  59. data/lib/simple_form/tags.rb +13 -2
  60. data/lib/simple_form/version.rb +2 -1
  61. data/lib/simple_form/wrappers/builder.rb +7 -6
  62. data/lib/simple_form/wrappers/leaf.rb +29 -0
  63. data/lib/simple_form/wrappers/many.rb +7 -6
  64. data/lib/simple_form/wrappers/root.rb +10 -3
  65. data/lib/simple_form/wrappers/single.rb +7 -4
  66. data/lib/simple_form/wrappers.rb +2 -0
  67. data/lib/simple_form.rb +137 -21
  68. data/test/action_view_extensions/builder_test.rb +64 -45
  69. data/test/action_view_extensions/form_helper_test.rb +36 -16
  70. data/test/components/custom_components_test.rb +62 -0
  71. data/test/components/label_test.rb +70 -41
  72. data/test/form_builder/association_test.rb +85 -37
  73. data/test/form_builder/button_test.rb +11 -10
  74. data/test/form_builder/error_notification_test.rb +2 -1
  75. data/test/form_builder/error_test.rb +146 -33
  76. data/test/form_builder/general_test.rb +183 -81
  77. data/test/form_builder/hint_test.rb +24 -18
  78. data/test/form_builder/input_field_test.rb +105 -75
  79. data/test/form_builder/label_test.rb +68 -13
  80. data/test/form_builder/wrapper_test.rb +197 -22
  81. data/test/generators/simple_form_generator_test.rb +8 -7
  82. data/test/inputs/boolean_input_test.rb +97 -6
  83. data/test/inputs/collection_check_boxes_input_test.rb +117 -25
  84. data/test/inputs/collection_radio_buttons_input_test.rb +176 -54
  85. data/test/inputs/collection_select_input_test.rb +189 -77
  86. data/test/inputs/color_input_test.rb +10 -0
  87. data/test/inputs/datetime_input_test.rb +121 -50
  88. data/test/inputs/disabled_test.rb +29 -15
  89. data/test/inputs/discovery_test.rb +79 -6
  90. data/test/inputs/file_input_test.rb +3 -2
  91. data/test/inputs/general_test.rb +23 -22
  92. data/test/inputs/grouped_collection_select_input_test.rb +54 -17
  93. data/test/inputs/hidden_input_test.rb +5 -4
  94. data/test/inputs/numeric_input_test.rb +48 -44
  95. data/test/inputs/priority_input_test.rb +17 -16
  96. data/test/inputs/readonly_test.rb +20 -19
  97. data/test/inputs/required_test.rb +58 -13
  98. data/test/inputs/rich_text_area_input_test.rb +15 -0
  99. data/test/inputs/string_input_test.rb +58 -36
  100. data/test/inputs/text_input_test.rb +20 -7
  101. data/test/simple_form_test.rb +9 -0
  102. data/test/support/discovery_inputs.rb +40 -2
  103. data/test/support/misc_helpers.rb +113 -5
  104. data/test/support/mock_controller.rb +7 -1
  105. data/test/support/models.rb +162 -39
  106. data/test/test_helper.rb +19 -4
  107. metadata +51 -43
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class PriorityInput < CollectionSelectInput
4
- def input
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
5
8
  @builder.send(:"#{input_type}_select", attribute_name, input_priority,
6
- input_options, input_html_options)
9
+ input_options, merged_input_options)
7
10
  end
8
11
 
9
12
  def input_priority
@@ -12,10 +15,6 @@ module SimpleForm
12
15
 
13
16
  protected
14
17
 
15
- def has_required?
16
- false
17
- end
18
-
19
18
  def skip_include_blank?
20
19
  super || input_priority.present?
21
20
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class RangeInput < NumericInput
4
- def input
5
+ def input(wrapper_options = nil)
5
6
  if html5?
6
7
  input_html_options[:type] ||= "range"
7
8
  input_html_options[:step] ||= 1
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module SimpleForm
3
+ module Inputs
4
+ class RichTextAreaInput < Base
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
8
+ @builder.rich_text_area(attribute_name, merged_input_options)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,21 +1,24 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class StringInput < Base
4
- enable :placeholder, :maxlength, :pattern
5
+ enable :placeholder, :maxlength, :minlength, :pattern
5
6
 
6
- def input
7
+ def input(wrapper_options = nil)
7
8
  unless string?
8
9
  input_html_classes.unshift("string")
9
10
  input_html_options[:type] ||= input_type if html5?
10
11
  end
11
12
 
12
- @builder.text_field(attribute_name, input_html_options)
13
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
14
+
15
+ @builder.text_field(attribute_name, merged_input_options)
13
16
  end
14
17
 
15
18
  private
16
19
 
17
20
  def string?
18
- input_type == :string
21
+ input_type == :string || input_type == :citext
19
22
  end
20
23
  end
21
24
  end
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class TextInput < Base
4
- enable :placeholder, :maxlength
5
+ enable :placeholder, :maxlength, :minlength
5
6
 
6
- def input
7
- @builder.text_area(attribute_name, input_html_options)
7
+ def input(wrapper_options = nil)
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
10
+ @builder.text_area(attribute_name, merged_input_options)
8
11
  end
9
12
  end
10
13
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  extend ActiveSupport::Autoload
@@ -9,6 +10,7 @@ module SimpleForm
9
10
  autoload :CollectionInput
10
11
  autoload :CollectionRadioButtonsInput
11
12
  autoload :CollectionSelectInput
13
+ autoload :ColorInput
12
14
  autoload :DateTimeInput
13
15
  autoload :FileInput
14
16
  autoload :GroupedCollectionSelectInput
@@ -17,6 +19,7 @@ module SimpleForm
17
19
  autoload :PasswordInput
18
20
  autoload :PriorityInput
19
21
  autoload :RangeInput
22
+ autoload :RichTextAreaInput
20
23
  autoload :StringInput
21
24
  autoload :TextInput
22
25
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'active_support/core_ext/class/attribute'
2
3
 
3
4
  module SimpleForm
@@ -1,7 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  require 'rails/railtie'
2
3
 
3
4
  module SimpleForm
4
5
  class Railtie < Rails::Railtie
5
6
  config.eager_load_namespaces << SimpleForm
7
+
8
+ config.after_initialize do
9
+ unless SimpleForm.configured?
10
+ warn '[Simple Form] Simple Form is not configured in the application and will use the default values.' +
11
+ ' Use `rails generate simple_form:install` to generate the Simple Form configuration.'
12
+ end
13
+ end
6
14
  end
7
15
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Tags
3
4
  module CollectionExtensions
@@ -15,6 +16,12 @@ module SimpleForm
15
16
 
16
17
  rendered_item = yield item, value, text, default_html_options.merge(additional_html_options)
17
18
 
19
+ if @options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested
20
+ label_options = default_html_options.slice(:index, :namespace)
21
+ label_options['class'] = @options[:item_label_class]
22
+ rendered_item = @template_object.label(@object_name, sanitize_attribute_name(value), rendered_item, label_options)
23
+ end
24
+
18
25
  item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item
19
26
  end.join.html_safe
20
27
  end
@@ -41,7 +48,9 @@ module SimpleForm
41
48
  private
42
49
 
43
50
  def render_component(builder)
44
- builder.radio_button + builder.label(class: "collection_radio_buttons")
51
+ label_class = "#{@options[:item_label_class]} collection_radio_buttons".strip
52
+
53
+ builder.radio_button + builder.label(class: label_class)
45
54
  end
46
55
  end
47
56
 
@@ -55,7 +64,9 @@ module SimpleForm
55
64
  private
56
65
 
57
66
  def render_component(builder)
58
- builder.check_box + builder.label(class: "collection_check_boxes")
67
+ label_class = "#{@options[:item_label_class]} collection_check_boxes".strip
68
+
69
+ builder.check_box + builder.label(class: label_class)
59
70
  end
60
71
  end
61
72
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
- VERSION = "3.0.4".freeze
3
+ VERSION = "5.0.3".freeze
3
4
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Wrappers
3
4
  # Provides the builder syntax for components. The builder provides
@@ -45,20 +46,20 @@ module SimpleForm
45
46
  @components = []
46
47
  end
47
48
 
48
- def use(name, options=nil, &block)
49
+ def use(name, options = {})
49
50
  if options && wrapper = options[:wrap_with]
50
- @components << Single.new(name, wrapper)
51
+ @components << Single.new(name, wrapper, options.except(:wrap_with))
51
52
  else
52
- @components << name
53
+ @components << Leaf.new(name, options)
53
54
  end
54
55
  end
55
56
 
56
- def optional(name, options=nil, &block)
57
+ def optional(name, options = {}, &block)
57
58
  @options[name] = false
58
- use(name, options, &block)
59
+ use(name, options)
59
60
  end
60
61
 
61
- def wrapper(name, options=nil)
62
+ def wrapper(name, options = nil)
62
63
  if block_given?
63
64
  name, options = nil, name if name.is_a?(Hash)
64
65
  builder = self.class.new(@options)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module SimpleForm
3
+ module Wrappers
4
+ class Leaf
5
+ attr_reader :namespace
6
+
7
+ def initialize(namespace, options = {})
8
+ @namespace = namespace
9
+ @options = options
10
+ end
11
+
12
+ def render(input)
13
+ method = input.method(@namespace)
14
+
15
+ if method.arity.zero?
16
+ ActiveSupport::Deprecation.warn(SimpleForm::CUSTOM_INPUT_DEPRECATION_WARN % { name: @namespace })
17
+
18
+ method.call
19
+ else
20
+ method.call(@options)
21
+ end
22
+ end
23
+
24
+ def find(name)
25
+ self if @namespace == name
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Wrappers
3
4
  # A wrapper is an object that holds several components and render them.
4
- # A component may either be a symbol or any object that responds to `render`.
5
+ # A component may be any object that responds to `render`.
5
6
  # This API allows inputs/components to be easily wrapped, removing the
6
7
  # need to modify the code only to wrap input in an extra tag.
7
8
  #
@@ -10,9 +11,8 @@ module SimpleForm
10
11
  # on demand on input generation.
11
12
  class Many
12
13
  attr_reader :namespace, :defaults, :components
13
- alias :to_sym :namespace
14
14
 
15
- def initialize(namespace, components, defaults={})
15
+ def initialize(namespace, components, defaults = {})
16
16
  @namespace = namespace
17
17
  @components = components
18
18
  @defaults = defaults
@@ -25,8 +25,8 @@ module SimpleForm
25
25
  options = input.options
26
26
 
27
27
  components.each do |component|
28
- next if options[component] == false
29
- rendered = component.respond_to?(:render) ? component.render(input) : input.send(component)
28
+ next if options[component.namespace] == false
29
+ rendered = component.render(input)
30
30
  content.safe_concat rendered.to_s if rendered
31
31
  end
32
32
 
@@ -51,6 +51,7 @@ module SimpleForm
51
51
 
52
52
  def wrap(input, options, content)
53
53
  return content if options[namespace] == false
54
+ return if defaults[:unless_blank] && content.empty?
54
55
 
55
56
  tag = (namespace && options[:"#{namespace}_tag"]) || @defaults[:tag]
56
57
  return content unless tag
@@ -62,7 +63,7 @@ module SimpleForm
62
63
  end
63
64
 
64
65
  def html_options(options)
65
- options[:"#{namespace}_html"] || {}
66
+ (@defaults[:html] || {}).merge(options[:"#{namespace}_html"] || {})
66
67
  end
67
68
 
68
69
  def html_classes(input, options)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Wrappers
3
4
  # `Root` is the root wrapper for all components. It is special cased to
@@ -17,7 +18,7 @@ module SimpleForm
17
18
 
18
19
  # Provide a fallback if name cannot be found.
19
20
  def find(name)
20
- super || SimpleForm::Wrappers::Many.new(name, [name])
21
+ super || SimpleForm::Wrappers::Many.new(name, [Leaf.new(name)])
21
22
  end
22
23
 
23
24
  private
@@ -27,10 +28,16 @@ module SimpleForm
27
28
  css += SimpleForm.additional_classes_for(:wrapper) do
28
29
  input.additional_classes + [input.input_class]
29
30
  end
30
- css << (options[:wrapper_error_class] || @defaults[:error_class]) if input.has_errors?
31
- css << (options[:wrapper_hint_class] || @defaults[:hint_class]) if input.has_hint?
31
+ css << html_class(:error_class, options) { input.has_errors? }
32
+ css << html_class(:hint_class, options) { input.has_hint? }
33
+ css << html_class(:valid_class, options) { input.valid? }
32
34
  css.compact
33
35
  end
36
+
37
+ def html_class(key, options)
38
+ css = (options[:"wrapper_#{key}"] || @defaults[key])
39
+ css if css && yield
40
+ end
34
41
  end
35
42
  end
36
43
  end
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Wrappers
3
4
  # `Single` is an optimization for a wrapper that has only one component.
4
5
  class Single < Many
5
- def initialize(name, options={})
6
- super(name, [name], options)
6
+ def initialize(name, wrapper_options = {}, options = {})
7
+ @component = Leaf.new(name, options)
8
+
9
+ super(name, [@component], wrapper_options)
7
10
  end
8
11
 
9
12
  def render(input)
10
13
  options = input.options
11
14
  if options[namespace] != false
12
- content = input.send(namespace)
15
+ content = @component.render(input)
13
16
  wrap(input, options, content) if content
14
17
  end
15
18
  end
@@ -17,7 +20,7 @@ module SimpleForm
17
20
  private
18
21
 
19
22
  def html_options(options)
20
- [:label, :input].include?(namespace) ? {} : super
23
+ %i[label input].include?(namespace) ? {} : super
21
24
  end
22
25
  end
23
26
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Wrappers
3
4
  autoload :Builder, 'simple_form/wrappers/builder'
4
5
  autoload :Many, 'simple_form/wrappers/many'
5
6
  autoload :Root, 'simple_form/wrappers/root'
6
7
  autoload :Single, 'simple_form/wrappers/single'
8
+ autoload :Leaf, 'simple_form/wrappers/leaf'
7
9
  end
8
10
  end
data/lib/simple_form.rb CHANGED
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  require 'action_view'
3
+ require 'action_pack'
2
4
  require 'simple_form/action_view_extensions/form_helper'
3
5
  require 'simple_form/action_view_extensions/builder'
4
6
  require 'active_support/core_ext/hash/slice'
@@ -24,6 +26,35 @@ module SimpleForm
24
26
  SimpleForm::Components.eager_load!
25
27
  end
26
28
 
29
+ CUSTOM_INPUT_DEPRECATION_WARN = <<-WARN
30
+ %{name} method now accepts a `wrapper_options` argument. The method definition without the argument is deprecated and will be removed in the next Simple Form version. Change your code from:
31
+
32
+ def %{name}
33
+
34
+ to
35
+
36
+ def %{name}(wrapper_options)
37
+
38
+ See https://github.com/heartcombo/simple_form/pull/997 for more information.
39
+ WARN
40
+
41
+ FILE_METHODS_DEPRECATION_WARN = <<-WARN
42
+ [SIMPLE_FORM] SimpleForm.file_methods is deprecated and has no effect.
43
+
44
+ Since version 5, Simple Form now supports automatically discover of file inputs for the following Gems: activestorage, carrierwave, paperclip, refile and shrine.
45
+ If you are using a custom method that is not from one of the supported Gems, please change your forms to pass the input type explicitly:
46
+
47
+ <%= form.input :avatar, as: :file %>
48
+
49
+ See http://blog.plataformatec.com.br/2019/09/incorrect-access-control-in-simple-form-cve-2019-16676 for more information.
50
+ WARN
51
+
52
+ @@configured = false
53
+
54
+ def self.configured? #:nodoc:
55
+ @@configured
56
+ end
57
+
27
58
  ## CONFIGURATION OPTIONS
28
59
 
29
60
  # Method used to tidy up errors.
@@ -40,11 +71,11 @@ module SimpleForm
40
71
 
41
72
  # Series of attemps to detect a default label method for collection.
42
73
  mattr_accessor :collection_label_methods
43
- @@collection_label_methods = [:to_label, :name, :title, :to_s]
74
+ @@collection_label_methods = %i[to_label name title to_s]
44
75
 
45
76
  # Series of attemps to detect a default value method for collection.
46
77
  mattr_accessor :collection_value_methods
47
- @@collection_value_methods = [:id, :to_s]
78
+ @@collection_value_methods = %i[id to_s]
48
79
 
49
80
  # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
50
81
  mattr_accessor :collection_wrapper_tag
@@ -66,7 +97,7 @@ module SimpleForm
66
97
 
67
98
  # How the label text should be generated altogether with the required text.
68
99
  mattr_accessor :label_text
69
- @@label_text = lambda { |label, required| "#{required} #{label}" }
100
+ @@label_text = ->(label, required, explicit_label) { "#{required} #{label}" }
70
101
 
71
102
  # You can define the class to be used on all labels. Defaults to none.
72
103
  mattr_accessor :label_class
@@ -78,13 +109,19 @@ module SimpleForm
78
109
  mattr_accessor :boolean_style
79
110
  @@boolean_style = :inline
80
111
 
81
- # You can define the class to be used on all forms. Default is simple_form.
82
- mattr_accessor :form_class
112
+ # DEPRECATED: You can define the class to be used on all forms. Default is
113
+ # simple_form.
114
+ mattr_reader :form_class
83
115
  @@form_class = :simple_form
84
116
 
117
+ # You can define the default class to be used on all forms. Can be overriden
118
+ # with `html: { :class }`. Defaults to none.
119
+ mattr_accessor :default_form_class
120
+ @@default_form_class = nil
121
+
85
122
  # You can define which elements should obtain additional classes.
86
123
  mattr_accessor :generate_additional_classes_for
87
- @@generate_additional_classes_for = [:wrapper, :label, :input]
124
+ @@generate_additional_classes_for = %i[wrapper label input]
88
125
 
89
126
  # Whether attributes are required by default or not.
90
127
  mattr_accessor :required_by_default
@@ -94,10 +131,6 @@ module SimpleForm
94
131
  mattr_accessor :browser_validations
95
132
  @@browser_validations = true
96
133
 
97
- # Collection of methods to detect if a file type was given.
98
- mattr_accessor :file_methods
99
- @@file_methods = [:mounted_as, :file?, :public_filename]
100
-
101
134
  # Custom mappings for input types. This should be a hash containing a regexp
102
135
  # to match as key, and the input type that will be used when the field name
103
136
  # matches the regexp as value, such as { /count/ => :integer }.
@@ -107,9 +140,19 @@ module SimpleForm
107
140
  # Custom wrappers for input types. This should be a hash containing an input
108
141
  # type as key and the wrapper that will be used for all inputs with specified type.
109
142
  # e.g { string: :string_wrapper, boolean: :boolean_wrapper }
143
+ # You can also set a wrapper mapping per form basis.
144
+ # e.g simple_form_for(@foo, wrapper_mappings: { check_boxes: :bootstrap_checkbox })
110
145
  mattr_accessor :wrapper_mappings
111
146
  @@wrapper_mappings = nil
112
147
 
148
+ # Namespaces where SimpleForm should look for custom input classes that override
149
+ # default inputs. Namespaces are given as string to allow lazy loading inputs.
150
+ # e.g. config.custom_inputs_namespaces << "CustomInputs"
151
+ # will try to find CustomInputs::NumericInput when an :integer
152
+ # field is called.
153
+ mattr_accessor :custom_inputs_namespaces
154
+ @@custom_inputs_namespaces = []
155
+
113
156
  # Default priority for time_zone inputs.
114
157
  mattr_accessor :time_zone_priority
115
158
  @@time_zone_priority = nil
@@ -118,10 +161,6 @@ module SimpleForm
118
161
  mattr_accessor :country_priority
119
162
  @@country_priority = nil
120
163
 
121
- # DEPRECATED: Maximum size allowed for inputs.
122
- mattr_accessor :default_input_size
123
- @@default_input_size = nil
124
-
125
164
  # When off, do not use translations in labels. Disabling translation in
126
165
  # hints and placeholders can be done manually in the wrapper API.
127
166
  mattr_accessor :translate_labels
@@ -133,7 +172,7 @@ module SimpleForm
133
172
 
134
173
  # Cache SimpleForm inputs discovery.
135
174
  mattr_accessor :cache_discovery
136
- @@cache_discovery = defined?(Rails) && !Rails.env.development?
175
+ @@cache_discovery = defined?(Rails.env) && !Rails.env.development?
137
176
 
138
177
  # Adds a class to each generated button, mostly for compatiblity.
139
178
  mattr_accessor :button_class
@@ -151,15 +190,32 @@ module SimpleForm
151
190
  mattr_accessor :input_class
152
191
  @@input_class = nil
153
192
 
193
+ # Defines if an input wrapper class should be included or not
194
+ mattr_accessor :include_default_input_wrapper_class
195
+ @@include_default_input_wrapper_class = true
196
+
197
+ # Define the default class of the input wrapper of the boolean input.
198
+ mattr_accessor :boolean_label_class
199
+ @@boolean_label_class = 'checkbox'
200
+
154
201
  ## WRAPPER CONFIGURATION
155
202
  # The default wrapper to be used by the FormBuilder.
156
203
  mattr_accessor :default_wrapper
157
204
  @@default_wrapper = :default
158
- @@wrappers = {}
205
+ @@wrappers = {} #:nodoc:
206
+
207
+ mattr_accessor :i18n_scope
208
+ @@i18n_scope = 'simple_form'
209
+
210
+ mattr_accessor :input_field_error_class
211
+ @@input_field_error_class = nil
212
+
213
+ mattr_accessor :input_field_valid_class
214
+ @@input_field_valid_class = nil
159
215
 
160
216
  # Retrieves a given wrapper
161
217
  def self.wrapper(name)
162
- @@wrappers[name.to_sym] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}"
218
+ @@wrappers[name.to_s] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}"
163
219
  end
164
220
 
165
221
  # Raised when fails to find a given wrapper name
@@ -172,25 +228,26 @@ module SimpleForm
172
228
  if block_given?
173
229
  options = args.extract_options!
174
230
  name = args.first || :default
175
- @@wrappers[name.to_sym] = build(options, &block)
231
+ @@wrappers[name.to_s] = build(options, &block)
176
232
  else
177
233
  @@wrappers
178
234
  end
179
235
  end
180
236
 
181
237
  # Builds a new wrapper using SimpleForm::Wrappers::Builder.
182
- def self.build(options={})
238
+ def self.build(options = {})
183
239
  options[:tag] = :div if options[:tag].nil?
184
240
  builder = SimpleForm::Wrappers::Builder.new(options)
185
241
  yield builder
186
242
  SimpleForm::Wrappers::Root.new(builder.to_a, options)
187
243
  end
188
244
 
189
- wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b|
245
+ wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
190
246
  b.use :html5
191
247
 
192
248
  b.use :min_max
193
249
  b.use :maxlength
250
+ b.use :minlength
194
251
  b.use :placeholder
195
252
  b.optional :pattern
196
253
  b.optional :readonly
@@ -210,11 +267,70 @@ module SimpleForm
210
267
  ActiveSupport::Deprecation.warn "[SIMPLE_FORM] SimpleForm.default_input_size= is deprecated and has no effect", caller
211
268
  end
212
269
 
213
- # Default way to setup SimpleForm. Run rails generate simple_form:install
270
+ def self.form_class=(value)
271
+ ActiveSupport::Deprecation.warn "[SIMPLE_FORM] SimpleForm.form_class= is deprecated and will be removed in 4.x. Use SimpleForm.default_form_class= instead", caller
272
+ @@form_class = value
273
+ end
274
+
275
+ def self.file_methods=(file_methods)
276
+ ActiveSupport::Deprecation.warn(FILE_METHODS_DEPRECATION_WARN, caller)
277
+ @@file_methods = file_methods
278
+ end
279
+
280
+ def self.file_methods
281
+ ActiveSupport::Deprecation.warn(FILE_METHODS_DEPRECATION_WARN, caller)
282
+ @@file_methods
283
+ end
284
+
285
+ # Default way to setup Simple Form. Run rails generate simple_form:install
214
286
  # to create a fresh initializer with all configuration values.
215
287
  def self.setup
288
+ @@configured = true
216
289
  yield self
217
290
  end
291
+
292
+ # Includes a component to be used by Simple Form. Methods defined in a
293
+ # component will be exposed to be used in the wrapper as Simple::Components
294
+ #
295
+ # Examples
296
+ #
297
+ # # The application needs to tell where the components will be.
298
+ # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
299
+ #
300
+ # # Create a custom component in the path specified above.
301
+ # # lib/components/input_group_component.rb
302
+ # module InputGroupComponent
303
+ # def prepend
304
+ # ...
305
+ # end
306
+ #
307
+ # def append
308
+ # ...
309
+ # end
310
+ # end
311
+ #
312
+ # SimpleForm.setup do |config|
313
+ # # Create a wrapper using the custom component.
314
+ # config.wrappers :input_group, tag: :div, error_class: :error do |b|
315
+ # b.use :label
316
+ # b.optional :prepend
317
+ # b.use :input
318
+ # b.use :append
319
+ # end
320
+ # end
321
+ #
322
+ # # Using the custom component in the form.
323
+ # <%= simple_form_for @blog, wrapper: input_group do |f| %>
324
+ # <%= f.input :title, prepend: true %>
325
+ # <% end %>
326
+ #
327
+ def self.include_component(component)
328
+ if Module === component
329
+ SimpleForm::Inputs::Base.include(component)
330
+ else
331
+ raise TypeError, "SimpleForm.include_component expects a module but got: #{component.class}"
332
+ end
333
+ end
218
334
  end
219
335
 
220
336
  require 'simple_form/railtie' if defined?(Rails)