bootstrap_form 4.5.0 → 5.0.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/.github/workflows/ruby.yml +46 -0
- data/.gitignore +16 -1
- data/.rubocop.yml +17 -14
- data/CHANGELOG.md +32 -1
- data/CONTRIBUTING.md +65 -5
- data/Dangerfile +5 -7
- data/Dockerfile +26 -0
- data/Gemfile +4 -3
- data/README.md +63 -40
- data/UPGRADE-4.0.md +1 -1
- data/UPGRADE-5.0.md +25 -0
- data/bootstrap_form.gemspec +8 -6
- data/demo/app/assets/config/manifest.js +1 -2
- data/demo/app/helpers/bootstrap_helper.rb +4 -4
- data/demo/app/views/bootstrap/form.html.erb +13 -0
- data/demo/app/views/layouts/application.html.erb +3 -3
- data/demo/config/environments/development.rb +1 -1
- data/demo/config/puma.rb +2 -2
- data/demo/db/schema.rb +2 -2
- data/docker-compose.yml +70 -0
- data/gemfiles/5.2.gemfile +2 -15
- data/gemfiles/6.0.gemfile +2 -17
- data/gemfiles/6.1.gemfile +4 -0
- data/gemfiles/edge.gemfile +2 -17
- data/lib/bootstrap_form/components/labels.rb +1 -1
- data/lib/bootstrap_form/components/validation.rb +1 -1
- data/lib/bootstrap_form/configuration.rb +1 -2
- data/lib/bootstrap_form/form_builder.rb +2 -4
- data/lib/bootstrap_form/form_group.rb +21 -10
- data/lib/bootstrap_form/form_group_builder.rb +6 -8
- data/lib/bootstrap_form/helpers/bootstrap.rb +11 -10
- data/lib/bootstrap_form/inputs/base.rb +5 -5
- data/lib/bootstrap_form/inputs/check_box.rb +8 -22
- data/lib/bootstrap_form/inputs/collection_select.rb +1 -0
- data/lib/bootstrap_form/inputs/file_field.rb +3 -15
- data/lib/bootstrap_form/inputs/grouped_collection_select.rb +1 -0
- data/lib/bootstrap_form/inputs/radio_button.rb +7 -25
- data/lib/bootstrap_form/inputs/select.rb +1 -0
- data/lib/bootstrap_form/inputs/time_zone_select.rb +1 -0
- data/lib/bootstrap_form/version.rb +1 -1
- data/lib/bootstrap_form.rb +1 -2
- metadata +24 -6
- data/.travis.yml +0 -35
data/bootstrap_form.gemspec
CHANGED
@@ -3,6 +3,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
require "bootstrap_form/version"
|
5
5
|
|
6
|
+
REQUIRED_RAILS_VERSION = ">= 5.2".freeze
|
7
|
+
|
6
8
|
Gem::Specification.new do |s|
|
7
9
|
s.name = "bootstrap_form"
|
8
10
|
s.version = BootstrapForm::VERSION
|
@@ -10,13 +12,11 @@ Gem::Specification.new do |s|
|
|
10
12
|
s.email = ["potenza@gmail.com", "carlos.el.lopes@gmail.com"]
|
11
13
|
s.homepage = "https://github.com/bootstrap-ruby/bootstrap_form"
|
12
14
|
s.summary = "Rails form builder that makes it easy to style forms using "\
|
13
|
-
"Bootstrap
|
15
|
+
"Bootstrap 5"
|
14
16
|
s.description = "bootstrap_form is a rails form builder that makes it super "\
|
15
|
-
"easy to create beautiful-looking forms using Bootstrap
|
17
|
+
"easy to create beautiful-looking forms using Bootstrap 5"
|
16
18
|
s.license = "MIT"
|
17
19
|
|
18
|
-
s.post_install_message = "Default form attribute role=\"form\" will be dropped in 5.0.0"
|
19
|
-
|
20
20
|
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
21
21
|
f.match(%r{^(test)/})
|
22
22
|
end
|
@@ -26,6 +26,8 @@ Gem::Specification.new do |s|
|
|
26
26
|
|
27
27
|
s.required_ruby_version = ">= 2.5"
|
28
28
|
|
29
|
-
s.add_dependency("actionpack",
|
30
|
-
s.add_dependency("activemodel",
|
29
|
+
s.add_dependency("actionpack", REQUIRED_RAILS_VERSION)
|
30
|
+
s.add_dependency("activemodel", REQUIRED_RAILS_VERSION)
|
31
|
+
|
32
|
+
s.add_development_dependency("rails", REQUIRED_RAILS_VERSION)
|
31
33
|
end
|
@@ -1,2 +1 @@
|
|
1
|
-
//=
|
2
|
-
//= link_directory ../stylesheets .css
|
1
|
+
//= link application.css
|
@@ -2,7 +2,7 @@ module BootstrapHelper
|
|
2
2
|
def form_with_source(&block)
|
3
3
|
form_html = capture(&block)
|
4
4
|
|
5
|
-
|
5
|
+
tag.div(class: "example") do
|
6
6
|
concat(form_html)
|
7
7
|
concat(toggle)
|
8
8
|
concat(codemirror(form_html))
|
@@ -12,15 +12,15 @@ module BootstrapHelper
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def codemirror(form_html)
|
15
|
-
|
16
|
-
|
15
|
+
tag.div(class: "code", style: "display: none") do
|
16
|
+
tag.textarea(class: "codemirror") do
|
17
17
|
HtmlBeautifier.beautify(form_html.strip.gsub(">", ">\n").gsub("<", "\n<"))
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def toggle
|
23
|
-
|
23
|
+
tag.button(class: "toggle btn btn-sm btn-info") do
|
24
24
|
"Show Source Code"
|
25
25
|
end
|
26
26
|
end
|
@@ -52,3 +52,16 @@
|
|
52
52
|
<%= form.submit %>
|
53
53
|
<% end %>
|
54
54
|
<% end %>
|
55
|
+
|
56
|
+
<h3>Floating Labels</h3>
|
57
|
+
|
58
|
+
<%= form_with_source do %>
|
59
|
+
<%= bootstrap_form_for @user do |form| %>
|
60
|
+
<%= form.email_field :email, placeholder: "Enter Email", label: "Email address", help: "We'll never share your email with anyone else", floating: true %>
|
61
|
+
<%= form.password_field :password, placeholder: "Password", floating: true %>
|
62
|
+
<%= form.text_field :misc, floating: true %>
|
63
|
+
<%= form.text_area :comments, floating: true %>
|
64
|
+
<%= form.select :status, [["Active", 1], ["Inactive", 2]], include_blank: "Select a value", floating: true %>
|
65
|
+
<%= form.submit %>
|
66
|
+
<% end %>
|
67
|
+
<% end %>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
7
7
|
|
8
8
|
<!-- Bootstrap CSS -->
|
9
|
-
<link
|
9
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
|
10
10
|
|
11
11
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/codemirror.min.css">
|
12
12
|
|
@@ -44,8 +44,8 @@
|
|
44
44
|
<!-- Optional JavaScript -->
|
45
45
|
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
46
46
|
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
47
|
-
<script src="https://
|
48
|
-
<script src="https://
|
47
|
+
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.1/dist/umd/popper.min.js" integrity="sha384-SR1sx49pcuLnqZUnnPwx6FCym0wLsk5JZuNx2bPPENzswTNFaQU1RDvt3wT4gWFG" crossorigin="anonymous"></script>
|
48
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.min.js" integrity="sha384-j0CNLUeiqtyaRmlzUHCPZ+Gy5fQu0dQ6eZ/xAww941Ai1SxSY+0EQqNXNE6DZiVc" crossorigin="anonymous"></script>
|
49
49
|
|
50
50
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/codemirror.min.js"></script>
|
51
51
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/mode/htmlmixed/htmlmixed.min.js"></script>
|
@@ -16,7 +16,7 @@ Rails.application.configure do
|
|
16
16
|
|
17
17
|
# Enable/disable caching. By default caching is disabled.
|
18
18
|
# Run rails dev:cache to toggle caching.
|
19
|
-
if Rails.root.join("tmp
|
19
|
+
if Rails.root.join("tmp/caching-dev.txt").exist?
|
20
20
|
config.action_controller.perform_caching = true
|
21
21
|
|
22
22
|
config.cache_store = :memory_store
|
data/demo/config/puma.rb
CHANGED
@@ -4,12 +4,12 @@
|
|
4
4
|
# the maximum value specified for Puma. Default is set to 5 threads for minimum
|
5
5
|
# and maximum; this matches the default thread size of Active Record.
|
6
6
|
#
|
7
|
-
threads_count = ENV.fetch("RAILS_MAX_THREADS"
|
7
|
+
threads_count = ENV.fetch("RAILS_MAX_THREADS", 5)
|
8
8
|
threads threads_count, threads_count
|
9
9
|
|
10
10
|
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
|
11
11
|
#
|
12
|
-
port ENV.fetch("PORT"
|
12
|
+
port ENV.fetch("PORT", 3000)
|
13
13
|
|
14
14
|
# Specifies the `environment` that Puma will run in.
|
15
15
|
#
|
data/demo/db/schema.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
# of editing this file, please use the migrations feature of Active Record to
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
4
4
|
#
|
5
|
-
# This file is the source Rails uses to define your schema when running `rails
|
6
|
-
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
5
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
6
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
7
7
|
# be faster and is potentially less error prone than running all of your
|
8
8
|
# migrations from scratch. Old migrations may fail to apply correctly if those
|
9
9
|
# migrations use external dependencies or application code.
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
version: '2.4'
|
2
|
+
|
3
|
+
services:
|
4
|
+
app: &app
|
5
|
+
build:
|
6
|
+
context: .
|
7
|
+
args:
|
8
|
+
RUBY_VERSION: '2.7.1'
|
9
|
+
NODE_MAJOR: '12'
|
10
|
+
YARN_VERSION: '1.22.4'
|
11
|
+
BUNDLER_VERSION: '2.1.4'
|
12
|
+
image: bootstrap-form:0.0.1
|
13
|
+
tmpfs:
|
14
|
+
- /tmp
|
15
|
+
|
16
|
+
backend: &backend
|
17
|
+
<<: *app
|
18
|
+
stdin_open: true
|
19
|
+
tty: true
|
20
|
+
volumes:
|
21
|
+
- .:/app:cached
|
22
|
+
- rails_cache:/app/tmp/cache
|
23
|
+
- bundle:/usr/local/bundle
|
24
|
+
- node_modules:/app/node_modules
|
25
|
+
- packs:/app/public/packs
|
26
|
+
environment:
|
27
|
+
- NODE_ENV=development
|
28
|
+
- RAILS_ENV=${RAILS_ENV:-development}
|
29
|
+
- BOOTSNAP_CACHE_DIR=/usr/local/bundle/_bootsnap
|
30
|
+
- WEBPACKER_DEV_SERVER_HOST=webpacker
|
31
|
+
- WEB_CONCURRENCY=1
|
32
|
+
- HISTFILE=/app/.bash_history
|
33
|
+
- EDITOR=vi
|
34
|
+
|
35
|
+
shell:
|
36
|
+
<<: *backend
|
37
|
+
command: /bin/bash
|
38
|
+
ports:
|
39
|
+
- '3000:3000'
|
40
|
+
|
41
|
+
server:
|
42
|
+
<<: *backend
|
43
|
+
command: sh -c "cd demo/app && bundle exec rails server -b 0.0.0.0"
|
44
|
+
ports:
|
45
|
+
- '3000:3000'
|
46
|
+
|
47
|
+
test:
|
48
|
+
<<: *backend
|
49
|
+
command: rake test
|
50
|
+
|
51
|
+
webpacker:
|
52
|
+
<<: *app
|
53
|
+
command: ./bin/webpack-dev-server
|
54
|
+
ports:
|
55
|
+
- '3035:3035'
|
56
|
+
volumes:
|
57
|
+
- .:/app:cached
|
58
|
+
- bundle:/usr/local/bundle
|
59
|
+
- node_modules:/app/node_modules
|
60
|
+
- packs:/app/public/packs
|
61
|
+
environment:
|
62
|
+
- NODE_ENV=${NODE_ENV:-development}
|
63
|
+
- RAILS_ENV=${RAILS_ENV:-development}
|
64
|
+
- WEBPACKER_DEV_SERVER_HOST=0.0.0.0
|
65
|
+
|
66
|
+
volumes:
|
67
|
+
bundle:
|
68
|
+
node_modules:
|
69
|
+
rails_cache:
|
70
|
+
packs:
|
data/gemfiles/5.2.gemfile
CHANGED
@@ -1,17 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
gemspec path: "../"
|
1
|
+
gems = "#{File.dirname __dir__}/Gemfile"
|
2
|
+
eval File.read(gems), binding, gems # rubocop: disable Security/Eval
|
4
3
|
|
5
4
|
gem "rails", "~> 5.2.0"
|
6
|
-
|
7
|
-
group :development do
|
8
|
-
gem "rubocop-rails", require: false
|
9
|
-
end
|
10
|
-
|
11
|
-
group :test do
|
12
|
-
gem "diffy"
|
13
|
-
gem "equivalent-xml"
|
14
|
-
gem "mocha"
|
15
|
-
gem "sqlite3", "~> 1.4"
|
16
|
-
gem "timecop", "~> 0.7.1"
|
17
|
-
end
|
data/gemfiles/6.0.gemfile
CHANGED
@@ -1,19 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
gemspec path: "../"
|
1
|
+
gems = "#{File.dirname __dir__}/Gemfile"
|
2
|
+
eval File.read(gems), binding, gems # rubocop: disable Security/Eval
|
4
3
|
|
5
4
|
gem "rails", "~> 6.0.0"
|
6
|
-
|
7
|
-
group :development do
|
8
|
-
gem "rubocop-rails", require: false
|
9
|
-
gem "sassc"
|
10
|
-
gem "webpacker", ">= 4.0.0.rc.3"
|
11
|
-
end
|
12
|
-
|
13
|
-
group :test do
|
14
|
-
gem "diffy"
|
15
|
-
gem "equivalent-xml"
|
16
|
-
gem "mocha"
|
17
|
-
gem "sqlite3"
|
18
|
-
gem "timecop", "~> 0.7.1"
|
19
|
-
end
|
data/gemfiles/edge.gemfile
CHANGED
@@ -1,19 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
gemspec path: "../"
|
1
|
+
gems = "#{File.dirname __dir__}/Gemfile"
|
2
|
+
eval File.read(gems), binding, gems # rubocop: disable Security/Eval
|
4
3
|
|
5
4
|
gem "rails", git: "https://github.com/rails/rails.git"
|
6
|
-
|
7
|
-
group :development do
|
8
|
-
gem "rubocop-rails", require: false
|
9
|
-
gem "sassc-rails"
|
10
|
-
gem "webpacker"
|
11
|
-
end
|
12
|
-
|
13
|
-
group :test do
|
14
|
-
gem "diffy"
|
15
|
-
gem "equivalent-xml"
|
16
|
-
gem "mocha"
|
17
|
-
gem "sqlite3"
|
18
|
-
gem "timecop", "~> 0.7.1"
|
19
|
-
end
|
@@ -23,7 +23,7 @@ module BootstrapForm
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def label_classes(name, options, custom_label_col, group_layout)
|
26
|
-
classes = [options[:class], label_layout_classes(custom_label_col, group_layout)]
|
26
|
+
classes = ["form-label", options[:class], label_layout_classes(custom_label_col, group_layout)]
|
27
27
|
|
28
28
|
case options.delete(:required)
|
29
29
|
when true
|
@@ -14,7 +14,7 @@ module BootstrapForm
|
|
14
14
|
def required_attribute?(obj, attribute)
|
15
15
|
return false unless obj && attribute
|
16
16
|
|
17
|
-
target = obj.
|
17
|
+
target = obj.instance_of?(Class) ? obj : obj.class
|
18
18
|
|
19
19
|
target_validators = if target.respond_to? :validators_on
|
20
20
|
target.validators_on(attribute).map(&:class)
|
@@ -16,8 +16,7 @@ module BootstrapForm
|
|
16
16
|
def default_form_attributes
|
17
17
|
return @default_form_attributes if defined? @default_form_attributes
|
18
18
|
|
19
|
-
|
20
|
-
{ role: "form" }
|
19
|
+
{}
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
@@ -43,9 +43,8 @@ module BootstrapForm
|
|
43
43
|
include BootstrapForm::Inputs::UrlField
|
44
44
|
include BootstrapForm::Inputs::WeekField
|
45
45
|
|
46
|
-
delegate :content_tag, :capture, :concat, to: :@template
|
46
|
+
delegate :content_tag, :capture, :concat, :tag, to: :@template
|
47
47
|
|
48
|
-
# rubocop:disable Metrics/AbcSize
|
49
48
|
def initialize(object_name, object, template, options)
|
50
49
|
@layout = options[:layout] || default_layout
|
51
50
|
@label_col = options[:label_col] || default_label_col
|
@@ -61,7 +60,6 @@ module BootstrapForm
|
|
61
60
|
add_default_form_attributes_and_form_inline options
|
62
61
|
super
|
63
62
|
end
|
64
|
-
# rubocop:enable Metrics/AbcSize
|
65
63
|
|
66
64
|
def add_default_form_attributes_and_form_inline(options)
|
67
65
|
options[:html] ||= {}
|
@@ -69,7 +67,7 @@ module BootstrapForm
|
|
69
67
|
|
70
68
|
return unless options[:layout] == :inline
|
71
69
|
|
72
|
-
options[:html][:class] = [options[:html][:class], "
|
70
|
+
options[:html][:class] = [options[:html][:class], "col-auto", "g-3"].compact.join(" ")
|
73
71
|
end
|
74
72
|
|
75
73
|
def fields_for_with_bootstrap(record_name, record_object=nil, fields_options={}, &block)
|
@@ -10,9 +10,9 @@ module BootstrapForm
|
|
10
10
|
|
11
11
|
options[:class] = form_group_classes(options)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
tag.div(**options.except(:append, :id, :label, :help, :icon,
|
14
|
+
:input_group_class, :label_col, :control_col,
|
15
|
+
:add_control_col_class, :layout, :prepend, :floating)) do
|
16
16
|
form_group_content(
|
17
17
|
generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]),
|
18
18
|
generate_help(name, options[:help]), options, &block
|
@@ -24,8 +24,8 @@ module BootstrapForm
|
|
24
24
|
|
25
25
|
def form_group_content_tag(name, field_name, without_field_name, options, html_options)
|
26
26
|
html_class = control_specific_class(field_name)
|
27
|
-
html_class = "#{html_class}
|
28
|
-
|
27
|
+
html_class = "#{html_class} col-auto g-3" if @layout == :horizontal && options[:skip_inline].blank?
|
28
|
+
tag.div(class: html_class) do
|
29
29
|
input_with_error(name) do
|
30
30
|
send(without_field_name, name, options, html_options)
|
31
31
|
end
|
@@ -34,10 +34,12 @@ module BootstrapForm
|
|
34
34
|
|
35
35
|
def form_group_content(label, help_text, options, &block)
|
36
36
|
if group_layout_horizontal?(options[:layout])
|
37
|
-
concat(label).concat(
|
37
|
+
concat(label).concat(tag.div(capture(&block) + help_text, class: form_group_control_class(options)))
|
38
38
|
else
|
39
|
-
|
39
|
+
# Floating labels need to be rendered after the field
|
40
|
+
concat(label) unless options[:floating]
|
40
41
|
concat(capture(&block))
|
42
|
+
concat(label) if options[:floating]
|
41
43
|
concat(help_text) if help_text
|
42
44
|
end
|
43
45
|
end
|
@@ -50,15 +52,24 @@ module BootstrapForm
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def form_group_classes(options)
|
53
|
-
classes = ["
|
54
|
-
classes << "row" if
|
55
|
-
classes << "
|
55
|
+
classes = ["mb-3", options[:class].try(:split)].flatten.compact
|
56
|
+
classes << "row" if horizontal_group_with_gutters?(options[:layout], classes)
|
57
|
+
classes << "col-auto g-3" if field_inline_override?(options[:layout])
|
56
58
|
classes << feedback_class if options[:icon]
|
59
|
+
classes << "form-floating" if options[:floating]
|
57
60
|
classes
|
58
61
|
end
|
59
62
|
|
63
|
+
def horizontal_group_with_gutters?(layout, classes)
|
64
|
+
group_layout_horizontal?(layout) && !classes_include_gutters?(classes)
|
65
|
+
end
|
66
|
+
|
60
67
|
def group_layout_horizontal?(layout)
|
61
68
|
get_group_layout(layout) == :horizontal
|
62
69
|
end
|
70
|
+
|
71
|
+
def classes_include_gutters?(classes)
|
72
|
+
classes.any? { |c| c =~ /^g-\d+$/ }
|
73
|
+
end
|
63
74
|
end
|
64
75
|
end
|
@@ -6,7 +6,7 @@ module BootstrapForm
|
|
6
6
|
|
7
7
|
private
|
8
8
|
|
9
|
-
def form_group_builder(method, options, html_options=nil)
|
9
|
+
def form_group_builder(method, options, html_options=nil, &block)
|
10
10
|
no_wrapper = options[:wrapper] == false
|
11
11
|
|
12
12
|
options = form_group_builder_options(options, method)
|
@@ -21,16 +21,14 @@ module BootstrapForm
|
|
21
21
|
if no_wrapper
|
22
22
|
yield
|
23
23
|
else
|
24
|
-
form_group(method, form_group_options)
|
24
|
+
form_group(method, form_group_options, &block)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def form_group_builder_options(options, method)
|
29
29
|
options.symbolize_keys!
|
30
30
|
options = convert_form_tag_options(method, options) if acts_like_form_tag
|
31
|
-
|
32
|
-
options[:required] = form_group_required(options) if options.key?(:skip_required)
|
33
|
-
end
|
31
|
+
options[:required] = form_group_required(options) if !options[:skip_label] && options.key?(:skip_required)
|
34
32
|
options
|
35
33
|
end
|
36
34
|
|
@@ -48,7 +46,8 @@ module BootstrapForm
|
|
48
46
|
id: options[:id], help: options[:help], icon: options[:icon],
|
49
47
|
label_col: options[:label_col], control_col: options[:control_col],
|
50
48
|
add_control_col_class: options[:add_control_col_class],
|
51
|
-
layout: get_group_layout(options[:layout]), class: options[:wrapper_class]
|
49
|
+
layout: get_group_layout(options[:layout]), class: options[:wrapper_class],
|
50
|
+
floating: options[:floating]
|
52
51
|
}
|
53
52
|
|
54
53
|
form_group_options.merge!(wrapper_options) if wrapper_options.is_a?(Hash)
|
@@ -57,12 +56,11 @@ module BootstrapForm
|
|
57
56
|
end
|
58
57
|
|
59
58
|
def form_group_label(options, css_options)
|
60
|
-
|
59
|
+
{
|
61
60
|
text: form_group_label_text(options[:label]),
|
62
61
|
class: form_group_label_class(options),
|
63
62
|
required: options[:required]
|
64
63
|
}.merge(css_options[:id].present? ? { for: css_options[:id] } : {})
|
65
|
-
hash
|
66
64
|
end
|
67
65
|
|
68
66
|
def form_group_label_text(label)
|
@@ -14,7 +14,7 @@ module BootstrapForm
|
|
14
14
|
def primary(name=nil, options={}, &block)
|
15
15
|
setup_css_class "btn btn-primary", options
|
16
16
|
|
17
|
-
if options[:render_as_button] ||
|
17
|
+
if options[:render_as_button] || block
|
18
18
|
options.except! :render_as_button
|
19
19
|
button(name, options, &block)
|
20
20
|
else
|
@@ -26,8 +26,8 @@ module BootstrapForm
|
|
26
26
|
css = options[:class] || "alert alert-danger"
|
27
27
|
return unless object.respond_to?(:errors) && object.errors.full_messages.any?
|
28
28
|
|
29
|
-
|
30
|
-
concat
|
29
|
+
tag.div class: css do
|
30
|
+
concat tag.p title
|
31
31
|
concat error_summary unless options[:error_summary] == false
|
32
32
|
end
|
33
33
|
end
|
@@ -35,9 +35,9 @@ module BootstrapForm
|
|
35
35
|
def error_summary
|
36
36
|
return unless object.errors.any?
|
37
37
|
|
38
|
-
|
38
|
+
tag.ul class: "rails-bootstrap-forms-error-summary" do
|
39
39
|
object.errors.full_messages.each do |error|
|
40
|
-
concat
|
40
|
+
concat tag.li(error)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -46,8 +46,9 @@ module BootstrapForm
|
|
46
46
|
return unless error?(name)
|
47
47
|
|
48
48
|
hide_attribute_name = options[:hide_attribute_name] || false
|
49
|
+
custom_class = options[:custom_class] || false
|
49
50
|
|
50
|
-
|
51
|
+
tag.div class: custom_class || "invalid-feedback" do
|
51
52
|
if hide_attribute_name
|
52
53
|
object.errors[name].join(", ")
|
53
54
|
else
|
@@ -85,7 +86,7 @@ module BootstrapForm
|
|
85
86
|
input = attach_input(options, :prepend) + input + attach_input(options, :append)
|
86
87
|
input += generate_error(name)
|
87
88
|
options.present? &&
|
88
|
-
input =
|
89
|
+
input = tag.div(input, class: ["input-group", options[:input_group_class]].compact)
|
89
90
|
input
|
90
91
|
end
|
91
92
|
|
@@ -95,9 +96,9 @@ module BootstrapForm
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def input_group_content(content)
|
98
|
-
return content if
|
99
|
+
return content if /btn/.match?(content)
|
99
100
|
|
100
|
-
|
101
|
+
tag.span(content, class: "input-group-text")
|
101
102
|
end
|
102
103
|
|
103
104
|
def static_class
|
@@ -108,7 +109,7 @@ module BootstrapForm
|
|
108
109
|
|
109
110
|
def attach_input(options, key)
|
110
111
|
tags = [*options[key]].map do |item|
|
111
|
-
|
112
|
+
input_group_content(item)
|
112
113
|
end
|
113
114
|
ActiveSupport::SafeBuffer.new(tags.join)
|
114
115
|
end
|
@@ -10,7 +10,8 @@ module BootstrapForm
|
|
10
10
|
define_method "#{field_name}_with_bootstrap" do |name, options={}|
|
11
11
|
form_group_builder(name, options) do
|
12
12
|
prepend_and_append_input(name, options) do
|
13
|
-
|
13
|
+
options[:placeholder] ||= name if options[:floating]
|
14
|
+
send("#{field_name}_without_bootstrap".to_sym, name, options.except(:floating))
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -19,11 +20,10 @@ module BootstrapForm
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def bootstrap_select_group(field_name)
|
22
|
-
|
23
|
-
|
24
|
-
define_method(with_field_name) do |name, options={}, html_options={}|
|
23
|
+
define_method("#{field_name}_with_bootstrap") do |name, options={}, html_options={}|
|
24
|
+
html_options = html_options.reverse_merge(control_class: "form-select")
|
25
25
|
form_group_builder(name, options, html_options) do
|
26
|
-
form_group_content_tag(name, field_name,
|
26
|
+
form_group_content_tag(name, field_name, "#{field_name}_without_bootstrap", options, html_options)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -10,10 +10,10 @@ module BootstrapForm
|
|
10
10
|
def check_box_with_bootstrap(name, options={}, checked_value="1", unchecked_value="0", &block)
|
11
11
|
options = options.symbolize_keys!
|
12
12
|
check_box_options = options.except(:class, :label, :label_class, :error_message, :help,
|
13
|
-
:inline, :
|
13
|
+
:inline, :hide_label, :skip_label, :wrapper_class, :switch)
|
14
14
|
check_box_options[:class] = check_box_classes(name, options)
|
15
15
|
|
16
|
-
|
16
|
+
tag.div(class: check_box_wrapper_class(options)) do
|
17
17
|
html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value)
|
18
18
|
html.concat(check_box_label(name, options, checked_value, &block)) unless options[:skip_label]
|
19
19
|
html.concat(generate_error(name)) if options[:error_message]
|
@@ -38,7 +38,7 @@ module BootstrapForm
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def check_box_description(name, options, &block)
|
41
|
-
content =
|
41
|
+
content = block ? capture(&block) : options[:label]
|
42
42
|
content || object&.class&.human_attribute_name(name) || name.to_s.humanize
|
43
43
|
end
|
44
44
|
|
@@ -50,40 +50,26 @@ module BootstrapForm
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def check_box_classes(name, options)
|
53
|
-
classes =
|
54
|
-
classes << (options[:custom] ? "custom-control-input" : "form-check-input")
|
53
|
+
classes = Array(options[:class]) << "form-check-input"
|
55
54
|
classes << "is-invalid" if error?(name)
|
56
55
|
classes << "position-static" if options[:skip_label] || options[:hide_label]
|
57
56
|
classes.flatten.compact
|
58
57
|
end
|
59
58
|
|
60
59
|
def check_box_label_class(options)
|
61
|
-
classes = []
|
62
|
-
classes << (options[:custom] ? "custom-control-label" : "form-check-label")
|
60
|
+
classes = ["form-check-label"]
|
63
61
|
classes << options[:label_class]
|
64
62
|
classes << hide_class if options[:hide_label]
|
65
63
|
classes.flatten.compact
|
66
64
|
end
|
67
65
|
|
68
66
|
def check_box_wrapper_class(options)
|
69
|
-
classes = []
|
70
|
-
if options[:
|
71
|
-
|
72
|
-
else
|
73
|
-
classes << "form-check"
|
74
|
-
classes << "form-check-inline" if layout_inline?(options[:inline])
|
75
|
-
end
|
67
|
+
classes = ["form-check"]
|
68
|
+
classes << "form-check-inline" if layout_inline?(options[:inline])
|
69
|
+
classes << "form-switch" if options[:switch]
|
76
70
|
classes << options[:wrapper_class] if options[:wrapper_class].present?
|
77
71
|
classes.flatten.compact
|
78
72
|
end
|
79
|
-
|
80
|
-
def custom_check_box_wrapper_class(options)
|
81
|
-
classes = []
|
82
|
-
classes << "custom-control"
|
83
|
-
classes << (options[:custom] == :switch ? "custom-switch" : "custom-checkbox")
|
84
|
-
classes << "custom-control-inline" if layout_inline?(options[:inline])
|
85
|
-
classes
|
86
|
-
end
|
87
73
|
end
|
88
74
|
end
|
89
75
|
end
|
@@ -10,6 +10,7 @@ module BootstrapForm
|
|
10
10
|
# Disabling Metrics/ParameterLists because the upstream Rails method has the same parameters
|
11
11
|
# rubocop:disable Metrics/ParameterLists
|
12
12
|
def collection_select_with_bootstrap(method, collection, value_method, text_method, options={}, html_options={})
|
13
|
+
html_options = html_options.reverse_merge(control_class: "form-select")
|
13
14
|
form_group_builder(method, options, html_options) do
|
14
15
|
input_with_error(method) do
|
15
16
|
collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options)
|