comfy_bootstrap_form 4.0.0.beta1 → 4.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +12 -0
- data/.travis.yml +14 -0
- data/CONTRIBUTING.md +40 -0
- data/Gemfile +14 -0
- data/{MIT-LICENSE → LICENSE.md} +1 -1
- data/README.md +130 -495
- data/Rakefile +5 -15
- data/bootstrap_form.gemspec +25 -0
- data/demo/README.md +18 -0
- data/demo/Rakefile +6 -0
- data/demo/app/controllers/application_controller.rb +2 -0
- data/demo/app/controllers/bootstrap_controller.rb +12 -0
- data/demo/app/models/application_record.rb +3 -0
- data/demo/app/models/user.rb +3 -0
- data/demo/app/views/bootstrap/form.html.erb +82 -0
- data/demo/app/views/layouts/application.html.erb +43 -0
- data/demo/bin/bundle +3 -0
- data/{test/dummy → demo}/bin/rails +1 -1
- data/{test/dummy → demo}/bin/rake +0 -0
- data/demo/bin/setup +36 -0
- data/demo/bin/update +31 -0
- data/demo/bin/yarn +11 -0
- data/{test/dummy → demo}/config.ru +2 -1
- data/demo/config/application.rb +24 -0
- data/demo/config/boot.rb +5 -0
- data/{test/dummy → demo}/config/database.yml +8 -12
- data/demo/config/environment.rb +5 -0
- data/demo/config/environments/development.rb +60 -0
- data/{test/dummy → demo}/config/environments/test.rb +15 -20
- data/demo/config/initializers/application_controller_renderer.rb +8 -0
- data/demo/config/initializers/assets.rb +14 -0
- data/{test/dummy → demo}/config/initializers/backtrace_silencers.rb +0 -0
- data/demo/config/initializers/cookies_serializer.rb +5 -0
- data/{test/dummy → demo}/config/initializers/filter_parameter_logging.rb +0 -0
- data/{test/dummy → demo}/config/initializers/inflections.rb +0 -0
- data/{test/dummy → demo}/config/initializers/mime_types.rb +0 -1
- data/{test/dummy → demo}/config/initializers/wrap_parameters.rb +2 -2
- data/{test/dummy → demo}/config/locales/en.yml +10 -0
- data/demo/config/puma.rb +56 -0
- data/{test/dummy → demo}/config/routes.rb +2 -0
- data/demo/config/spring.rb +6 -0
- data/demo/config/storage.yml +35 -0
- data/demo/db/schema.rb +11 -0
- data/{test/dummy/public/favicon.ico → demo/log/.keep} +0 -0
- data/demo/package.json +5 -0
- data/demo/public/favicon.ico +0 -0
- data/lib/bootstrap_form.rb +2 -2
- data/lib/bootstrap_form/form_builder.rb +367 -346
- data/lib/bootstrap_form/version.rb +1 -1
- data/lib/bootstrap_form/view_helper.rb +33 -0
- data/lib/comfy_bootstrap_form.rb +1 -1
- data/test/bootstrap_form/fields_test.rb +304 -0
- data/test/bootstrap_form/fields_with_errors_test.rb +109 -0
- data/test/bootstrap_form/form_builder_test.rb +49 -0
- data/test/bootstrap_form/horizontal_form_test.rb +159 -0
- data/test/bootstrap_form/inline_form_test.rb +68 -0
- data/test/bootstrap_form/input_group_test.rb +53 -0
- data/test/bootstrap_form/radios_and_checkboxes_test.rb +208 -0
- data/test/bootstrap_form/submit_test.rb +59 -0
- data/test/bootstrap_form/view_helpers_test.rb +99 -0
- data/test/gemfiles/5.2.gemfile +13 -0
- data/test/test_helper.rb +31 -69
- metadata +71 -258
- data/app/assets/stylesheets/rails_bootstrap_forms.css +0 -10
- data/lib/bootstrap_form/aliasing.rb +0 -35
- data/lib/bootstrap_form/helper.rb +0 -36
- data/lib/bootstrap_form/helpers/bootstrap.rb +0 -94
- data/lib/bootstrap_form/helpers/nested_form.rb +0 -33
- data/test/bootstrap_checkbox_test.rb +0 -144
- data/test/bootstrap_fields_test.rb +0 -152
- data/test/bootstrap_form_group_test.rb +0 -313
- data/test/bootstrap_form_test.rb +0 -276
- data/test/bootstrap_other_components_test.rb +0 -86
- data/test/bootstrap_radio_button_test.rb +0 -124
- data/test/bootstrap_selects_test.rb +0 -160
- data/test/dummy/Gemfile +0 -45
- data/test/dummy/Gemfile.lock +0 -120
- data/test/dummy/README.rdoc +0 -28
- data/test/dummy/Rakefile +0 -10
- data/test/dummy/app/assets/javascripts/application.js +0 -16
- data/test/dummy/app/assets/stylesheets/application.css +0 -13
- data/test/dummy/app/controllers/application_controller.rb +0 -5
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/models/address.rb +0 -3
- data/test/dummy/app/models/faux_user.rb +0 -9
- data/test/dummy/app/models/super_user.rb +0 -2
- data/test/dummy/app/models/user.rb +0 -9
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/bin/bundle +0 -3
- data/test/dummy/config/application.rb +0 -23
- data/test/dummy/config/boot.rb +0 -4
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -29
- data/test/dummy/config/environments/production.rb +0 -80
- data/test/dummy/config/initializers/generic_migration.rb +0 -6
- data/test/dummy/config/initializers/secret_token.rb +0 -12
- data/test/dummy/config/initializers/session_store.rb +0 -3
- data/test/dummy/db/migrate/20130703191909_create_users.rb +0 -13
- data/test/dummy/db/migrate/20130703191937_create_addresses.rb +0 -13
- data/test/dummy/db/migrate/20130912171202_add_preferences_to_user.rb +0 -5
- data/test/dummy/db/migrate/20140327190145_add_terms_to_user.rb +0 -5
- data/test/dummy/db/migrate/20140922133133_add_type_to_users.rb +0 -5
- data/test/dummy/db/schema.rb +0 -38
- data/test/dummy/db/seeds.rb +0 -7
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +0 -18394
- data/test/dummy/public/404.html +0 -58
- data/test/dummy/public/422.html +0 -58
- data/test/dummy/public/500.html +0 -57
- data/test/dummy/public/robots.txt +0 -5
- data/test/dummy/test/fixtures/addresses.yml +0 -15
- data/test/dummy/test/fixtures/users.yml +0 -15
- data/test/dummy/test/models/address_test.rb +0 -7
- data/test/dummy/test/models/user_test.rb +0 -7
- data/test/dummy/test/test_helper.rb +0 -15
- data/test/special_form_class_models_test.rb +0 -43
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
Rails.application.configure do
|
2
2
|
# Settings specified here will take precedence over those in config/application.rb.
|
3
3
|
|
4
4
|
# The test environment is used exclusively to run your application's
|
@@ -12,23 +12,11 @@ Dummy::Application.configure do
|
|
12
12
|
# preloads Rails for running tests, you may have to set it to true.
|
13
13
|
config.eager_load = false
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
elsif version < 5
|
21
|
-
config.serve_static_files = true
|
22
|
-
end
|
23
|
-
|
24
|
-
if version < 5
|
25
|
-
config.static_cache_control = "public, max-age=3600"
|
26
|
-
else
|
27
|
-
config.public_file_server.enabled = true
|
28
|
-
config.public_file_server.headers = {
|
29
|
-
"Cache-Control" => "public, max-age=3600"
|
30
|
-
}
|
31
|
-
end
|
15
|
+
# Configure public file server for tests with Cache-Control for performance.
|
16
|
+
config.public_file_server.enabled = true
|
17
|
+
config.public_file_server.headers = {
|
18
|
+
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
|
19
|
+
}
|
32
20
|
|
33
21
|
# Show full error reports and disable caching.
|
34
22
|
config.consider_all_requests_local = true
|
@@ -40,6 +28,13 @@ Dummy::Application.configure do
|
|
40
28
|
# Disable request forgery protection in test environment.
|
41
29
|
config.action_controller.allow_forgery_protection = false
|
42
30
|
|
31
|
+
# Store uploaded files on the local file system in a temporary directory
|
32
|
+
if config.respond_to?(:active_storage)
|
33
|
+
config.active_storage.service = :test
|
34
|
+
end
|
35
|
+
|
36
|
+
config.action_mailer.perform_caching = false
|
37
|
+
|
43
38
|
# Tell Action Mailer not to deliver emails to the real world.
|
44
39
|
# The :test delivery method accumulates sent emails in the
|
45
40
|
# ActionMailer::Base.deliveries array.
|
@@ -48,6 +43,6 @@ Dummy::Application.configure do
|
|
48
43
|
# Print deprecation notices to the stderr.
|
49
44
|
config.active_support.deprecation = :stderr
|
50
45
|
|
51
|
-
#
|
52
|
-
config.
|
46
|
+
# Raises error for missing translations
|
47
|
+
# config.action_view.raise_on_missing_translations = true
|
53
48
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Version of your assets, change this if you want to expire all your assets.
|
4
|
+
Rails.application.config.assets.version = '1.0'
|
5
|
+
|
6
|
+
# Add additional assets to the asset load path.
|
7
|
+
# Rails.application.config.assets.paths << Emoji.images_path
|
8
|
+
# Add Yarn node_modules folder to the asset load path.
|
9
|
+
Rails.application.config.assets.paths << Rails.root.join('node_modules')
|
10
|
+
|
11
|
+
# Precompile additional assets.
|
12
|
+
# application.js, application.css, and all non-JS/CSS in the app/assets
|
13
|
+
# folder are already added.
|
14
|
+
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
|
File without changes
|
File without changes
|
File without changes
|
@@ -5,10 +5,10 @@
|
|
5
5
|
|
6
6
|
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
|
7
7
|
ActiveSupport.on_load(:action_controller) do
|
8
|
-
wrap_parameters format: [:json]
|
8
|
+
wrap_parameters format: [:json]
|
9
9
|
end
|
10
10
|
|
11
11
|
# To enable root element in JSON for ActiveRecord objects.
|
12
12
|
# ActiveSupport.on_load(:active_record) do
|
13
|
-
#
|
13
|
+
# self.include_root_in_json = true
|
14
14
|
# end
|
@@ -16,6 +16,16 @@
|
|
16
16
|
#
|
17
17
|
# This would use the information in config/locales/es.yml.
|
18
18
|
#
|
19
|
+
# The following keys must be escaped otherwise they will not be retrieved by
|
20
|
+
# the default I18n backend:
|
21
|
+
#
|
22
|
+
# true, false, on, off, yes, no
|
23
|
+
#
|
24
|
+
# Instead, surround them with single quotes.
|
25
|
+
#
|
26
|
+
# en:
|
27
|
+
# 'true': 'foo'
|
28
|
+
#
|
19
29
|
# To learn more, please read the Rails Internationalization guide
|
20
30
|
# available at http://guides.rubyonrails.org/i18n.html.
|
21
31
|
|
data/demo/config/puma.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Puma can serve each request in a thread from an internal thread pool.
|
2
|
+
# The `threads` method setting takes two numbers: a minimum and maximum.
|
3
|
+
# Any libraries that use thread pools should be configured to match
|
4
|
+
# the maximum value specified for Puma. Default is set to 5 threads for minimum
|
5
|
+
# and maximum; this matches the default thread size of Active Record.
|
6
|
+
#
|
7
|
+
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
|
8
|
+
threads threads_count, threads_count
|
9
|
+
|
10
|
+
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
|
11
|
+
#
|
12
|
+
port ENV.fetch("PORT") { 3000 }
|
13
|
+
|
14
|
+
# Specifies the `environment` that Puma will run in.
|
15
|
+
#
|
16
|
+
environment ENV.fetch("RAILS_ENV") { "development" }
|
17
|
+
|
18
|
+
# Specifies the number of `workers` to boot in clustered mode.
|
19
|
+
# Workers are forked webserver processes. If using threads and workers together
|
20
|
+
# the concurrency of the application would be max `threads` * `workers`.
|
21
|
+
# Workers do not work on JRuby or Windows (both of which do not support
|
22
|
+
# processes).
|
23
|
+
#
|
24
|
+
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
|
25
|
+
|
26
|
+
# Use the `preload_app!` method when specifying a `workers` number.
|
27
|
+
# This directive tells Puma to first boot the application and load code
|
28
|
+
# before forking the application. This takes advantage of Copy On Write
|
29
|
+
# process behavior so workers use less memory. If you use this option
|
30
|
+
# you need to make sure to reconnect any threads in the `on_worker_boot`
|
31
|
+
# block.
|
32
|
+
#
|
33
|
+
# preload_app!
|
34
|
+
|
35
|
+
# If you are preloading your application and using Active Record, it's
|
36
|
+
# recommended that you close any connections to the database before workers
|
37
|
+
# are forked to prevent connection leakage.
|
38
|
+
#
|
39
|
+
# before_fork do
|
40
|
+
# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
|
41
|
+
# end
|
42
|
+
|
43
|
+
# The code in the `on_worker_boot` will be called if you are using
|
44
|
+
# clustered mode by specifying a number of `workers`. After each worker
|
45
|
+
# process is booted, this block will be run. If you are using the `preload_app!`
|
46
|
+
# option, you will want to use this block to reconnect to any threads
|
47
|
+
# or connections that may have been created at application boot, as Ruby
|
48
|
+
# cannot share connections between processes.
|
49
|
+
#
|
50
|
+
# on_worker_boot do
|
51
|
+
# ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
|
55
|
+
# Allow puma to be restarted by `rails restart` command.
|
56
|
+
plugin :tmp_restart
|
@@ -0,0 +1,35 @@
|
|
1
|
+
test:
|
2
|
+
service: Disk
|
3
|
+
root: <%= Rails.root.join("tmp/storage") %>
|
4
|
+
|
5
|
+
local:
|
6
|
+
service: Disk
|
7
|
+
root: <%= Rails.root.join("storage") %>
|
8
|
+
|
9
|
+
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
|
10
|
+
# amazon:
|
11
|
+
# service: S3
|
12
|
+
# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
|
13
|
+
# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
|
14
|
+
# region: us-east-1
|
15
|
+
# bucket: your_own_bucket
|
16
|
+
|
17
|
+
# Remember not to checkin your GCS keyfile to a repository
|
18
|
+
# google:
|
19
|
+
# service: GCS
|
20
|
+
# project: your_project
|
21
|
+
# keyfile: <%= Rails.root.join("path/to/gcs.keyfile") %>
|
22
|
+
# bucket: your_own_bucket
|
23
|
+
|
24
|
+
# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
|
25
|
+
# microsoft:
|
26
|
+
# service: AzureStorage
|
27
|
+
# path: your_azure_storage_path
|
28
|
+
# storage_account_name: your_account_name
|
29
|
+
# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
|
30
|
+
# container: your_container_name
|
31
|
+
|
32
|
+
# mirror:
|
33
|
+
# service: Mirror
|
34
|
+
# primary: local
|
35
|
+
# mirrors: [ amazon, google, microsoft ]
|
data/demo/db/schema.rb
ADDED
File without changes
|
data/demo/package.json
ADDED
File without changes
|
data/lib/bootstrap_form.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'bootstrap_form/form_builder'
|
2
|
-
require 'bootstrap_form/
|
2
|
+
require 'bootstrap_form/view_helper'
|
3
3
|
|
4
4
|
module BootstrapForm
|
5
5
|
module Rails
|
@@ -9,5 +9,5 @@ module BootstrapForm
|
|
9
9
|
end
|
10
10
|
|
11
11
|
ActiveSupport.on_load(:action_view) do
|
12
|
-
include BootstrapForm::
|
12
|
+
include BootstrapForm::ViewHelper
|
13
13
|
end
|
@@ -1,460 +1,481 @@
|
|
1
|
-
require_relative 'aliasing'
|
2
|
-
require_relative 'helpers/bootstrap'
|
3
|
-
|
4
1
|
module BootstrapForm
|
5
2
|
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
3
|
|
11
|
-
FIELD_HELPERS = %w
|
12
|
-
|
13
|
-
range_field
|
14
|
-
url_field
|
4
|
+
FIELD_HELPERS = %w[
|
5
|
+
color_field file_field phone_field text_field
|
6
|
+
date_field month_field range_field time_field
|
7
|
+
datetime_field number_field search_field url_field
|
8
|
+
email_field password_field text_area week_field
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
# Container for bootstrap specific form builder options. It controls options
|
12
|
+
# that define form layout and grid sizing.
|
13
|
+
class BootstrapOptions
|
14
|
+
|
15
|
+
attr_reader :layout,
|
16
|
+
:label_col_class,
|
17
|
+
:control_col_class,
|
18
|
+
:label_align_class,
|
19
|
+
:inline_margin_class
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
@layout = options[:layout] || "default"
|
23
|
+
@label_col_class = options[:label_col_class] || "col-sm-2"
|
24
|
+
@control_col_class = options[:control_col_class] || "col-sm-10"
|
25
|
+
@label_align_class = options[:label_align_class] || "text-sm-right"
|
26
|
+
@inline_margin_class = options[:inline_margin_class] || "mr-sm-2"
|
27
|
+
end
|
15
28
|
|
16
|
-
|
29
|
+
def horizontal?
|
30
|
+
@layout.to_s == "horizontal"
|
31
|
+
end
|
17
32
|
|
18
|
-
|
33
|
+
def inline?
|
34
|
+
@layout.to_s == "inline"
|
35
|
+
end
|
19
36
|
|
20
|
-
|
21
|
-
|
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
|
37
|
+
def offset_col_class
|
38
|
+
label_col_class.sub(/\Acol-(\w+)-(\d+)\z/, 'offset-\1-\2')
|
29
39
|
end
|
30
|
-
@acts_like_form_tag = options[:acts_like_form_tag]
|
31
40
|
|
32
|
-
super
|
33
41
|
end
|
34
42
|
|
35
|
-
|
36
|
-
with_method_name = "#{method_name}_with_bootstrap"
|
37
|
-
without_method_name = "#{method_name}_without_bootstrap"
|
43
|
+
delegate :content_tag, :capture, :concat, to: :@template
|
38
44
|
|
39
|
-
|
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
|
45
|
+
attr_accessor :bootstrap
|
46
46
|
|
47
|
-
|
47
|
+
def initialize(object_name, object, template, options)
|
48
|
+
@bootstrap = BootstrapOptions.new(options.delete(:bootstrap) || {})
|
49
|
+
super(object_name, object, template, options)
|
48
50
|
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
# Overriding default methods to forward everything to field_helper
|
53
|
+
FIELD_HELPERS.each do |field_helper|
|
54
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
55
|
+
def #{field_helper}(method, options = {})
|
56
|
+
field_helper(method, options) do
|
57
|
+
super(method, options)
|
58
|
+
end
|
57
59
|
end
|
58
|
-
|
59
|
-
|
60
|
-
bootstrap_method_alias method_name
|
60
|
+
RUBY_EVAL
|
61
61
|
end
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
# Wrapper for select helper. Boostrap options are sent via html_options hash:
|
64
|
+
#
|
65
|
+
# select :choices, ["a", "b"], {}, bootstrap: {label: {text: "Custom"}}
|
66
|
+
#
|
67
|
+
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
68
|
+
bootstrap_options = (html_options.delete(:bootstrap) || {})
|
69
|
+
draw_form_group(bootstrap_options, method, html_options) do
|
70
|
+
super(method, choices, options, html_options, &block)
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
69
|
-
|
74
|
+
# Wrapper around checkbox. Example usage:
|
75
|
+
#
|
76
|
+
# checkbox :agree, bootstrap: {label: {text: "Do you agree?"}}
|
77
|
+
#
|
78
|
+
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
79
|
+
bootstrap_options = options.delete(:bootstrap) || {}
|
80
|
+
bootstrap_label_options = bootstrap_options[:label] || {}
|
70
81
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
help_text = draw_help(bootstrap_options[:help])
|
83
|
+
errors = draw_errors(method)
|
84
|
+
|
85
|
+
add_css_class!(options, "form-check-input")
|
86
|
+
add_css_class!(options, "is-invalid") if errors.present?
|
87
|
+
|
88
|
+
label_text = nil
|
89
|
+
if (custom_text = bootstrap_label_options[:text]).present?
|
90
|
+
label_text = custom_text
|
78
91
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
92
|
+
|
93
|
+
fieldset_css_class = "form-group"
|
94
|
+
fieldset_css_class << " row" if bootstrap.horizontal?
|
95
|
+
fieldset_css_class << " #{bootstrap.inline_margin_class}" if bootstrap.inline?
|
96
|
+
|
97
|
+
content_tag(:fieldset, class: fieldset_css_class) do
|
98
|
+
draw_control_column(offset: true) do
|
99
|
+
content_tag(:div, class: "form-check") do
|
100
|
+
concat super(method, options, checked_value, unchecked_value)
|
101
|
+
concat label(method, label_text, class: "form-check-label")
|
102
|
+
concat errors if errors.present?
|
103
|
+
concat help_text if help_text.present?
|
84
104
|
end
|
85
105
|
end
|
86
106
|
end
|
87
107
|
end
|
88
108
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
109
|
+
# Helper to generate multiple radio buttons. Example usage:
|
110
|
+
#
|
111
|
+
# collection_radio_buttons :choices, ["a", "b"], :to_s, :to_s %>
|
112
|
+
# collection_radio_buttons :choices, [["a", "Label A"], ["b", "Label B"]], :first, :second
|
113
|
+
# collection_radio_buttons :choices, Choice.all, :id, :label
|
114
|
+
#
|
115
|
+
# Takes bootstrap options:
|
116
|
+
# inline: true - to render inputs inline
|
117
|
+
# label: {text: "Custom"} - to specify a label
|
118
|
+
# label: {hide: true} - to not render label at all
|
119
|
+
#
|
120
|
+
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {})
|
121
|
+
bootstrap_options = (options.delete(:bootstrap) || {})
|
122
|
+
|
123
|
+
args = [bootstrap_options, method, collection, value_method, text_method, options, html_options]
|
124
|
+
draw_choices(*args) do |m, v, opts|
|
125
|
+
radio_button(m, v, opts)
|
94
126
|
end
|
95
127
|
end
|
96
128
|
|
97
|
-
|
129
|
+
# Helper to generate multiple checkboxes. Same options as for radio buttons.
|
130
|
+
# Example usage:
|
131
|
+
#
|
132
|
+
# collection_check_boxes :choices, Choice.all, :id, :label
|
133
|
+
#
|
134
|
+
def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {})
|
135
|
+
bootstrap_options = (options.delete(:bootstrap) || {})
|
98
136
|
|
99
|
-
|
100
|
-
|
101
|
-
|
137
|
+
content = "".html_safe
|
138
|
+
unless options[:include_hidden] == false
|
139
|
+
content << hidden_field(method, multiple: true, value: "")
|
102
140
|
end
|
103
|
-
end
|
104
|
-
|
105
|
-
bootstrap_method_alias :grouped_collection_select
|
106
141
|
|
107
|
-
|
108
|
-
|
109
|
-
|
142
|
+
args = [bootstrap_options, method, collection, value_method, text_method, options, html_options]
|
143
|
+
content << draw_choices(*args) do |m, v, opts|
|
144
|
+
opts[:multiple] = true
|
145
|
+
opts[:include_hidden] = false
|
146
|
+
ActionView::Helpers::FormBuilder.instance_method(:check_box).bind(self).call(m, opts, v)
|
110
147
|
end
|
111
148
|
end
|
112
149
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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}"
|
150
|
+
# Bootstrap wrapper for readonly text field that is shown as plain text.
|
151
|
+
#
|
152
|
+
# plaintext(:value)
|
153
|
+
#
|
154
|
+
def plaintext(method, options = {})
|
155
|
+
bootstrap_options = (options.delete(:bootstrap) || {})
|
156
|
+
draw_form_group(bootstrap_options, method, options) do
|
157
|
+
remove_css_class!(options, "form-control")
|
158
|
+
add_css_class!(options, "form-control-plaintext")
|
159
|
+
options[:readonly] = true
|
160
|
+
ActionView::Helpers::FormBuilder.instance_method(:text_field).bind(self).call(method, options)
|
131
161
|
end
|
162
|
+
end
|
132
163
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
164
|
+
# Add bootstrap formatted submit button. If you need to change its type or
|
165
|
+
# add another css class, you need to override all css classes like so:
|
166
|
+
#
|
167
|
+
# submit(class: "btn btn-info custom-class")
|
168
|
+
#
|
169
|
+
# You may add additional content that directly follows the button. Here's
|
170
|
+
# an example of a cancel link:
|
171
|
+
#
|
172
|
+
# submit do
|
173
|
+
# link_to("Cancel", "/", class: "btn btn-link")
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
def submit(value = nil, options = {}, &block)
|
177
|
+
value, options = nil, value if value.is_a?(Hash)
|
178
|
+
add_css_class!(options, "btn")
|
179
|
+
|
180
|
+
form_group_class = "form-group"
|
181
|
+
form_group_class << " row" if bootstrap.horizontal?
|
182
|
+
|
183
|
+
content_tag(:div, class: form_group_class) do
|
184
|
+
draw_control_column(offset: true) do
|
185
|
+
out = super(value, options)
|
186
|
+
out << capture(&block) if block_given?
|
187
|
+
out
|
142
188
|
end
|
143
189
|
end
|
144
190
|
end
|
145
191
|
|
146
|
-
|
192
|
+
# Same as submit button, only with btn-primary class added
|
193
|
+
def primary(value = nil, options = {}, &block)
|
194
|
+
add_css_class!(options, "btn-primary")
|
195
|
+
submit(value, options, &block)
|
196
|
+
end
|
147
197
|
|
148
|
-
|
149
|
-
|
150
|
-
|
198
|
+
# Helper method to put arbitrary content in markup that renders correctly
|
199
|
+
# for the Bootstrap form. Example:
|
200
|
+
#
|
201
|
+
# form_group bootstrap: {label: {text: "Label"}} do
|
202
|
+
# "Some content"
|
203
|
+
# end
|
204
|
+
#
|
205
|
+
def form_group(options = {}, &block)
|
206
|
+
bootstrap_options = options.delete(:bootstrap) || {}
|
207
|
+
bootstrap_label_options = bootstrap_options.delete(:label) || {}
|
151
208
|
|
152
|
-
|
209
|
+
label_text = bootstrap_label_options[:text]
|
153
210
|
|
154
|
-
|
155
|
-
|
211
|
+
label = if label_text.present?
|
212
|
+
label_options = {}
|
213
|
+
add_css_class!(label_options, bootstrap_label_options[:class])
|
156
214
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
215
|
+
if bootstrap.horizontal?
|
216
|
+
add_css_class!(label_options, "col-form-label")
|
217
|
+
add_css_class!(label_options, bootstrap.label_col_class)
|
218
|
+
add_css_class!(label_options, bootstrap.label_align_class)
|
219
|
+
elsif bootstrap.inline?
|
220
|
+
add_css_class!(label_options, bootstrap.inline_margin_class)
|
163
221
|
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
bootstrap_method_alias :radio_button
|
168
222
|
|
169
|
-
|
170
|
-
html = inputs_collection(*args) do |name, value, options|
|
171
|
-
options[:multiple] = true
|
172
|
-
check_box(name, options, value, nil)
|
223
|
+
content_tag(:label, label_text, label_options)
|
173
224
|
end
|
174
|
-
hidden_field(args.first,{value: "", multiple: true}).concat(html)
|
175
|
-
end
|
176
225
|
|
177
|
-
|
226
|
+
form_group_class = "form-group"
|
227
|
+
form_group_class << " row" if bootstrap.horizontal?
|
228
|
+
form_group_class << " mr-sm-2" if bootstrap.inline?
|
178
229
|
|
179
|
-
|
180
|
-
|
181
|
-
|
230
|
+
content_tag(:div, class: form_group_class) do
|
231
|
+
content = "".html_safe
|
232
|
+
content << label if label.present?
|
233
|
+
content << draw_control_column(offset: label.blank?) do
|
234
|
+
yield
|
235
|
+
end
|
182
236
|
end
|
183
237
|
end
|
184
238
|
|
185
|
-
|
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
|
239
|
+
private
|
220
240
|
|
221
|
-
|
241
|
+
# Wrapper for all field helpers. Example usage:
|
242
|
+
#
|
243
|
+
# bootstrap_form_with model: @user do |form|
|
244
|
+
# form.text_field :name
|
245
|
+
# end
|
246
|
+
#
|
247
|
+
# Output of the `text_field` will be wrapped in Bootstrap markup
|
248
|
+
#
|
249
|
+
def field_helper(method, options, &block)
|
250
|
+
bootstrap_options = (options.delete(:bootstrap) || {})
|
251
|
+
draw_form_group(bootstrap_options, method, options) do
|
252
|
+
yield
|
222
253
|
end
|
223
254
|
end
|
224
255
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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
|
256
|
+
# form group wrapper for input fields
|
257
|
+
def draw_form_group(bootstrap_options, method, options, &block)
|
258
|
+
label = draw_label(bootstrap_options, method)
|
259
|
+
errors = draw_errors(method)
|
234
260
|
|
235
|
-
|
261
|
+
control = draw_control(bootstrap_options, errors, method, options) do
|
262
|
+
yield
|
263
|
+
end
|
236
264
|
|
237
|
-
|
265
|
+
form_group_class = "form-group"
|
266
|
+
form_group_class << " row" if bootstrap.horizontal?
|
267
|
+
form_group_class << " mr-sm-2" if bootstrap.inline?
|
238
268
|
|
239
|
-
|
240
|
-
|
269
|
+
content_tag(:div, class: form_group_class) do
|
270
|
+
concat label
|
271
|
+
concat control
|
272
|
+
end
|
241
273
|
end
|
242
274
|
|
243
|
-
def
|
244
|
-
|
245
|
-
end
|
275
|
+
def draw_errors(method)
|
276
|
+
return unless (errors = object && object.errors[method]).present?
|
246
277
|
|
247
|
-
|
248
|
-
|
278
|
+
content_tag(:div, class: "invalid-feedback") do
|
279
|
+
errors.join(", ")
|
280
|
+
end
|
249
281
|
end
|
250
282
|
|
251
|
-
|
252
|
-
|
253
|
-
|
283
|
+
# Renders label for a given field. Takes following bootstrap options:
|
284
|
+
#
|
285
|
+
# :text - replace default label text
|
286
|
+
# :class - css class on the label
|
287
|
+
# :hide - if `true` will render for screen readers only
|
288
|
+
#
|
289
|
+
# This is how those options can be passed in:
|
290
|
+
#
|
291
|
+
# text_field(:value, bootstrap: {label: {text: "Custom", class: "custom"}})
|
292
|
+
#
|
293
|
+
def draw_label(bootstrap_options, method)
|
294
|
+
bootstrap_label_options = bootstrap_options[:label] || {}
|
295
|
+
|
296
|
+
text = nil
|
297
|
+
options = {}
|
298
|
+
|
299
|
+
if (custom_text = bootstrap_label_options[:text]).present?
|
300
|
+
text = custom_text
|
301
|
+
end
|
254
302
|
|
255
|
-
|
256
|
-
"
|
257
|
-
|
303
|
+
add_css_class!(options, bootstrap_label_options[:class])
|
304
|
+
add_css_class!(options, "sr-only") if bootstrap_label_options[:hide]
|
305
|
+
add_css_class!(options, bootstrap.inline_margin_class) if bootstrap.inline?
|
258
306
|
|
259
|
-
|
260
|
-
|
261
|
-
|
307
|
+
if bootstrap.horizontal?
|
308
|
+
add_css_class!(options, "col-form-label")
|
309
|
+
add_css_class!(options, bootstrap.label_col_class)
|
310
|
+
add_css_class!(options, bootstrap.label_align_class)
|
311
|
+
end
|
262
312
|
|
263
|
-
|
264
|
-
"form-control"
|
313
|
+
label(method, text, options)
|
265
314
|
end
|
266
315
|
|
267
|
-
|
268
|
-
|
269
|
-
|
316
|
+
# Renders control for a given field
|
317
|
+
def draw_control(bootstrap_options, errors, method, options, &block)
|
318
|
+
bootstrap_label_options = bootstrap_options[:label] || {}
|
270
319
|
|
271
|
-
|
272
|
-
"
|
273
|
-
end
|
320
|
+
add_css_class!(options, "form-control")
|
321
|
+
add_css_class!(options, "is-invalid") if errors.present?
|
274
322
|
|
275
|
-
|
276
|
-
"has-feedback"
|
277
|
-
end
|
323
|
+
offset = !!bootstrap_label_options[:hide]
|
278
324
|
|
279
|
-
|
280
|
-
|
325
|
+
draw_control_column(offset: offset) do
|
326
|
+
draw_input_group(bootstrap_options, errors) do
|
327
|
+
yield
|
328
|
+
end
|
329
|
+
end
|
281
330
|
end
|
282
331
|
|
283
|
-
|
284
|
-
|
332
|
+
# Wrapping in control in column wrapper
|
333
|
+
#
|
334
|
+
def draw_control_column(offset:, &block)
|
335
|
+
return yield unless bootstrap.horizontal?
|
336
|
+
css_class = "#{bootstrap.control_col_class}"
|
337
|
+
css_class << " #{bootstrap.offset_col_class}" if offset
|
338
|
+
content_tag(:div, class: css_class) do
|
339
|
+
yield
|
340
|
+
end
|
285
341
|
end
|
286
342
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
343
|
+
# Wraps input field in input group container that allows prepending and
|
344
|
+
# appending text or html. Example:
|
345
|
+
#
|
346
|
+
# text_field(:value, bootstrap: {prepend: "$.$$"}})
|
347
|
+
# text_field(:value, bootstrap: {append: {html: "<button>Go</button>"}}})
|
348
|
+
#
|
349
|
+
def draw_input_group(bootstrap_options, errors, &block)
|
350
|
+
prepend_html = draw_input_group_content(bootstrap_options, :prepend)
|
351
|
+
append_html = draw_input_group_content(bootstrap_options, :append)
|
352
|
+
|
353
|
+
help_text = draw_help(bootstrap_options[:help])
|
354
|
+
|
355
|
+
# Not prepending or appending anything. Bail.
|
356
|
+
if prepend_html.blank? && append_html.blank?
|
357
|
+
content = capture(&block)
|
358
|
+
content << errors if errors.present?
|
359
|
+
content << help_text if help_text.present?
|
360
|
+
return content
|
305
361
|
end
|
306
362
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
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)
|
363
|
+
content_tag(:div, class: "input-group") do
|
364
|
+
concat prepend_html if prepend_html.present?
|
365
|
+
concat capture(&block)
|
366
|
+
concat append_html if append_html.present?
|
367
|
+
concat errors if errors.present?
|
368
|
+
concat help_text if help_text.present?
|
341
369
|
end
|
370
|
+
end
|
342
371
|
|
343
|
-
|
344
|
-
|
345
|
-
|
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)
|
372
|
+
def draw_input_group_content(bootstrap_options, type)
|
373
|
+
value = bootstrap_options[type]
|
374
|
+
return unless value.present?
|
351
375
|
|
352
|
-
|
353
|
-
|
376
|
+
content_tag(:div, class: "input-group-#{type}") do
|
377
|
+
if value.is_a?(Hash) && value[:html].present?
|
378
|
+
value[:html]
|
379
|
+
else
|
380
|
+
content_tag(:span, value, class: "input-group-text")
|
354
381
|
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
382
|
end
|
366
383
|
end
|
367
384
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
385
|
+
# Drawing boostrap form field help text. Example usage:
|
386
|
+
#
|
387
|
+
# text_field(:value, bootstrap: {help: "help text"})
|
388
|
+
#
|
389
|
+
def draw_help(text)
|
390
|
+
return if text.blank?
|
391
|
+
content_tag(:small, text, class: "form-text text-muted")
|
372
392
|
end
|
373
393
|
|
374
|
-
|
375
|
-
|
376
|
-
|
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
|
394
|
+
# Rendering of choices for checkboxes and radio buttons
|
395
|
+
def draw_choices(bootstrap_options, method, collection, value_method, text_method, options, html_options, &input)
|
396
|
+
add_css_class!(html_options, "form-check-input")
|
381
397
|
|
382
|
-
|
398
|
+
draw_form_group_fieldset(bootstrap_options, method, html_options) do
|
383
399
|
|
384
|
-
|
385
|
-
|
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
|
400
|
+
form_check_css_class = "form-check"
|
401
|
+
form_check_css_class << " form-check-inline" if bootstrap_options[:inline]
|
391
402
|
|
392
|
-
|
403
|
+
errors = draw_errors(method)
|
404
|
+
help_text = draw_help(bootstrap_options[:help])
|
393
405
|
|
394
|
-
|
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
|
406
|
+
add_css_class!(html_options, "is-invalid") if errors.present?
|
400
407
|
|
401
|
-
|
402
|
-
|
408
|
+
content = "".html_safe
|
409
|
+
collection.each_with_index.map do |item, index|
|
410
|
+
item_value = item.send(value_method)
|
411
|
+
item_text = item.send(text_method)
|
403
412
|
|
404
|
-
|
405
|
-
|
413
|
+
content << content_tag(:div, class: form_check_css_class) do
|
414
|
+
concat input.call(method, item_value, html_options)
|
415
|
+
concat label(method, item_text, value: item_value, class: "form-check-label")
|
416
|
+
if ((collection.count - 1) == index) && !bootstrap_options[:inline]
|
417
|
+
concat errors if errors.present?
|
418
|
+
concat help_text if help_text.present?
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
406
422
|
|
407
|
-
|
408
|
-
|
409
|
-
|
423
|
+
if bootstrap_options[:inline]
|
424
|
+
content << errors if errors.present?
|
425
|
+
content << help_text if help_text.present?
|
426
|
+
end
|
410
427
|
|
411
|
-
|
412
|
-
|
428
|
+
content
|
429
|
+
end
|
413
430
|
end
|
414
431
|
|
415
|
-
|
416
|
-
|
417
|
-
|
432
|
+
# Wrapper for collections of radio buttons and checkboxes
|
433
|
+
def draw_form_group_fieldset(bootstrap_options, method, options, &block)
|
434
|
+
bootstrap_label_options = bootstrap_options[:label] || {}
|
418
435
|
|
419
|
-
|
420
|
-
|
436
|
+
unless bootstrap_label_options[:hide]
|
437
|
+
label_text = bootstrap_label_options.delete(:text)
|
438
|
+
label_text ||= ActionView::Helpers::Tags::Label::LabelBuilder
|
439
|
+
.new(@template, @object_name.to_s, method, @object, nil).translation
|
421
440
|
|
422
|
-
|
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
|
441
|
+
add_css_class!(bootstrap_label_options, "col-form-label pt-0")
|
429
442
|
|
430
|
-
|
431
|
-
|
443
|
+
if bootstrap.horizontal?
|
444
|
+
add_css_class!(bootstrap_label_options, bootstrap.label_col_class)
|
445
|
+
add_css_class!(bootstrap_label_options, bootstrap.label_align_class)
|
432
446
|
end
|
433
447
|
|
434
|
-
|
448
|
+
label = content_tag(:legend, bootstrap_label_options) do
|
449
|
+
label_text
|
450
|
+
end
|
435
451
|
end
|
436
|
-
end
|
437
452
|
|
438
|
-
|
439
|
-
|
453
|
+
content_tag(:fieldset, class: "form-group") do
|
454
|
+
content = "".html_safe
|
455
|
+
content << label if label.present?
|
456
|
+
content << draw_control_column(offset: bootstrap_label_options[:hide]) do
|
457
|
+
yield
|
458
|
+
end
|
440
459
|
|
441
|
-
if
|
442
|
-
|
443
|
-
partial_scope = object.class.model_name.respond_to?(:name) ? object.class.model_name.name : object.class.model_name
|
460
|
+
if bootstrap.horizontal?
|
461
|
+
content_tag(:div, content, class: "row")
|
444
462
|
else
|
445
|
-
|
463
|
+
content
|
446
464
|
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
465
|
end
|
457
466
|
end
|
458
467
|
|
468
|
+
def add_css_class!(options, string)
|
469
|
+
css_class = [options[:class], string].compact.join(" ")
|
470
|
+
options[:class] = css_class if css_class.present?
|
471
|
+
end
|
472
|
+
|
473
|
+
def remove_css_class!(options, string)
|
474
|
+
css_class = options[:class].to_s.split(" ")
|
475
|
+
options[:class] = (css_class - [string]).compact.join(" ")
|
476
|
+
options.delete(:class) if options[:class].blank?
|
477
|
+
end
|
478
|
+
|
459
479
|
end
|
480
|
+
|
460
481
|
end
|