comfy_bootstrap_form 4.0.0.beta1
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +621 -0
- data/Rakefile +37 -0
- data/app/assets/stylesheets/rails_bootstrap_forms.css +10 -0
- data/lib/bootstrap_form.rb +13 -0
- data/lib/bootstrap_form/aliasing.rb +35 -0
- data/lib/bootstrap_form/form_builder.rb +460 -0
- data/lib/bootstrap_form/helper.rb +36 -0
- data/lib/bootstrap_form/helpers/bootstrap.rb +94 -0
- data/lib/bootstrap_form/helpers/nested_form.rb +33 -0
- data/lib/bootstrap_form/version.rb +3 -0
- data/lib/comfy_bootstrap_form.rb +1 -0
- data/test/bootstrap_checkbox_test.rb +144 -0
- data/test/bootstrap_fields_test.rb +152 -0
- data/test/bootstrap_form_group_test.rb +313 -0
- data/test/bootstrap_form_test.rb +276 -0
- data/test/bootstrap_other_components_test.rb +86 -0
- data/test/bootstrap_radio_button_test.rb +124 -0
- data/test/bootstrap_selects_test.rb +160 -0
- data/test/dummy/Gemfile +45 -0
- data/test/dummy/Gemfile.lock +120 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +10 -0
- data/test/dummy/app/assets/javascripts/application.js +16 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/address.rb +3 -0
- data/test/dummy/app/models/faux_user.rb +9 -0
- data/test/dummy/app/models/super_user.rb +2 -0
- data/test/dummy/app/models/user.rb +9 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +4 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +53 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/generic_migration.rb +6 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/migrate/20130703191909_create_users.rb +13 -0
- data/test/dummy/db/migrate/20130703191937_create_addresses.rb +13 -0
- data/test/dummy/db/migrate/20130912171202_add_preferences_to_user.rb +5 -0
- data/test/dummy/db/migrate/20140327190145_add_terms_to_user.rb +5 -0
- data/test/dummy/db/migrate/20140922133133_add_type_to_users.rb +5 -0
- data/test/dummy/db/schema.rb +38 -0
- data/test/dummy/db/seeds.rb +7 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +18394 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/robots.txt +5 -0
- data/test/dummy/test/fixtures/addresses.yml +15 -0
- data/test/dummy/test/fixtures/users.yml +15 -0
- data/test/dummy/test/models/address_test.rb +7 -0
- data/test/dummy/test/models/user_test.rb +7 -0
- data/test/dummy/test/test_helper.rb +15 -0
- data/test/special_form_class_models_test.rb +43 -0
- data/test/test_helper.rb +86 -0
- metadata +309 -0
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'BootstrapForm'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
task :default => :test
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module BootstrapForm
|
2
|
+
# This module implements the old ActiveSupport alias_method_chain feature
|
3
|
+
# with a new name, and without the deprecation warnings. In ActiveSupport 5+,
|
4
|
+
# this style of patching was deprecated in favor of Module.prepend. But
|
5
|
+
# Module.prepend is not present in Ruby 1.9, which we would still like to
|
6
|
+
# support. So we continue to use of alias_method_chain, albeit with a
|
7
|
+
# different name to avoid collisions.
|
8
|
+
module Aliasing
|
9
|
+
# This code is copied and pasted from ActiveSupport, but with :bootstrap
|
10
|
+
# hardcoded as the feature name, and with the deprecation warning removed.
|
11
|
+
def bootstrap_method_alias(target)
|
12
|
+
feature = :bootstrap
|
13
|
+
|
14
|
+
# Strip out punctuation on predicates, bang or writer methods since
|
15
|
+
# e.g. target?_without_feature is not a valid method name.
|
16
|
+
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
17
|
+
yield(aliased_target, punctuation) if block_given?
|
18
|
+
|
19
|
+
with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
|
20
|
+
without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
|
21
|
+
|
22
|
+
alias_method without_method, target
|
23
|
+
alias_method target, with_method
|
24
|
+
|
25
|
+
case
|
26
|
+
when public_method_defined?(without_method)
|
27
|
+
public target
|
28
|
+
when protected_method_defined?(without_method)
|
29
|
+
protected target
|
30
|
+
when private_method_defined?(without_method)
|
31
|
+
private target
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,460 @@
|
|
1
|
+
require_relative 'aliasing'
|
2
|
+
require_relative 'helpers/bootstrap'
|
3
|
+
|
4
|
+
module BootstrapForm
|
5
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
6
|
+
extend BootstrapForm::Aliasing
|
7
|
+
include BootstrapForm::Helpers::Bootstrap
|
8
|
+
|
9
|
+
attr_reader :layout, :label_col, :control_col, :has_error, :inline_errors, :label_errors, :acts_like_form_tag
|
10
|
+
|
11
|
+
FIELD_HELPERS = %w{color_field date_field datetime_field datetime_local_field
|
12
|
+
email_field month_field number_field password_field phone_field
|
13
|
+
range_field search_field telephone_field text_area text_field time_field
|
14
|
+
url_field week_field}
|
15
|
+
|
16
|
+
DATE_SELECT_HELPERS = %w{date_select time_select datetime_select}
|
17
|
+
|
18
|
+
delegate :content_tag, :capture, :concat, to: :@template
|
19
|
+
|
20
|
+
def initialize(object_name, object, template, options)
|
21
|
+
@layout = options[:layout]
|
22
|
+
@label_col = options[:label_col] || default_label_col
|
23
|
+
@control_col = options[:control_col] || default_control_col
|
24
|
+
@label_errors = options[:label_errors] || false
|
25
|
+
@inline_errors = if options[:inline_errors].nil?
|
26
|
+
@label_errors != true
|
27
|
+
else
|
28
|
+
options[:inline_errors] != false
|
29
|
+
end
|
30
|
+
@acts_like_form_tag = options[:acts_like_form_tag]
|
31
|
+
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
FIELD_HELPERS.each do |method_name|
|
36
|
+
with_method_name = "#{method_name}_with_bootstrap"
|
37
|
+
without_method_name = "#{method_name}_without_bootstrap"
|
38
|
+
|
39
|
+
define_method(with_method_name) do |name, options = {}|
|
40
|
+
form_group_builder(name, options) do
|
41
|
+
prepend_and_append_input(options) do
|
42
|
+
send(without_method_name, name, options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
bootstrap_method_alias method_name
|
48
|
+
end
|
49
|
+
|
50
|
+
DATE_SELECT_HELPERS.each do |method_name|
|
51
|
+
with_method_name = "#{method_name}_with_bootstrap"
|
52
|
+
without_method_name = "#{method_name}_without_bootstrap"
|
53
|
+
|
54
|
+
define_method(with_method_name) do |name, options = {}, html_options = {}|
|
55
|
+
form_group_builder(name, options, html_options) do
|
56
|
+
content_tag(:div, send(without_method_name, name, options, html_options), class: control_specific_class(method_name))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
bootstrap_method_alias method_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def file_field_with_bootstrap(name, options = {})
|
64
|
+
form_group_builder(name, options.reverse_merge(control_class: nil)) do
|
65
|
+
file_field_without_bootstrap(name, options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
bootstrap_method_alias :file_field
|
70
|
+
|
71
|
+
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new("4.1.0")
|
72
|
+
def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block)
|
73
|
+
form_group_builder(method, options, html_options) do
|
74
|
+
prepend_and_append_input(options) do
|
75
|
+
select_without_bootstrap(method, choices, options, html_options, &block)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
def select_with_bootstrap(method, choices, options = {}, html_options = {})
|
81
|
+
form_group_builder(method, options, html_options) do
|
82
|
+
prepend_and_append_input(options) do
|
83
|
+
select_without_bootstrap(method, choices, options, html_options)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
bootstrap_method_alias :select
|
90
|
+
|
91
|
+
def collection_select_with_bootstrap(method, collection, value_method, text_method, options = {}, html_options = {})
|
92
|
+
form_group_builder(method, options, html_options) do
|
93
|
+
collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
bootstrap_method_alias :collection_select
|
98
|
+
|
99
|
+
def grouped_collection_select_with_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
|
100
|
+
form_group_builder(method, options, html_options) do
|
101
|
+
grouped_collection_select_without_bootstrap(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
bootstrap_method_alias :grouped_collection_select
|
106
|
+
|
107
|
+
def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {}, html_options = {})
|
108
|
+
form_group_builder(method, options, html_options) do
|
109
|
+
time_zone_select_without_bootstrap(method, priority_zones, options, html_options)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
bootstrap_method_alias :time_zone_select
|
114
|
+
|
115
|
+
def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_value = "0", &block)
|
116
|
+
options = options.symbolize_keys!
|
117
|
+
check_box_options = options.except(:label, :label_class, :help, :inline)
|
118
|
+
check_box_options[:class] = ["form-check-input", check_box_options[:class]].compact.join(' ')
|
119
|
+
|
120
|
+
html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value)
|
121
|
+
label_content = block_given? ? capture(&block) : options[:label]
|
122
|
+
html.concat(" ").concat(label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize)
|
123
|
+
|
124
|
+
label_name = name
|
125
|
+
# label's `for` attribute needs to match checkbox tag's id,
|
126
|
+
# IE sanitized value, IE
|
127
|
+
# https://github.com/rails/rails/blob/c57e7239a8b82957bcb07534cb7c1a3dcef71864/actionview/lib/action_view/helpers/tags/base.rb#L116-L118
|
128
|
+
if options[:multiple]
|
129
|
+
label_name =
|
130
|
+
"#{name}_#{checked_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}"
|
131
|
+
end
|
132
|
+
|
133
|
+
disabled_class = " disabled" if options[:disabled]
|
134
|
+
label_class = options[:label_class]
|
135
|
+
|
136
|
+
if options[:inline]
|
137
|
+
label_class = " #{label_class}" if label_class
|
138
|
+
label(label_name, html, class: "form-check-inline#{disabled_class}#{label_class}")
|
139
|
+
else
|
140
|
+
content_tag(:div, class: "form-check#{disabled_class}") do
|
141
|
+
label(label_name, html, class: ["form-check-label", label_class].compact.join(" "))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
bootstrap_method_alias :check_box
|
147
|
+
|
148
|
+
def radio_button_with_bootstrap(name, value, *args)
|
149
|
+
options = args.extract_options!.symbolize_keys!
|
150
|
+
args << options.except(:label, :label_class, :help, :inline)
|
151
|
+
|
152
|
+
html = radio_button_without_bootstrap(name, value, *args) + " " + options[:label]
|
153
|
+
|
154
|
+
disabled_class = " disabled" if options[:disabled]
|
155
|
+
label_class = options[:label_class]
|
156
|
+
|
157
|
+
if options[:inline]
|
158
|
+
label_class = " #{label_class}" if label_class
|
159
|
+
label(name, html, class: "radio-inline#{disabled_class}#{label_class}", value: value)
|
160
|
+
else
|
161
|
+
content_tag(:div, class: "radio#{disabled_class}") do
|
162
|
+
label(name, html, value: value, class: label_class)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
bootstrap_method_alias :radio_button
|
168
|
+
|
169
|
+
def collection_check_boxes_with_bootstrap(*args)
|
170
|
+
html = inputs_collection(*args) do |name, value, options|
|
171
|
+
options[:multiple] = true
|
172
|
+
check_box(name, options, value, nil)
|
173
|
+
end
|
174
|
+
hidden_field(args.first,{value: "", multiple: true}).concat(html)
|
175
|
+
end
|
176
|
+
|
177
|
+
bootstrap_method_alias :collection_check_boxes
|
178
|
+
|
179
|
+
def collection_radio_buttons_with_bootstrap(*args)
|
180
|
+
inputs_collection(*args) do |name, value, options|
|
181
|
+
radio_button(name, value, options)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
bootstrap_method_alias :collection_radio_buttons
|
186
|
+
|
187
|
+
def check_boxes_collection(*args)
|
188
|
+
warn "'BootstrapForm#check_boxes_collection' is deprecated, use 'BootstrapForm#collection_check_boxes' instead"
|
189
|
+
collection_check_boxes(*args)
|
190
|
+
end
|
191
|
+
|
192
|
+
def radio_buttons_collection(*args)
|
193
|
+
warn "'BootstrapForm#radio_buttons_collection' is deprecated, use 'BootstrapForm#collection_radio_buttons' instead"
|
194
|
+
collection_radio_buttons(*args)
|
195
|
+
end
|
196
|
+
|
197
|
+
def form_group(*args, &block)
|
198
|
+
options = args.extract_options!
|
199
|
+
name = args.first
|
200
|
+
|
201
|
+
options[:class] = ["form-group", options[:class]].compact.join(' ')
|
202
|
+
options[:class] << " row" if get_group_layout(options[:layout]) == :horizontal
|
203
|
+
options[:class] << " #{error_class}" if has_error?(name)
|
204
|
+
options[:class] << " #{feedback_class}" if options[:icon]
|
205
|
+
|
206
|
+
content_tag(:div, options.except(:id, :label, :help, :icon, :label_col, :control_col, :layout)) do
|
207
|
+
label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label]
|
208
|
+
control = capture(&block).to_s
|
209
|
+
control.concat(generate_help(name, options[:help]).to_s)
|
210
|
+
control.concat(generate_icon(options[:icon])) if options[:icon]
|
211
|
+
|
212
|
+
if get_group_layout(options[:layout]) == :horizontal
|
213
|
+
control_class = options[:control_col] || control_col
|
214
|
+
unless options[:label]
|
215
|
+
control_offset = offset_col(options[:label_col] || @label_col)
|
216
|
+
control_class = "#{control_class} #{control_offset}"
|
217
|
+
end
|
218
|
+
control = content_tag(:div, control, class: control_class)
|
219
|
+
end
|
220
|
+
|
221
|
+
concat(label).concat(control)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def fields_for_with_bootstrap(record_name, record_object = nil, fields_options = {}, &block)
|
226
|
+
fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
|
227
|
+
fields_options[:layout] ||= options[:layout]
|
228
|
+
fields_options[:label_col] = fields_options[:label_col].present? ? "#{fields_options[:label_col]} #{label_class}" : options[:label_col]
|
229
|
+
fields_options[:control_col] ||= options[:control_col]
|
230
|
+
fields_options[:inline_errors] ||= options[:inline_errors]
|
231
|
+
fields_options[:label_errors] ||= options[:label_errors]
|
232
|
+
fields_for_without_bootstrap(record_name, record_object, fields_options, &block)
|
233
|
+
end
|
234
|
+
|
235
|
+
bootstrap_method_alias :fields_for
|
236
|
+
|
237
|
+
private
|
238
|
+
|
239
|
+
def horizontal?
|
240
|
+
layout == :horizontal
|
241
|
+
end
|
242
|
+
|
243
|
+
def get_group_layout(group_layout)
|
244
|
+
group_layout || layout
|
245
|
+
end
|
246
|
+
|
247
|
+
def default_label_col
|
248
|
+
"col-sm-2"
|
249
|
+
end
|
250
|
+
|
251
|
+
def offset_col(label_col)
|
252
|
+
label_col.sub(/^col-(\w+)-(\d)$/, 'col-\1-offset-\2')
|
253
|
+
end
|
254
|
+
|
255
|
+
def default_control_col
|
256
|
+
"col-sm-10"
|
257
|
+
end
|
258
|
+
|
259
|
+
def hide_class
|
260
|
+
"sr-only" # still accessible for screen readers
|
261
|
+
end
|
262
|
+
|
263
|
+
def control_class
|
264
|
+
"form-control"
|
265
|
+
end
|
266
|
+
|
267
|
+
def label_class
|
268
|
+
"form-control-label"
|
269
|
+
end
|
270
|
+
|
271
|
+
def error_class
|
272
|
+
"has-danger"
|
273
|
+
end
|
274
|
+
|
275
|
+
def feedback_class
|
276
|
+
"has-feedback"
|
277
|
+
end
|
278
|
+
|
279
|
+
def control_specific_class(method)
|
280
|
+
"rails-bootstrap-forms-#{method.gsub(/_/, "-")}"
|
281
|
+
end
|
282
|
+
|
283
|
+
def has_error?(name)
|
284
|
+
object.respond_to?(:errors) && !(name.nil? || object.errors[name].empty?)
|
285
|
+
end
|
286
|
+
|
287
|
+
def required_attribute?(obj, attribute)
|
288
|
+
|
289
|
+
return false unless obj and attribute
|
290
|
+
|
291
|
+
target = (obj.class == Class) ? obj : obj.class
|
292
|
+
|
293
|
+
target_validators = if target.respond_to? :validators_on
|
294
|
+
target.validators_on(attribute).map(&:class)
|
295
|
+
else
|
296
|
+
[]
|
297
|
+
end
|
298
|
+
|
299
|
+
has_presence_validator = target_validators.include?(
|
300
|
+
ActiveModel::Validations::PresenceValidator)
|
301
|
+
|
302
|
+
if defined? ActiveRecord::Validations::PresenceValidator
|
303
|
+
has_presence_validator |= target_validators.include?(
|
304
|
+
ActiveRecord::Validations::PresenceValidator)
|
305
|
+
end
|
306
|
+
|
307
|
+
has_presence_validator
|
308
|
+
end
|
309
|
+
|
310
|
+
def form_group_builder(method, options, html_options = nil)
|
311
|
+
options.symbolize_keys!
|
312
|
+
html_options.symbolize_keys! if html_options
|
313
|
+
|
314
|
+
# Add control_class; allow it to be overridden by :control_class option
|
315
|
+
css_options = html_options || options
|
316
|
+
control_classes = css_options.delete(:control_class) { control_class }
|
317
|
+
css_options[:class] = [control_classes, css_options[:class]].compact.join(" ")
|
318
|
+
css_options[:class] << " is-invalid" if has_error?(method)
|
319
|
+
|
320
|
+
options = convert_form_tag_options(method, options) if acts_like_form_tag
|
321
|
+
|
322
|
+
wrapper_class = css_options.delete(:wrapper_class)
|
323
|
+
wrapper_options = css_options.delete(:wrapper)
|
324
|
+
help = options.delete(:help)
|
325
|
+
icon = options.delete(:icon)
|
326
|
+
label_col = options.delete(:label_col)
|
327
|
+
control_col = options.delete(:control_col)
|
328
|
+
layout = get_group_layout(options.delete(:layout))
|
329
|
+
form_group_options = {
|
330
|
+
id: options[:id],
|
331
|
+
help: help,
|
332
|
+
icon: icon,
|
333
|
+
label_col: label_col,
|
334
|
+
control_col: control_col,
|
335
|
+
layout: layout,
|
336
|
+
class: wrapper_class
|
337
|
+
}
|
338
|
+
|
339
|
+
if wrapper_options.is_a?(Hash)
|
340
|
+
form_group_options.merge!(wrapper_options)
|
341
|
+
end
|
342
|
+
|
343
|
+
unless options.delete(:skip_label)
|
344
|
+
if options[:label].is_a?(Hash)
|
345
|
+
label_text = options[:label].delete(:text)
|
346
|
+
label_class = options[:label].delete(:class)
|
347
|
+
options.delete(:label)
|
348
|
+
end
|
349
|
+
label_class ||= options.delete(:label_class)
|
350
|
+
label_class = hide_class if options.delete(:hide_label)
|
351
|
+
|
352
|
+
if options[:label].is_a?(String)
|
353
|
+
label_text ||= options.delete(:label)
|
354
|
+
end
|
355
|
+
|
356
|
+
form_group_options.merge!(label: {
|
357
|
+
text: label_text,
|
358
|
+
class: label_class,
|
359
|
+
skip_required: options.delete(:skip_required)
|
360
|
+
})
|
361
|
+
end
|
362
|
+
|
363
|
+
form_group(method, form_group_options) do
|
364
|
+
yield
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def convert_form_tag_options(method, options = {})
|
369
|
+
options[:name] ||= method
|
370
|
+
options[:id] ||= method
|
371
|
+
options
|
372
|
+
end
|
373
|
+
|
374
|
+
def generate_label(id, name, options, custom_label_col, group_layout)
|
375
|
+
options[:for] = id if acts_like_form_tag
|
376
|
+
classes = [options[:class], label_class]
|
377
|
+
classes << (custom_label_col || label_col) if get_group_layout(group_layout) == :horizontal
|
378
|
+
unless options.delete(:skip_required)
|
379
|
+
classes << "required" if required_attribute?(object, name)
|
380
|
+
end
|
381
|
+
|
382
|
+
options[:class] = classes.compact.join(" ")
|
383
|
+
|
384
|
+
if label_errors && has_error?(name)
|
385
|
+
error_messages = get_error_messages(name)
|
386
|
+
label_text = (options[:text] || object.class.human_attribute_name(name)).to_s.concat(" #{error_messages}")
|
387
|
+
label(name, label_text, options.except(:text))
|
388
|
+
else
|
389
|
+
label(name, options[:text], options.except(:text))
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
|
394
|
+
def generate_help(name, help_text)
|
395
|
+
if has_error?(name) && inline_errors
|
396
|
+
help_text = get_error_messages(name)
|
397
|
+
help_klass = 'invalid-feedback'
|
398
|
+
end
|
399
|
+
return if help_text == false
|
400
|
+
|
401
|
+
help_klass ||= 'form-text text-muted'
|
402
|
+
help_text ||= get_help_text_by_i18n_key(name)
|
403
|
+
|
404
|
+
content_tag(:span, help_text, class: help_klass) if help_text.present?
|
405
|
+
end
|
406
|
+
|
407
|
+
def generate_icon(icon)
|
408
|
+
content_tag(:span, "", class: "glyphicon glyphicon-#{icon} form-control-feedback")
|
409
|
+
end
|
410
|
+
|
411
|
+
def get_error_messages(name)
|
412
|
+
object.errors[name].join(", ")
|
413
|
+
end
|
414
|
+
|
415
|
+
def inputs_collection(name, collection, value, text, options = {}, &block)
|
416
|
+
form_group_builder(name, options) do
|
417
|
+
inputs = ""
|
418
|
+
|
419
|
+
collection.each do |obj|
|
420
|
+
input_options = options.merge(label: text.respond_to?(:call) ? text.call(obj) : obj.send(text))
|
421
|
+
|
422
|
+
input_value = value.respond_to?(:call) ? value.call(obj) : obj.send(value)
|
423
|
+
if checked = input_options[:checked]
|
424
|
+
input_options[:checked] = checked == input_value ||
|
425
|
+
Array(checked).try(:include?, input_value) ||
|
426
|
+
checked == obj ||
|
427
|
+
Array(checked).try(:include?, obj)
|
428
|
+
end
|
429
|
+
|
430
|
+
input_options.delete(:class)
|
431
|
+
inputs << block.call(name, input_value, input_options)
|
432
|
+
end
|
433
|
+
|
434
|
+
inputs.html_safe
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
def get_help_text_by_i18n_key(name)
|
439
|
+
if object
|
440
|
+
|
441
|
+
if object.class.respond_to?(:model_name)
|
442
|
+
# ActiveModel::Naming 3.X.X does not support .name; it is supported as of 4.X.X
|
443
|
+
partial_scope = object.class.model_name.respond_to?(:name) ? object.class.model_name.name : object.class.model_name
|
444
|
+
else
|
445
|
+
partial_scope = object.class.name
|
446
|
+
end
|
447
|
+
|
448
|
+
underscored_scope = "activerecord.help.#{partial_scope.underscore}"
|
449
|
+
downcased_scope = "activerecord.help.#{partial_scope.downcase}"
|
450
|
+
help_text = I18n.t(name, scope: underscored_scope, default: '').presence
|
451
|
+
help_text ||= if text = I18n.t(name, scope: downcased_scope, default: '').presence
|
452
|
+
warn "I18n key '#{downcased_scope}.#{name}' is deprecated, use '#{underscored_scope}.#{name}' instead"
|
453
|
+
text
|
454
|
+
end
|
455
|
+
help_text
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
end
|