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.
- data/.gitignore +2 -0
- data/.gitmodules +3 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.rdoc +109 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +82 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +180 -53
- data/Rakefile +27 -0
- data/lib/generators/simple_form/USAGE +1 -1
- data/lib/generators/simple_form/install_generator.rb +5 -6
- data/lib/generators/simple_form/templates/_form.html.erb +2 -12
- data/lib/generators/simple_form/templates/_form.html.haml +10 -0
- data/lib/generators/simple_form/templates/_form.html.slim +10 -0
- data/lib/generators/simple_form/templates/en.yml +14 -0
- data/lib/generators/simple_form/templates/simple_form.rb +66 -12
- data/lib/simple_form/action_view_extensions/builder.rb +99 -40
- data/lib/simple_form/action_view_extensions/form_helper.rb +29 -6
- data/lib/simple_form/components/errors.rb +16 -6
- data/lib/simple_form/components/hints.rb +2 -2
- data/lib/simple_form/components/label_input.rb +13 -0
- data/lib/simple_form/components/labels.rb +5 -7
- data/lib/simple_form/components/placeholders.rb +22 -0
- data/lib/simple_form/components/wrapper.rb +19 -2
- data/lib/simple_form/components.rb +6 -4
- data/lib/simple_form/error_notification.rb +42 -0
- data/lib/simple_form/form_builder.rb +187 -72
- data/lib/simple_form/has_errors.rb +14 -0
- data/lib/simple_form/inputs/base.rb +106 -24
- data/lib/simple_form/inputs/block_input.rb +3 -2
- data/lib/simple_form/inputs/boolean_input.rb +22 -0
- data/lib/simple_form/inputs/collection_input.rb +46 -17
- data/lib/simple_form/inputs/date_time_input.rb +11 -5
- data/lib/simple_form/inputs/hidden_input.rb +11 -2
- data/lib/simple_form/inputs/mapping_input.rb +12 -6
- data/lib/simple_form/inputs/numeric_input.rb +55 -6
- data/lib/simple_form/inputs/priority_input.rb +5 -1
- data/lib/simple_form/inputs/string_input.rb +25 -11
- data/lib/simple_form/inputs.rb +1 -0
- data/lib/simple_form/map_type.rb +9 -6
- data/lib/simple_form/version.rb +1 -1
- data/lib/simple_form.rb +92 -8
- data/simple_form.gemspec +22 -0
- data/test/action_view_extensions/builder_test.rb +187 -51
- data/test/action_view_extensions/form_helper_test.rb +17 -5
- data/test/components/error_test.rb +23 -12
- data/test/components/hint_test.rb +4 -8
- data/test/components/label_test.rb +79 -11
- data/test/components/wrapper_test.rb +63 -0
- data/test/discovery_inputs.rb +21 -0
- data/test/error_notification_test.rb +62 -0
- data/test/form_builder_test.rb +332 -35
- data/test/inputs_test.rb +516 -53
- data/test/support/misc_helpers.rb +32 -4
- data/test/support/mock_controller.rb +4 -4
- data/test/support/models.rb +75 -11
- data/test/test_helper.rb +28 -12
- metadata +51 -11
|
@@ -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
|
-
|
|
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
|
-
|
|
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(@<%=
|
|
2
|
-
|
|
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
|
-
#
|
|
5
|
-
#
|
|
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
|
-
#
|
|
20
|
-
# config.
|
|
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
|
-
#
|
|
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.
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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,
|
|
45
|
-
# with a clickable label. Use value_method and text_method to
|
|
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.
|
|
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="
|
|
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="
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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(
|
|
81
|
-
end
|
|
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
|
-
|
|
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
|
-
|
|
110
|
+
private
|
|
100
111
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
else
|
|
111
|
-
Array(options[option]).include?(value)
|
|
112
|
-
end
|
|
117
|
+
[:checked, :disabled].each do |option|
|
|
118
|
+
next unless options[option]
|
|
113
119
|
|
|
114
|
-
|
|
115
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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]
|
|
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][:
|
|
25
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
37
|
+
object.errors[attribute_name]
|
|
28
38
|
end
|
|
29
39
|
|
|
30
40
|
def errors_on_association
|
|
31
|
-
reflection ?
|
|
41
|
+
reflection ? object.errors[reflection.name] : []
|
|
32
42
|
end
|
|
33
43
|
end
|
|
34
44
|
end
|
|
35
|
-
end
|
|
45
|
+
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
|
|
55
|
+
# First check labels translation and then human attribute name.
|
|
56
56
|
def label_translation #:nodoc:
|
|
57
|
-
|
|
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
|
-
|
|
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,
|
|
4
|
-
autoload :Hints,
|
|
5
|
-
autoload :
|
|
6
|
-
autoload :
|
|
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
|