bootstrap_form 4.1.0 → 4.2.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.
- checksums.yaml +4 -4
- data/.gitignore +18 -0
- data/.rubocop.yml +3 -2
- data/.travis.yml +7 -1
- data/CHANGELOG.md +15 -1
- data/CONTRIBUTING.md +11 -0
- data/Dangerfile +4 -4
- data/Gemfile +7 -2
- data/OLD-README.md +795 -0
- data/README.md +150 -93
- data/Rakefile +2 -4
- data/bootstrap_form.gemspec +2 -1
- data/demo/.postcssrc.yml +3 -0
- data/demo/app/assets/config/manifest.js +2 -0
- data/demo/app/assets/stylesheets/actiontext.scss +38 -0
- data/demo/app/assets/stylesheets/application.scss +1 -0
- data/demo/app/helpers/bootstrap_helper.rb +16 -10
- data/demo/app/javascript/channels/consumer.js +6 -0
- data/demo/app/javascript/channels/index.js +5 -0
- data/demo/app/javascript/packs/application.js +11 -0
- data/demo/app/models/user.rb +2 -0
- data/demo/app/views/active_storage/blobs/_blob.html.erb +14 -0
- data/demo/app/views/bootstrap/form.html.erb +2 -1
- data/demo/app/views/layouts/application.html.erb +3 -0
- data/demo/bin/webpack +15 -0
- data/demo/bin/webpack-dev-server +15 -0
- data/demo/config/application.rb +2 -3
- data/demo/config/environments/development.rb +3 -1
- data/demo/config/environments/production.rb +48 -0
- data/demo/config/webpack/development.js +5 -0
- data/demo/config/webpack/environment.js +3 -0
- data/demo/config/webpack/production.js +5 -0
- data/demo/config/webpack/test.js +5 -0
- data/demo/config/webpacker.yml +92 -0
- data/demo/db/schema.rb +63 -18
- data/demo/package.json +13 -1
- data/demo/test/fixtures/action_text/rich_texts.yml +4 -0
- data/demo/yarn.lock +6257 -0
- data/lib/bootstrap_form.rb +34 -8
- data/lib/bootstrap_form/action_view_extensions/form_helper.rb +71 -0
- data/lib/bootstrap_form/components.rb +17 -0
- data/lib/bootstrap_form/components/hints.rb +60 -0
- data/lib/bootstrap_form/components/labels.rb +56 -0
- data/lib/bootstrap_form/components/layout.rb +39 -0
- data/lib/bootstrap_form/components/validation.rb +61 -0
- data/lib/bootstrap_form/engine.rb +10 -0
- data/lib/bootstrap_form/form_builder.rb +54 -524
- data/lib/bootstrap_form/form_group.rb +64 -0
- data/lib/bootstrap_form/form_group_builder.rb +103 -0
- data/lib/bootstrap_form/helpers.rb +9 -0
- data/lib/bootstrap_form/helpers/bootstrap.rb +39 -31
- data/lib/bootstrap_form/inputs.rb +40 -0
- data/lib/bootstrap_form/inputs/base.rb +40 -0
- data/lib/bootstrap_form/inputs/check_box.rb +89 -0
- data/lib/bootstrap_form/inputs/collection_check_boxes.rb +23 -0
- data/lib/bootstrap_form/inputs/collection_radio_buttons.rb +21 -0
- data/lib/bootstrap_form/inputs/collection_select.rb +25 -0
- data/lib/bootstrap_form/inputs/color_field.rb +14 -0
- data/lib/bootstrap_form/inputs/date_field.rb +14 -0
- data/lib/bootstrap_form/inputs/date_select.rb +14 -0
- data/lib/bootstrap_form/inputs/datetime_field.rb +14 -0
- data/lib/bootstrap_form/inputs/datetime_local_field.rb +14 -0
- data/lib/bootstrap_form/inputs/datetime_select.rb +14 -0
- data/lib/bootstrap_form/inputs/email_field.rb +14 -0
- data/lib/bootstrap_form/inputs/file_field.rb +35 -0
- data/lib/bootstrap_form/inputs/grouped_collection_select.rb +29 -0
- data/lib/bootstrap_form/inputs/inputs_collection.rb +44 -0
- data/lib/bootstrap_form/inputs/month_field.rb +14 -0
- data/lib/bootstrap_form/inputs/number_field.rb +14 -0
- data/lib/bootstrap_form/inputs/password_field.rb +14 -0
- data/lib/bootstrap_form/inputs/phone_field.rb +14 -0
- data/lib/bootstrap_form/inputs/radio_button.rb +77 -0
- data/lib/bootstrap_form/inputs/range_field.rb +14 -0
- data/lib/bootstrap_form/inputs/rich_text_area.rb +23 -0
- data/lib/bootstrap_form/inputs/search_field.rb +14 -0
- data/lib/bootstrap_form/inputs/select.rb +22 -0
- data/lib/bootstrap_form/inputs/telephone_field.rb +14 -0
- data/lib/bootstrap_form/inputs/text_area.rb +14 -0
- data/lib/bootstrap_form/inputs/text_field.rb +14 -0
- data/lib/bootstrap_form/inputs/time_field.rb +14 -0
- data/lib/bootstrap_form/inputs/time_select.rb +14 -0
- data/lib/bootstrap_form/inputs/time_zone_select.rb +22 -0
- data/lib/bootstrap_form/inputs/url_field.rb +14 -0
- data/lib/bootstrap_form/inputs/week_field.rb +14 -0
- data/lib/bootstrap_form/version.rb +1 -1
- metadata +79 -6
- data/.rubocop_todo.yml +0 -104
- data/lib/bootstrap_form/aliasing.rb +0 -35
- data/lib/bootstrap_form/helper.rb +0 -52
data/lib/bootstrap_form.rb
CHANGED
@@ -1,13 +1,39 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# NOTE: The rich_text_area and rich_text_area_tag helpers are defined in a file with a different
|
2
|
+
# name and not in the usual autoload-reachable way.
|
3
|
+
# The following line is definitely need to make `bootstrap_form` work.
|
4
|
+
if ::Rails::VERSION::STRING > "6"
|
5
|
+
require Gem::Specification.find_by_name("actiontext").gem_dir + # rubocop:disable Rails/DynamicFindBy
|
6
|
+
"/app/helpers/action_text/tag_helper"
|
7
|
+
end
|
8
|
+
require "action_view"
|
9
|
+
require "action_pack"
|
10
|
+
require "bootstrap_form/action_view_extensions/form_helper"
|
3
11
|
|
4
12
|
module BootstrapForm
|
5
|
-
|
6
|
-
|
7
|
-
|
13
|
+
extend ActiveSupport::Autoload
|
14
|
+
|
15
|
+
eager_autoload do
|
16
|
+
autoload :FormBuilder
|
17
|
+
autoload :FormGroupBuilder
|
18
|
+
autoload :FormGroup
|
19
|
+
autoload :Components
|
20
|
+
autoload :Inputs
|
21
|
+
autoload :Helpers
|
8
22
|
end
|
9
|
-
end
|
10
23
|
|
11
|
-
|
12
|
-
|
24
|
+
def self.eager_load!
|
25
|
+
super
|
26
|
+
BootstrapForm::Components.eager_load!
|
27
|
+
BootstrapForm::Helpers.eager_load!
|
28
|
+
BootstrapForm::Inputs.eager_load!
|
29
|
+
end
|
30
|
+
|
31
|
+
mattr_accessor :field_error_proc
|
32
|
+
# rubocop:disable Style/ClassVars
|
33
|
+
@@field_error_proc = proc do |html_tag, _instance_tag|
|
34
|
+
html_tag
|
35
|
+
end
|
36
|
+
# rubocop:enable Style/ClassVars
|
13
37
|
end
|
38
|
+
|
39
|
+
require "bootstrap_form/engine" if defined?(Rails)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BootstrapForm
|
4
|
+
module ActionViewExtensions
|
5
|
+
# This module creates BootstrapForm wrappers around the default form_with
|
6
|
+
# and form_for methods
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# bootstrap_form_for @user do |f|
|
11
|
+
# f.text_field :name
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# bootstrap_form_with model: @user do |f|
|
17
|
+
# f.text_field :name
|
18
|
+
# end
|
19
|
+
module FormHelper
|
20
|
+
def bootstrap_form_for(record, options={}, &block)
|
21
|
+
options.reverse_merge!(builder: BootstrapForm::FormBuilder)
|
22
|
+
|
23
|
+
options = process_options(options)
|
24
|
+
|
25
|
+
with_bootstrap_form_field_error_proc do
|
26
|
+
form_for(record, options, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def bootstrap_form_with(options={}, &block)
|
31
|
+
options.reverse_merge!(builder: BootstrapForm::FormBuilder)
|
32
|
+
|
33
|
+
options = process_options(options)
|
34
|
+
|
35
|
+
with_bootstrap_form_field_error_proc do
|
36
|
+
form_with(options, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def bootstrap_form_tag(options={}, &block)
|
41
|
+
options[:acts_like_form_tag] = true
|
42
|
+
|
43
|
+
bootstrap_form_for("", options, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def process_options(options)
|
49
|
+
options[:html] ||= {}
|
50
|
+
options[:html][:role] ||= "form"
|
51
|
+
|
52
|
+
options[:layout] == :inline &&
|
53
|
+
options[:html][:class] = [options[:html][:class], "form-inline"].compact.join(" ")
|
54
|
+
|
55
|
+
options
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_bootstrap_form_field_error_proc
|
59
|
+
original_proc = ActionView::Base.field_error_proc
|
60
|
+
ActionView::Base.field_error_proc = BootstrapForm.field_error_proc
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
ActionView::Base.field_error_proc = original_proc
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
ActiveSupport.on_load(:action_view) do
|
70
|
+
include BootstrapForm::ActionViewExtensions::FormHelper
|
71
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BootstrapForm
|
4
|
+
module Components
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
autoload :Hints
|
8
|
+
autoload :Labels
|
9
|
+
autoload :Layout
|
10
|
+
autoload :Validation
|
11
|
+
|
12
|
+
include Hints
|
13
|
+
include Labels
|
14
|
+
include Layout
|
15
|
+
include Validation
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BootstrapForm
|
4
|
+
module Components
|
5
|
+
module Hints
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def generate_help(name, help_text)
|
11
|
+
return if help_text == false || inline_error?(name)
|
12
|
+
|
13
|
+
help_klass ||= "form-text text-muted"
|
14
|
+
help_text ||= get_help_text_by_i18n_key(name)
|
15
|
+
help_tag ||= :small
|
16
|
+
|
17
|
+
content_tag(help_tag, help_text, class: help_klass) if help_text.present?
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_help_text_by_i18n_key(name)
|
21
|
+
return unless object
|
22
|
+
|
23
|
+
partial_scope = if object.class.respond_to?(:model_name)
|
24
|
+
object.class.model_name.name
|
25
|
+
else
|
26
|
+
object.class.name
|
27
|
+
end
|
28
|
+
|
29
|
+
# First check for a subkey :html, as it is also accepted by i18n, and the
|
30
|
+
# simple check for name would return an hash instead of a string (both
|
31
|
+
# with .presence returning true!)
|
32
|
+
help_text = nil
|
33
|
+
["#{name}.html", name, "#{name}_html"].each do |scope|
|
34
|
+
break if help_text
|
35
|
+
|
36
|
+
help_text = scoped_help_text(scope, partial_scope)
|
37
|
+
end
|
38
|
+
help_text
|
39
|
+
end
|
40
|
+
|
41
|
+
def scoped_help_text(name, partial_scope)
|
42
|
+
underscored_scope = "activerecord.help.#{partial_scope.underscore}"
|
43
|
+
downcased_scope = "activerecord.help.#{partial_scope.downcase}"
|
44
|
+
|
45
|
+
help_text = translated_help_text(name, underscored_scope).presence
|
46
|
+
|
47
|
+
help_text ||= if (text = translated_help_text(name, downcased_scope).presence)
|
48
|
+
warn "I18n key '#{downcased_scope}.#{name}' is deprecated, use '#{underscored_scope}.#{name}' instead"
|
49
|
+
text
|
50
|
+
end
|
51
|
+
|
52
|
+
help_text
|
53
|
+
end
|
54
|
+
|
55
|
+
def translated_help_text(name, scope)
|
56
|
+
ActiveSupport::SafeBuffer.new I18n.t(name, scope: scope, default: "")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BootstrapForm
|
4
|
+
module Components
|
5
|
+
module Labels
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def generate_label(id, name, options, custom_label_col, group_layout)
|
11
|
+
return if options.blank?
|
12
|
+
|
13
|
+
# id is the caller's options[:id] at the only place this method is called.
|
14
|
+
# The options argument is a small subset of the options that might have
|
15
|
+
# been passed to generate_label's caller, and definitely doesn't include
|
16
|
+
# :id.
|
17
|
+
options[:for] = id if acts_like_form_tag
|
18
|
+
|
19
|
+
options[:class] = label_classes(name, options, custom_label_col, group_layout)
|
20
|
+
options.delete(:class) if options[:class].none?
|
21
|
+
|
22
|
+
label(name, label_text(name, options), options.except(:text))
|
23
|
+
end
|
24
|
+
|
25
|
+
def label_classes(name, options, custom_label_col, group_layout)
|
26
|
+
classes = [options[:class], label_layout_classes(custom_label_col, group_layout)]
|
27
|
+
|
28
|
+
case options.delete(:required)
|
29
|
+
when true
|
30
|
+
classes << "required"
|
31
|
+
when nil, :default
|
32
|
+
classes << "required" if required_attribute?(object, name)
|
33
|
+
end
|
34
|
+
|
35
|
+
classes << "text-danger" if label_errors && error?(name)
|
36
|
+
classes.flatten.compact
|
37
|
+
end
|
38
|
+
|
39
|
+
def label_layout_classes(custom_label_col, group_layout)
|
40
|
+
if layout_horizontal?(group_layout)
|
41
|
+
["col-form-label", (custom_label_col || label_col)]
|
42
|
+
elsif layout_inline?(group_layout)
|
43
|
+
["mr-sm-2"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def label_text(name, options)
|
48
|
+
if label_errors && error?(name)
|
49
|
+
(options[:text] || object.class.human_attribute_name(name)).to_s.concat(" #{get_error_messages(name)}")
|
50
|
+
else
|
51
|
+
options[:text]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BootstrapForm
|
4
|
+
module Components
|
5
|
+
module Layout
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def layout_default?(field_layout=nil)
|
11
|
+
[:default, nil].include? layout_in_effect(field_layout)
|
12
|
+
end
|
13
|
+
|
14
|
+
def layout_horizontal?(field_layout=nil)
|
15
|
+
layout_in_effect(field_layout) == :horizontal
|
16
|
+
end
|
17
|
+
|
18
|
+
def layout_inline?(field_layout=nil)
|
19
|
+
layout_in_effect(field_layout) == :inline
|
20
|
+
end
|
21
|
+
|
22
|
+
def field_inline_override?(field_layout=nil)
|
23
|
+
field_layout == :inline && layout != :inline
|
24
|
+
end
|
25
|
+
|
26
|
+
# true and false should only come from check_box and radio_button,
|
27
|
+
# and those don't have a :horizontal layout
|
28
|
+
def layout_in_effect(field_layout)
|
29
|
+
field_layout = :inline if field_layout == true
|
30
|
+
field_layout = :default if field_layout == false
|
31
|
+
field_layout || layout
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_group_layout(group_layout)
|
35
|
+
group_layout || layout
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BootstrapForm
|
4
|
+
module Components
|
5
|
+
module Validation
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def error?(name)
|
11
|
+
object.respond_to?(:errors) && !(name.nil? || object.errors[name].empty?)
|
12
|
+
end
|
13
|
+
|
14
|
+
def required_attribute?(obj, attribute)
|
15
|
+
return false unless obj && attribute
|
16
|
+
|
17
|
+
target = obj.class == Class ? obj : obj.class
|
18
|
+
|
19
|
+
target_validators = if target.respond_to? :validators_on
|
20
|
+
target.validators_on(attribute).map(&:class)
|
21
|
+
else
|
22
|
+
[]
|
23
|
+
end
|
24
|
+
|
25
|
+
presence_validator?(target_validators)
|
26
|
+
end
|
27
|
+
|
28
|
+
def presence_validator?(target_validators)
|
29
|
+
has_presence_validator = target_validators.include?(
|
30
|
+
ActiveModel::Validations::PresenceValidator
|
31
|
+
)
|
32
|
+
|
33
|
+
if defined? ActiveRecord::Validations::PresenceValidator
|
34
|
+
has_presence_validator |= target_validators.include?(
|
35
|
+
ActiveRecord::Validations::PresenceValidator
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
has_presence_validator
|
40
|
+
end
|
41
|
+
|
42
|
+
def inline_error?(name)
|
43
|
+
error?(name) && inline_errors
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_error(name)
|
47
|
+
return unless inline_error?(name)
|
48
|
+
|
49
|
+
help_text = get_error_messages(name)
|
50
|
+
help_klass = "invalid-feedback"
|
51
|
+
help_tag = :div
|
52
|
+
|
53
|
+
content_tag(help_tag, help_text, class: help_klass)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_error_messages(name)
|
57
|
+
object.errors[name].join(", ")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,20 +1,47 @@
|
|
1
|
-
|
2
|
-
require_relative "helpers/bootstrap"
|
1
|
+
# require 'bootstrap_form/aliasing'
|
3
2
|
|
4
3
|
module BootstrapForm
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
include BootstrapForm::Helpers::Bootstrap
|
9
|
-
|
10
|
-
attr_reader :layout, :label_col, :control_col, :has_error, :inline_errors, :label_errors, :acts_like_form_tag
|
4
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
5
|
+
attr_reader :layout, :label_col, :control_col, :has_error, :inline_errors,
|
6
|
+
:label_errors, :acts_like_form_tag
|
11
7
|
|
12
|
-
|
13
|
-
email_field month_field number_field password_field phone_field
|
14
|
-
range_field search_field telephone_field text_area text_field time_field
|
15
|
-
url_field week_field].freeze
|
8
|
+
include BootstrapForm::Helpers::Bootstrap
|
16
9
|
|
17
|
-
|
10
|
+
include BootstrapForm::FormGroupBuilder
|
11
|
+
include BootstrapForm::FormGroup
|
12
|
+
include BootstrapForm::Components
|
13
|
+
|
14
|
+
include BootstrapForm::Inputs::Base
|
15
|
+
include BootstrapForm::Inputs::CheckBox
|
16
|
+
include BootstrapForm::Inputs::CollectionCheckBoxes
|
17
|
+
include BootstrapForm::Inputs::CollectionRadioButtons
|
18
|
+
include BootstrapForm::Inputs::CollectionSelect
|
19
|
+
include BootstrapForm::Inputs::ColorField
|
20
|
+
include BootstrapForm::Inputs::DateField
|
21
|
+
include BootstrapForm::Inputs::DateSelect
|
22
|
+
include BootstrapForm::Inputs::DatetimeField
|
23
|
+
include BootstrapForm::Inputs::DatetimeLocalField
|
24
|
+
include BootstrapForm::Inputs::DatetimeSelect
|
25
|
+
include BootstrapForm::Inputs::EmailField
|
26
|
+
include BootstrapForm::Inputs::FileField
|
27
|
+
include BootstrapForm::Inputs::GroupedCollectionSelect
|
28
|
+
include BootstrapForm::Inputs::MonthField
|
29
|
+
include BootstrapForm::Inputs::NumberField
|
30
|
+
include BootstrapForm::Inputs::PasswordField
|
31
|
+
include BootstrapForm::Inputs::PhoneField
|
32
|
+
include BootstrapForm::Inputs::RadioButton
|
33
|
+
include BootstrapForm::Inputs::RangeField
|
34
|
+
include BootstrapForm::Inputs::RichTextArea if Rails::VERSION::MAJOR >= 6
|
35
|
+
include BootstrapForm::Inputs::SearchField
|
36
|
+
include BootstrapForm::Inputs::Select
|
37
|
+
include BootstrapForm::Inputs::TelephoneField
|
38
|
+
include BootstrapForm::Inputs::TextArea
|
39
|
+
include BootstrapForm::Inputs::TextField
|
40
|
+
include BootstrapForm::Inputs::TimeField
|
41
|
+
include BootstrapForm::Inputs::TimeSelect
|
42
|
+
include BootstrapForm::Inputs::TimeZoneSelect
|
43
|
+
include BootstrapForm::Inputs::UrlField
|
44
|
+
include BootstrapForm::Inputs::WeekField
|
18
45
|
|
19
46
|
delegate :content_tag, :capture, :concat, to: :@template
|
20
47
|
|
@@ -23,278 +50,24 @@ module BootstrapForm
|
|
23
50
|
@label_col = options[:label_col] || default_label_col
|
24
51
|
@control_col = options[:control_col] || default_control_col
|
25
52
|
@label_errors = options[:label_errors] || false
|
53
|
+
|
26
54
|
@inline_errors = if options[:inline_errors].nil?
|
27
55
|
@label_errors != true
|
28
56
|
else
|
29
57
|
options[:inline_errors] != false
|
30
58
|
end
|
31
59
|
@acts_like_form_tag = options[:acts_like_form_tag]
|
32
|
-
|
33
60
|
super
|
34
61
|
end
|
35
62
|
|
36
|
-
FIELD_HELPERS.each do |method_name|
|
37
|
-
with_method_name = "#{method_name}_with_bootstrap"
|
38
|
-
without_method_name = "#{method_name}_without_bootstrap"
|
39
|
-
|
40
|
-
define_method(with_method_name) do |name, options={}|
|
41
|
-
form_group_builder(name, options) do
|
42
|
-
prepend_and_append_input(name, options) do
|
43
|
-
send(without_method_name, name, options)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
bootstrap_method_alias method_name
|
49
|
-
end
|
50
|
-
|
51
|
-
DATE_SELECT_HELPERS.each do |method_name|
|
52
|
-
with_method_name = "#{method_name}_with_bootstrap"
|
53
|
-
without_method_name = "#{method_name}_without_bootstrap"
|
54
|
-
|
55
|
-
define_method(with_method_name) do |name, options={}, html_options={}|
|
56
|
-
form_group_builder(name, options, html_options) do
|
57
|
-
html_class = control_specific_class(method_name)
|
58
|
-
html_class = "#{html_class} form-inline" if @layout == :horizontal && options[:skip_inline].blank?
|
59
|
-
content_tag(:div, class: html_class) do
|
60
|
-
input_with_error(name) do
|
61
|
-
send(without_method_name, name, options, html_options)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
bootstrap_method_alias method_name
|
68
|
-
end
|
69
|
-
|
70
|
-
def file_field_with_bootstrap(name, options={})
|
71
|
-
options = options.reverse_merge(control_class: "custom-file-input")
|
72
|
-
form_group_builder(name, options) do
|
73
|
-
content_tag(:div, class: "custom-file") do
|
74
|
-
input_with_error(name) do
|
75
|
-
placeholder = options.delete(:placeholder) || "Choose file"
|
76
|
-
placeholder_opts = { class: "custom-file-label" }
|
77
|
-
placeholder_opts[:for] = options[:id] if options[:id].present?
|
78
|
-
|
79
|
-
input = file_field_without_bootstrap(name, options)
|
80
|
-
placeholder_label = label(name, placeholder, placeholder_opts)
|
81
|
-
concat(input)
|
82
|
-
concat(placeholder_label)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
bootstrap_method_alias :file_field
|
89
|
-
|
90
|
-
def select_with_bootstrap(method, choices=nil, options={}, html_options={}, &block)
|
91
|
-
form_group_builder(method, options, html_options) do
|
92
|
-
prepend_and_append_input(method, options) do
|
93
|
-
select_without_bootstrap(method, choices, options, html_options, &block)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
bootstrap_method_alias :select
|
99
|
-
|
100
|
-
def collection_select_with_bootstrap(method, collection, value_method, text_method, options={}, html_options={})
|
101
|
-
form_group_builder(method, options, html_options) do
|
102
|
-
input_with_error(method) do
|
103
|
-
collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
bootstrap_method_alias :collection_select
|
109
|
-
|
110
|
-
def grouped_collection_select_with_bootstrap(method, collection, group_method,
|
111
|
-
group_label_method, option_key_method,
|
112
|
-
option_value_method, options={}, html_options={})
|
113
|
-
form_group_builder(method, options, html_options) do
|
114
|
-
input_with_error(method) do
|
115
|
-
grouped_collection_select_without_bootstrap(method, collection, group_method,
|
116
|
-
group_label_method, option_key_method,
|
117
|
-
option_value_method, options, html_options)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
bootstrap_method_alias :grouped_collection_select
|
123
|
-
|
124
|
-
def time_zone_select_with_bootstrap(method, priority_zones=nil, options={}, html_options={})
|
125
|
-
form_group_builder(method, options, html_options) do
|
126
|
-
input_with_error(method) do
|
127
|
-
time_zone_select_without_bootstrap(method, priority_zones, options, html_options)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
bootstrap_method_alias :time_zone_select
|
133
|
-
|
134
|
-
def check_box_with_bootstrap(name, options={}, checked_value="1", unchecked_value="0", &block)
|
135
|
-
options = options.symbolize_keys!
|
136
|
-
check_box_options = options.except(:label, :label_class, :error_message, :help,
|
137
|
-
:inline, :custom, :hide_label, :skip_label, :wrapper_class)
|
138
|
-
check_box_classes = [check_box_options[:class]]
|
139
|
-
check_box_classes << "position-static" if options[:skip_label] || options[:hide_label]
|
140
|
-
check_box_classes << "is-invalid" if has_error?(name)
|
141
|
-
|
142
|
-
label_classes = [options[:label_class]]
|
143
|
-
label_classes << hide_class if options[:hide_label]
|
144
|
-
|
145
|
-
if options[:custom]
|
146
|
-
check_box_options[:class] = (["custom-control-input"] + check_box_classes).compact.join(" ")
|
147
|
-
wrapper_class = ["custom-control", "custom-checkbox"]
|
148
|
-
wrapper_class.append("custom-control-inline") if layout_inline?(options[:inline])
|
149
|
-
label_class = label_classes.prepend("custom-control-label").compact.join(" ")
|
150
|
-
else
|
151
|
-
check_box_options[:class] = (["form-check-input"] + check_box_classes).compact.join(" ")
|
152
|
-
wrapper_class = ["form-check"]
|
153
|
-
wrapper_class.append("form-check-inline") if layout_inline?(options[:inline])
|
154
|
-
label_class = label_classes.prepend("form-check-label").compact.join(" ")
|
155
|
-
end
|
156
|
-
|
157
|
-
checkbox_html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value)
|
158
|
-
label_content = block_given? ? capture(&block) : options[:label]
|
159
|
-
label_description = label_content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize
|
160
|
-
|
161
|
-
label_name = name
|
162
|
-
# label's `for` attribute needs to match checkbox tag's id,
|
163
|
-
# IE sanitized value, IE
|
164
|
-
# https://github.com/rails/rails/blob/5-0-stable/actionview/lib/action_view/helpers/tags/base.rb#L123-L125
|
165
|
-
if options[:multiple]
|
166
|
-
label_name =
|
167
|
-
"#{name}_#{checked_value.to_s.gsub(/\s/, '_').gsub(/[^-[[:word:]]]/, '').mb_chars.downcase}"
|
168
|
-
end
|
169
|
-
|
170
|
-
label_options = { class: label_class }
|
171
|
-
label_options[:for] = options[:id] if options[:id].present?
|
172
|
-
|
173
|
-
wrapper_class.append(options[:wrapper_class]) if options[:wrapper_class]
|
174
|
-
|
175
|
-
content_tag(:div, class: wrapper_class.compact.join(" ")) do
|
176
|
-
html = if options[:skip_label]
|
177
|
-
checkbox_html
|
178
|
-
else
|
179
|
-
checkbox_html.concat(label(label_name, label_description, label_options))
|
180
|
-
end
|
181
|
-
html.concat(generate_error(name)) if options[:error_message]
|
182
|
-
html
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
bootstrap_method_alias :check_box
|
187
|
-
|
188
|
-
def radio_button_with_bootstrap(name, value, *args)
|
189
|
-
options = args.extract_options!.symbolize_keys!
|
190
|
-
radio_options = options.except(:label, :label_class, :error_message, :help,
|
191
|
-
:inline, :custom, :hide_label, :skip_label,
|
192
|
-
:wrapper_class)
|
193
|
-
radio_classes = [options[:class]]
|
194
|
-
radio_classes << "position-static" if options[:skip_label] || options[:hide_label]
|
195
|
-
radio_classes << "is-invalid" if has_error?(name)
|
196
|
-
|
197
|
-
label_classes = [options[:label_class]]
|
198
|
-
label_classes << hide_class if options[:hide_label]
|
199
|
-
|
200
|
-
if options[:custom]
|
201
|
-
radio_options[:class] = radio_classes.prepend("custom-control-input").compact.join(" ")
|
202
|
-
wrapper_class = ["custom-control", "custom-radio"]
|
203
|
-
wrapper_class.append("custom-control-inline") if layout_inline?(options[:inline])
|
204
|
-
label_class = label_classes.prepend("custom-control-label").compact.join(" ")
|
205
|
-
else
|
206
|
-
radio_options[:class] = radio_classes.prepend("form-check-input").compact.join(" ")
|
207
|
-
wrapper_class = ["form-check"]
|
208
|
-
wrapper_class.append("form-check-inline") if layout_inline?(options[:inline])
|
209
|
-
wrapper_class.append("disabled") if options[:disabled]
|
210
|
-
label_class = label_classes.prepend("form-check-label").compact.join(" ")
|
211
|
-
end
|
212
|
-
radio_html = radio_button_without_bootstrap(name, value, radio_options)
|
213
|
-
|
214
|
-
label_options = { value: value, class: label_class }
|
215
|
-
label_options[:for] = options[:id] if options[:id].present?
|
216
|
-
|
217
|
-
wrapper_class.append(options[:wrapper_class]) if options[:wrapper_class]
|
218
|
-
|
219
|
-
content_tag(:div, class: wrapper_class.compact.join(" ")) do
|
220
|
-
html = if options[:skip_label]
|
221
|
-
radio_html
|
222
|
-
else
|
223
|
-
radio_html.concat(label(name, options[:label], label_options))
|
224
|
-
end
|
225
|
-
html.concat(generate_error(name)) if options[:error_message]
|
226
|
-
html
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
bootstrap_method_alias :radio_button
|
231
|
-
|
232
|
-
def collection_check_boxes_with_bootstrap(*args)
|
233
|
-
html = inputs_collection(*args) do |name, value, options|
|
234
|
-
options[:multiple] = true
|
235
|
-
check_box(name, options, value, nil)
|
236
|
-
end
|
237
|
-
hidden_field(args.first, value: "", multiple: true).concat(html)
|
238
|
-
end
|
239
|
-
|
240
|
-
bootstrap_method_alias :collection_check_boxes
|
241
|
-
|
242
|
-
def collection_radio_buttons_with_bootstrap(*args)
|
243
|
-
inputs_collection(*args) do |name, value, options|
|
244
|
-
radio_button(name, value, options)
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
bootstrap_method_alias :collection_radio_buttons
|
249
|
-
|
250
|
-
def form_group(*args, &block)
|
251
|
-
options = args.extract_options!
|
252
|
-
name = args.first
|
253
|
-
|
254
|
-
options[:class] = ["form-group", options[:class]].compact.join(" ")
|
255
|
-
options[:class] << " row" if get_group_layout(options[:layout]) == :horizontal &&
|
256
|
-
!options[:class].split.include?("form-row")
|
257
|
-
options[:class] << " form-inline" if field_inline_override?(options[:layout])
|
258
|
-
options[:class] << " #{feedback_class}" if options[:icon]
|
259
|
-
|
260
|
-
content_tag(:div, options.except(:append, :id, :label, :help, :icon,
|
261
|
-
:input_group_class, :label_col, :control_col,
|
262
|
-
:add_control_col_class, :layout, :prepend)) do
|
263
|
-
label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label]
|
264
|
-
control = capture(&block)
|
265
|
-
|
266
|
-
help = options[:help]
|
267
|
-
help_text = generate_help(name, help).to_s
|
268
|
-
|
269
|
-
if get_group_layout(options[:layout]) == :horizontal
|
270
|
-
control_class = options[:control_col] || control_col
|
271
|
-
control_class = [control_class, options[:add_control_col_class]].compact.join(" ") if options[:add_control_col_class]
|
272
|
-
unless options[:label]
|
273
|
-
control_offset = offset_col(options[:label_col] || @label_col)
|
274
|
-
control_class = "#{control_class} #{control_offset}"
|
275
|
-
end
|
276
|
-
control = content_tag(:div, control + help_text, class: control_class)
|
277
|
-
concat(label).concat(control)
|
278
|
-
else
|
279
|
-
concat(label).concat(control).concat(help_text)
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
63
|
def fields_for_with_bootstrap(record_name, record_object=nil, fields_options={}, &block)
|
285
|
-
|
286
|
-
|
64
|
+
fields_options = fields_for_options(record_object, fields_options)
|
65
|
+
record_object.is_a?(Hash) && record_object.extractable_options? &&
|
287
66
|
record_object = nil
|
288
|
-
end
|
289
|
-
fields_options[:layout] ||= options[:layout]
|
290
|
-
fields_options[:label_col] = fields_options[:label_col].present? ? (fields_options[:label_col]).to_s : options[:label_col]
|
291
|
-
fields_options[:control_col] ||= options[:control_col]
|
292
|
-
fields_options[:inline_errors] ||= options[:inline_errors]
|
293
|
-
fields_options[:label_errors] ||= options[:label_errors]
|
294
67
|
fields_for_without_bootstrap(record_name, record_object, fields_options, &block)
|
295
68
|
end
|
296
69
|
|
297
|
-
|
70
|
+
bootstrap_alias :fields_for
|
298
71
|
|
299
72
|
# the Rails `fields` method passes its options
|
300
73
|
# to the builder, so there is no need to write a `bootstrap_form` helper
|
@@ -302,32 +75,15 @@ module BootstrapForm
|
|
302
75
|
|
303
76
|
private
|
304
77
|
|
305
|
-
def
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
layout_in_effect(field_layout) == :inline
|
315
|
-
end
|
316
|
-
|
317
|
-
def field_inline_override?(field_layout=nil)
|
318
|
-
field_layout == :inline && layout != :inline
|
319
|
-
end
|
320
|
-
|
321
|
-
# true and false should only come from check_box and radio_button,
|
322
|
-
# and those don't have a :horizontal layout
|
323
|
-
def layout_in_effect(field_layout)
|
324
|
-
field_layout = :inline if field_layout == true
|
325
|
-
field_layout = :default if field_layout == false
|
326
|
-
field_layout || layout
|
327
|
-
end
|
328
|
-
|
329
|
-
def get_group_layout(group_layout)
|
330
|
-
group_layout || layout
|
78
|
+
def fields_for_options(record_object, fields_options)
|
79
|
+
field_options = fields_options
|
80
|
+
record_object.is_a?(Hash) && record_object.extractable_options? &&
|
81
|
+
field_options = record_object
|
82
|
+
%i[layout control_col inline_errors label_errors].each do |option|
|
83
|
+
field_options[option] ||= options[option]
|
84
|
+
end
|
85
|
+
field_options[:label_col] = field_options[:label_col].present? ? (field_options[:label_col]).to_s : options[:label_col]
|
86
|
+
field_options
|
331
87
|
end
|
332
88
|
|
333
89
|
def default_label_col
|
@@ -355,233 +111,7 @@ module BootstrapForm
|
|
355
111
|
end
|
356
112
|
|
357
113
|
def control_specific_class(method)
|
358
|
-
"rails-bootstrap-forms-#{method.tr('_', '-')}"
|
359
|
-
end
|
360
|
-
|
361
|
-
def has_error?(name)
|
362
|
-
object.respond_to?(:errors) && !(name.nil? || object.errors[name].empty?)
|
363
|
-
end
|
364
|
-
|
365
|
-
def required_attribute?(obj, attribute)
|
366
|
-
return false unless obj && attribute
|
367
|
-
|
368
|
-
target = obj.class == Class ? obj : obj.class
|
369
|
-
|
370
|
-
target_validators = if target.respond_to? :validators_on
|
371
|
-
target.validators_on(attribute).map(&:class)
|
372
|
-
else
|
373
|
-
[]
|
374
|
-
end
|
375
|
-
|
376
|
-
has_presence_validator = target_validators.include?(
|
377
|
-
ActiveModel::Validations::PresenceValidator
|
378
|
-
)
|
379
|
-
|
380
|
-
if defined? ActiveRecord::Validations::PresenceValidator
|
381
|
-
has_presence_validator |= target_validators.include?(
|
382
|
-
ActiveRecord::Validations::PresenceValidator
|
383
|
-
)
|
384
|
-
end
|
385
|
-
|
386
|
-
has_presence_validator
|
387
|
-
end
|
388
|
-
|
389
|
-
# TODO: Refactor this method and remove the rubocop:disable
|
390
|
-
def form_group_builder(method, options, html_options=nil) # rubocop:disable Metrics/MethodLength
|
391
|
-
options.symbolize_keys!
|
392
|
-
|
393
|
-
wrapper_class = options.delete(:wrapper_class)
|
394
|
-
wrapper_options = options.delete(:wrapper)
|
395
|
-
|
396
|
-
html_options.symbolize_keys! if html_options
|
397
|
-
|
398
|
-
# Add control_class; allow it to be overridden by :control_class option
|
399
|
-
css_options = html_options || options
|
400
|
-
control_classes = css_options.delete(:control_class) { control_class }
|
401
|
-
css_options[:class] = [control_classes, css_options[:class]].compact.join(" ")
|
402
|
-
css_options[:class] << " is-invalid" if has_error?(method)
|
403
|
-
|
404
|
-
options = convert_form_tag_options(method, options) if acts_like_form_tag
|
405
|
-
|
406
|
-
help = options.delete(:help)
|
407
|
-
icon = options.delete(:icon)
|
408
|
-
label_col = options.delete(:label_col)
|
409
|
-
control_col = options.delete(:control_col)
|
410
|
-
add_control_col_class = options.delete(:add_control_col_class)
|
411
|
-
layout = get_group_layout(options.delete(:layout))
|
412
|
-
form_group_options = {
|
413
|
-
id: options[:id],
|
414
|
-
help: help,
|
415
|
-
icon: icon,
|
416
|
-
label_col: label_col,
|
417
|
-
control_col: control_col,
|
418
|
-
add_control_col_class: add_control_col_class,
|
419
|
-
layout: layout,
|
420
|
-
class: wrapper_class
|
421
|
-
}
|
422
|
-
|
423
|
-
form_group_options.merge!(wrapper_options) if wrapper_options.is_a?(Hash)
|
424
|
-
|
425
|
-
unless options.delete(:skip_label)
|
426
|
-
if options[:label].is_a?(Hash)
|
427
|
-
label_text = options[:label].delete(:text)
|
428
|
-
label_class = options[:label].delete(:class)
|
429
|
-
options.delete(:label)
|
430
|
-
end
|
431
|
-
label_class ||= options.delete(:label_class)
|
432
|
-
label_class = hide_class if options.delete(:hide_label) || options[:label_as_placeholder]
|
433
|
-
|
434
|
-
label_text ||= options.delete(:label) if options[:label].is_a?(String)
|
435
|
-
|
436
|
-
if options.key?(:skip_required)
|
437
|
-
warn "`:skip_required` is deprecated, use `:required: false` instead"
|
438
|
-
options[:required] = options.delete(:skip_required) ? false : :default
|
439
|
-
end
|
440
|
-
|
441
|
-
form_group_options[:label] = {
|
442
|
-
text: label_text,
|
443
|
-
class: label_class,
|
444
|
-
required: options[:required]
|
445
|
-
}.merge(css_options[:id].present? ? { for: css_options[:id] } : {})
|
446
|
-
|
447
|
-
css_options[:placeholder] = label_text || object.class.human_attribute_name(method) if options.delete(:label_as_placeholder)
|
448
|
-
end
|
449
|
-
|
450
|
-
if wrapper_options == false
|
451
|
-
yield
|
452
|
-
else
|
453
|
-
form_group(method, form_group_options) do
|
454
|
-
yield
|
455
|
-
end
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
def convert_form_tag_options(method, options={})
|
460
|
-
unless @options[:skip_default_ids]
|
461
|
-
options[:name] ||= method
|
462
|
-
options[:id] ||= method
|
463
|
-
end
|
464
|
-
options
|
465
|
-
end
|
466
|
-
|
467
|
-
def generate_label(id, name, options, custom_label_col, group_layout)
|
468
|
-
# id is the caller's options[:id] at the only place this method is called.
|
469
|
-
# The options argument is a small subset of the options that might have
|
470
|
-
# been passed to generate_label's caller, and definitely doesn't include
|
471
|
-
# :id.
|
472
|
-
options[:for] = id if acts_like_form_tag
|
473
|
-
classes = [options[:class]]
|
474
|
-
|
475
|
-
if layout_horizontal?(group_layout)
|
476
|
-
classes << "col-form-label"
|
477
|
-
classes << (custom_label_col || label_col)
|
478
|
-
elsif layout_inline?(group_layout)
|
479
|
-
classes << "mr-sm-2"
|
480
|
-
end
|
481
|
-
|
482
|
-
case options.delete(:required)
|
483
|
-
when true
|
484
|
-
classes << "required"
|
485
|
-
when nil, :default
|
486
|
-
classes << "required" if required_attribute?(object, name)
|
487
|
-
end
|
488
|
-
|
489
|
-
options[:class] = classes.compact.join(" ").strip
|
490
|
-
options.delete(:class) if options[:class].empty?
|
491
|
-
|
492
|
-
if label_errors && has_error?(name)
|
493
|
-
error_messages = get_error_messages(name)
|
494
|
-
label_text = (options[:text] || object.class.human_attribute_name(name)).to_s.concat(" #{error_messages}")
|
495
|
-
options[:class] = [options[:class], "text-danger"].compact.join(" ")
|
496
|
-
label(name, label_text, options.except(:text))
|
497
|
-
else
|
498
|
-
label(name, options[:text], options.except(:text))
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
def has_inline_error?(name)
|
503
|
-
has_error?(name) && inline_errors
|
504
|
-
end
|
505
|
-
|
506
|
-
def generate_error(name)
|
507
|
-
if has_inline_error?(name)
|
508
|
-
help_text = get_error_messages(name)
|
509
|
-
help_klass = "invalid-feedback"
|
510
|
-
help_tag = :div
|
511
|
-
|
512
|
-
content_tag(help_tag, help_text, class: help_klass)
|
513
|
-
end
|
514
|
-
end
|
515
|
-
|
516
|
-
def generate_help(name, help_text)
|
517
|
-
return if help_text == false || has_inline_error?(name)
|
518
|
-
|
519
|
-
help_klass ||= "form-text text-muted"
|
520
|
-
help_text ||= get_help_text_by_i18n_key(name)
|
521
|
-
help_tag ||= :small
|
522
|
-
|
523
|
-
content_tag(help_tag, help_text, class: help_klass) if help_text.present?
|
524
|
-
end
|
525
|
-
|
526
|
-
def get_error_messages(name)
|
527
|
-
object.errors[name].join(", ")
|
528
|
-
end
|
529
|
-
|
530
|
-
def inputs_collection(name, collection, value, text, options={})
|
531
|
-
options[:inline] ||= layout_inline?(options[:layout])
|
532
|
-
form_group_builder(name, options) do
|
533
|
-
inputs = ""
|
534
|
-
|
535
|
-
collection.each_with_index do |obj, i|
|
536
|
-
input_options = options.merge(label: text.respond_to?(:call) ? text.call(obj) : obj.send(text))
|
537
|
-
|
538
|
-
input_value = value.respond_to?(:call) ? value.call(obj) : obj.send(value)
|
539
|
-
if (checked = input_options[:checked])
|
540
|
-
input_options[:checked] = checked == input_value ||
|
541
|
-
Array(checked).try(:include?, input_value) ||
|
542
|
-
checked == obj ||
|
543
|
-
Array(checked).try(:include?, obj)
|
544
|
-
end
|
545
|
-
|
546
|
-
input_options.delete(:class)
|
547
|
-
inputs << yield(name, input_value, input_options.merge(error_message: i == collection.size - 1))
|
548
|
-
end
|
549
|
-
|
550
|
-
inputs.html_safe
|
551
|
-
end
|
552
|
-
end
|
553
|
-
|
554
|
-
def get_help_text_by_i18n_key(name)
|
555
|
-
if object
|
556
|
-
|
557
|
-
partial_scope = if object.class.respond_to?(:model_name)
|
558
|
-
object.class.model_name.name
|
559
|
-
else
|
560
|
-
object.class.name
|
561
|
-
end
|
562
|
-
|
563
|
-
underscored_scope = "activerecord.help.#{partial_scope.underscore}"
|
564
|
-
downcased_scope = "activerecord.help.#{partial_scope.downcase}"
|
565
|
-
# First check for a subkey :html, as it is also accepted by i18n, and the
|
566
|
-
# simple check for name would return an hash instead of a string (both
|
567
|
-
# with .presence returning true!)
|
568
|
-
help_text = I18n.t("#{name}.html", scope: underscored_scope, default: "").html_safe.presence
|
569
|
-
help_text ||= if (text = I18n.t("#{name}.html", scope: downcased_scope, default: "").html_safe.presence)
|
570
|
-
warn "I18n key '#{downcased_scope}.#{name}' is deprecated, use '#{underscored_scope}.#{name}' instead"
|
571
|
-
text
|
572
|
-
end
|
573
|
-
help_text ||= I18n.t(name, scope: underscored_scope, default: "").presence
|
574
|
-
help_text ||= if (text = I18n.t(name, scope: downcased_scope, default: "").presence)
|
575
|
-
warn "I18n key '#{downcased_scope}.#{name}' is deprecated, use '#{underscored_scope}.#{name}' instead"
|
576
|
-
text
|
577
|
-
end
|
578
|
-
help_text ||= I18n.t("#{name}_html", scope: underscored_scope, default: "").html_safe.presence
|
579
|
-
help_text ||= if (text = I18n.t("#{name}_html", scope: downcased_scope, default: "").html_safe.presence)
|
580
|
-
warn "I18n key '#{downcased_scope}.#{name}' is deprecated, use '#{underscored_scope}.#{name}' instead"
|
581
|
-
text
|
582
|
-
end
|
583
|
-
help_text
|
584
|
-
end
|
114
|
+
"rails-bootstrap-forms-#{method.to_s.tr('_', '-')}"
|
585
115
|
end
|
586
116
|
end
|
587
117
|
end
|