rails_bootstrap_form 0.2.2 → 0.3.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/Gemfile.lock +1 -1
- data/app/assets/images/exclamation-triangle.svg +5 -0
- data/app/assets/stylesheets/rails_bootstrap_form.css +16 -1
- data/lib/rails_bootstrap_form/bootstrap_form_builder.rb +1 -0
- data/lib/rails_bootstrap_form/bootstrap_form_options.rb +31 -2
- data/lib/rails_bootstrap_form/components/errors.rb +67 -0
- data/lib/rails_bootstrap_form/components/labels.rb +2 -0
- data/lib/rails_bootstrap_form/components/required_field.rb +64 -0
- data/lib/rails_bootstrap_form/components.rb +4 -0
- data/lib/rails_bootstrap_form/field_wrapper_builder.rb +35 -5
- data/lib/rails_bootstrap_form/input_group_builder.rb +49 -0
- data/lib/rails_bootstrap_form/version.rb +1 -1
- data/lib/rails_bootstrap_form.rb +2 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54148096404aa5a60bc550aca63ac09e15c0ec5b6bc9de993bd908879d366908
|
4
|
+
data.tar.gz: 85a7d48bf6ccf530828395265f9aa41db7be3b1bf9fc6a8f83455614449ec02a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9569aeb686d7bef2a2c15018c46e14413c35ecb9eb18ce784cc4b074dcfdc2e5205e583cbf9ad85a6d98da8ab2939af772903c12c5d1a2d3bc0812bd908bf4f
|
7
|
+
data.tar.gz: 6b7222a2477195f38db5b63aeddecf28777e8f1de3dcb17ddbcd3126c747aa61903d411bad1341976590ccfb92e1cab07c93dcb31c4e49e7743b607478acce8b
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,5 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3
|
+
<svg version="1.1" id="icon-exclamation-triangle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" fill="#cf222e">
|
4
|
+
<path d="M12,16a1,1,0,1,0,1,1A1,1,0,0,0,12,16Zm10.67,1.47-8.05-14a3,3,0,0,0-5.24,0l-8,14A3,3,0,0,0,3.94,22H20.06a3,3,0,0,0,2.61-4.53Zm-1.73,2a1,1,0,0,1-.88.51H3.94a1,1,0,0,1-.88-.51,1,1,0,0,1,0-1l8-14a1,1,0,0,1,1.78,0l8.05,14A1,1,0,0,1,20.94,19.49ZM12,8a1,1,0,0,0-1,1v4a1,1,0,0,0,2,0V9A1,1,0,0,0,12,8Z" />
|
5
|
+
</svg>
|
@@ -1 +1,16 @@
|
|
1
|
-
|
1
|
+
label.is-invalid, .invalid-feedback {
|
2
|
+
color: var(--bs-danger);
|
3
|
+
}
|
4
|
+
label.required::after {
|
5
|
+
color: var(--bs-danger);
|
6
|
+
content: "*";
|
7
|
+
padding-left: .25rem;
|
8
|
+
top: -2px;
|
9
|
+
font-weight: bolder;
|
10
|
+
}
|
11
|
+
.form-control.is-invalid, .form-select.is-invalid {
|
12
|
+
background-image: url("exclamation-triangle.svg") !important;
|
13
|
+
background-repeat: no-repeat !important;
|
14
|
+
background-position: right 0.5rem center, center right 2rem !important;
|
15
|
+
background-size: 24px 24px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem) !important;
|
16
|
+
}
|
@@ -35,12 +35,15 @@ module RailsBootstrapForm
|
|
35
35
|
attr_accessor :help_text
|
36
36
|
|
37
37
|
# An option to override automatically generated label text.
|
38
|
+
# Default is `nil`.
|
38
39
|
attr_accessor :label_text
|
39
40
|
|
40
41
|
# An option to custmize whether the label is to be displayed or not.
|
42
|
+
# Default is `false`.
|
41
43
|
attr_accessor :skip_label
|
42
44
|
|
43
45
|
# An option to customize whether the label is only visible to screen readers.
|
46
|
+
# Default is `false`.
|
44
47
|
attr_accessor :hide_label
|
45
48
|
|
46
49
|
# The CSS class that will be used when the label is only accessible by screen
|
@@ -52,9 +55,33 @@ module RailsBootstrapForm
|
|
52
55
|
attr_accessor :label_class
|
53
56
|
|
54
57
|
# An additional CSS class that will be added along with the existing
|
55
|
-
# `label_class` of the label. Default is nil
|
58
|
+
# `label_class` of the label. Default is `nil`.
|
56
59
|
attr_accessor :additional_label_class
|
57
60
|
|
61
|
+
# Input group specific options. Input groups allow prepending and appending
|
62
|
+
# arbitrary html or text to the field.
|
63
|
+
#
|
64
|
+
# Example:
|
65
|
+
#
|
66
|
+
# form.text_field :dollars, bootstrap_form: {input_group: {prepend: "$", append: ".00"}}
|
67
|
+
# form.text_field :search, bootstrap_form: {input_group: {append: button_tag("Go", type: :submit, class: "btn btn-secondary")}}
|
68
|
+
#
|
69
|
+
# Raw or HTML content to be prepended to the field.
|
70
|
+
# Default is `nil`.
|
71
|
+
attr_accessor :prepend
|
72
|
+
|
73
|
+
# Raw or HTML content to be appended to the field.
|
74
|
+
# Default is `nil`.
|
75
|
+
attr_accessor :append
|
76
|
+
|
77
|
+
# Append additional CSS class added to the input group wrapper.
|
78
|
+
# Default is `nil`.
|
79
|
+
attr_accessor :additional_input_group_class
|
80
|
+
|
81
|
+
# Option to control whether the field should have a floating label.
|
82
|
+
# Default is false.
|
83
|
+
attr_accessor :floating
|
84
|
+
|
58
85
|
def initialize(options = {})
|
59
86
|
set_defaults
|
60
87
|
set_bootstrap_form_options(options)
|
@@ -105,12 +132,14 @@ module RailsBootstrapForm
|
|
105
132
|
|
106
133
|
@help_text = nil
|
107
134
|
|
108
|
-
@label_text =
|
135
|
+
@label_text = nil
|
109
136
|
@skip_label = false
|
110
137
|
@hide_label = false
|
111
138
|
@hide_class = "visually-hidden"
|
112
139
|
@label_class = "form-label"
|
113
140
|
@additional_label_class = nil
|
141
|
+
|
142
|
+
@floating = false
|
114
143
|
end
|
115
144
|
|
116
145
|
private :set_defaults
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module RailsBootstrapForm
|
6
|
+
module Components
|
7
|
+
module Errors
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
def self.included(base_class)
|
11
|
+
def is_invalid?(attribute)
|
12
|
+
(attribute && object.respond_to?(:errors) && object.errors[attribute].any?) ||
|
13
|
+
has_association_error?(attribute)
|
14
|
+
end
|
15
|
+
|
16
|
+
def input_with_error(attribute, &block)
|
17
|
+
input = capture(&block)
|
18
|
+
input << generate_error(attribute)
|
19
|
+
input
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate_error(attribute)
|
23
|
+
if is_invalid?(attribute)
|
24
|
+
error_text = error_messages(attribute)
|
25
|
+
error_klass = "invalid-feedback"
|
26
|
+
|
27
|
+
tag.div(error_text, class: error_klass)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_association_error?(attribute)
|
32
|
+
object.class.reflections.any? do |association_name, association|
|
33
|
+
next unless is_belongs_to_association?(association)
|
34
|
+
next unless is_association_same?(attribute, association)
|
35
|
+
|
36
|
+
object.errors[association_name].any?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def error_messages(attribute)
|
41
|
+
messages = object.errors[attribute]
|
42
|
+
|
43
|
+
object.class.reflections.each do |association_name, association|
|
44
|
+
next unless is_belongs_to_association?(association)
|
45
|
+
next unless is_association_same?(attribute, association)
|
46
|
+
|
47
|
+
messages << object.errors[association_name]
|
48
|
+
end
|
49
|
+
|
50
|
+
messages.flatten.to_sentence
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_belongs_to_association?(association)
|
54
|
+
association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
55
|
+
end
|
56
|
+
|
57
|
+
def is_association_same?(attribute, association)
|
58
|
+
(association.foreign_key == attribute.to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
private :is_invalid?, :input_with_error, :generate_error,
|
62
|
+
:has_association_error?, :error_messages,
|
63
|
+
:is_belongs_to_association?, :is_association_same?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -20,6 +20,8 @@ module RailsBootstrapForm
|
|
20
20
|
def label_classes(attribute, bootstrap_options)
|
21
21
|
classes = [bootstrap_options.label_class, bootstrap_options.additional_label_class]
|
22
22
|
classes << bootstrap_options.hide_class if bootstrap_options.hide_label
|
23
|
+
classes << "required" if is_attribute_required?(attribute)
|
24
|
+
classes << "is-invalid" if is_invalid?(attribute)
|
23
25
|
classes.flatten.compact
|
24
26
|
end
|
25
27
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module RailsBootstrapForm
|
6
|
+
module Components
|
7
|
+
module RequiredField
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
def self.included(base_class)
|
11
|
+
def is_field_required?(attribute, options)
|
12
|
+
return false unless attribute
|
13
|
+
|
14
|
+
if options.key?(:required)
|
15
|
+
options[:required]
|
16
|
+
else
|
17
|
+
is_attribute_required?(attribute)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def required_field_options(attribute, options)
|
22
|
+
required = is_field_required?(attribute, options)
|
23
|
+
|
24
|
+
{}.tap do |option|
|
25
|
+
option[:aria] = {required: true} if required
|
26
|
+
option[:required] = required
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_attribute_required?(attribute)
|
31
|
+
return false unless attribute
|
32
|
+
|
33
|
+
target = object.instance_of?(Class) ? object : object.class
|
34
|
+
return false unless target.respond_to?(:validators_on)
|
35
|
+
|
36
|
+
has_presence_validator?(target_validators(target, attribute)) ||
|
37
|
+
is_required_association?(target, attribute)
|
38
|
+
end
|
39
|
+
|
40
|
+
def target_validators(target, attribute)
|
41
|
+
target.validators_on(attribute).map(&:class)
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_presence_validator?(target_validators)
|
45
|
+
target_validators.include?(ActiveModel::Validations::PresenceValidator) ||
|
46
|
+
(defined?(ActiveRecord::Validations::PresenceValidator) &&
|
47
|
+
target_validators.include?(ActiveRecord::Validations::PresenceValidator))
|
48
|
+
end
|
49
|
+
|
50
|
+
def is_required_association?(target, attribute)
|
51
|
+
target.reflections.find do |name, a|
|
52
|
+
next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
53
|
+
next unless a.foreign_key == attribute.to_s
|
54
|
+
|
55
|
+
has_presence_validator?(target_validators(target, name))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private :is_field_required?, :required_field_options, :target_validators,
|
60
|
+
:has_presence_validator?, :is_required_association?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -16,10 +16,24 @@ module RailsBootstrapForm
|
|
16
16
|
label = label(attribute, bootstrap_options)
|
17
17
|
help_text = help_text(attribute, bootstrap_options)
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
if bootstrap_options.floating
|
20
|
+
tag.div(class: field_wrapper_classes) do
|
21
|
+
concat(input_group_wrapper(attribute, bootstrap_options) do
|
22
|
+
tag.div(class: floating_label_classes(attribute)) do
|
23
|
+
concat(capture(&block))
|
24
|
+
concat(label)
|
25
|
+
end
|
26
|
+
end)
|
27
|
+
concat(help_text)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
tag.div(class: field_wrapper_classes) do
|
31
|
+
concat(label)
|
32
|
+
concat(input_group_wrapper(attribute, bootstrap_options) do
|
33
|
+
capture(&block)
|
34
|
+
end)
|
35
|
+
concat(help_text)
|
36
|
+
end
|
23
37
|
end
|
24
38
|
end
|
25
39
|
|
@@ -42,12 +56,28 @@ module RailsBootstrapForm
|
|
42
56
|
bootstrap_options.field_class,
|
43
57
|
bootstrap_options.additional_field_class
|
44
58
|
]
|
59
|
+
field_classes << "is-invalid" if is_invalid?(attribute)
|
60
|
+
|
45
61
|
css_options[:class] = field_classes.flatten.compact
|
46
62
|
|
63
|
+
css_options.merge!(required_field_options(attribute, options))
|
64
|
+
|
65
|
+
if bootstrap_options.floating
|
66
|
+
css_options[:placeholder] ||= label_text(attribute, bootstrap_options)
|
67
|
+
end
|
68
|
+
|
47
69
|
css_options
|
48
70
|
end
|
49
71
|
|
72
|
+
def floating_label_classes(attribute)
|
73
|
+
classes = Array("form-floating")
|
74
|
+
# Floating label fields with input group requires `is-invalid` class in
|
75
|
+
# order to display error messages.
|
76
|
+
classes << "is-invalid" if is_invalid?(attribute)
|
77
|
+
classes
|
78
|
+
end
|
79
|
+
|
50
80
|
private :field_wrapper, :field_wrapper_classes, :form_wrapper_default_class,
|
51
|
-
:field_css_options
|
81
|
+
:field_css_options, :floating_label_classes
|
52
82
|
end
|
53
83
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module RailsBootstrapForm
|
6
|
+
module InputGroupBuilder
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base_class)
|
10
|
+
def input_group_wrapper(attribute, bootstrap_options, &block)
|
11
|
+
input = capture(&block) || ActiveSupport::SafeBuffer.new
|
12
|
+
|
13
|
+
prepend = attach_input(bootstrap_options, :prepend)
|
14
|
+
append = attach_input(bootstrap_options, :append)
|
15
|
+
|
16
|
+
input = prepend + input + append
|
17
|
+
input += generate_error(attribute)
|
18
|
+
|
19
|
+
input = tag.div(input, class: input_group_classes(attribute, bootstrap_options))
|
20
|
+
|
21
|
+
input
|
22
|
+
end
|
23
|
+
|
24
|
+
def input_group_classes(attribute, bootstrap_options)
|
25
|
+
classes = ["input-group", bootstrap_options.additional_input_group_class]
|
26
|
+
# Require `has-validation` class if field has errors.
|
27
|
+
classes << "has-validation" if is_invalid?(attribute)
|
28
|
+
classes.flatten.compact
|
29
|
+
end
|
30
|
+
|
31
|
+
def attach_input(bootstrap_options, key)
|
32
|
+
tags = [*bootstrap_options.send(key)].map do |item|
|
33
|
+
input_group_content(item)
|
34
|
+
end
|
35
|
+
|
36
|
+
ActiveSupport::SafeBuffer.new(tags.join)
|
37
|
+
end
|
38
|
+
|
39
|
+
def input_group_content(content)
|
40
|
+
return content if /button|submit/.match?(content)
|
41
|
+
|
42
|
+
tag.span(content.html_safe, class: "input-group-text")
|
43
|
+
end
|
44
|
+
|
45
|
+
private :input_group_wrapper, :input_group_classes, :attach_input,
|
46
|
+
:input_group_content
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/rails_bootstrap_form.rb
CHANGED
@@ -13,8 +13,9 @@ module RailsBootstrapForm
|
|
13
13
|
autoload :Configuration
|
14
14
|
autoload :BootstrapFormOptions
|
15
15
|
autoload :BootstrapFormBuilder
|
16
|
-
autoload :FieldWrapperBuilder
|
17
16
|
autoload :Components
|
17
|
+
autoload :FieldWrapperBuilder
|
18
|
+
autoload :InputGroupBuilder
|
18
19
|
autoload :Inputs
|
19
20
|
end
|
20
21
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_bootstrap_form
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harshal LADHE (shivam091)
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- LICENSE.txt
|
41
41
|
- README.md
|
42
42
|
- Rakefile
|
43
|
+
- app/assets/images/exclamation-triangle.svg
|
43
44
|
- app/assets/stylesheets/rails_bootstrap_form.css
|
44
45
|
- demo/.byebug_history
|
45
46
|
- demo/.ruby-version
|
@@ -108,11 +109,14 @@ files:
|
|
108
109
|
- lib/rails_bootstrap_form/bootstrap_form_builder.rb
|
109
110
|
- lib/rails_bootstrap_form/bootstrap_form_options.rb
|
110
111
|
- lib/rails_bootstrap_form/components.rb
|
112
|
+
- lib/rails_bootstrap_form/components/errors.rb
|
111
113
|
- lib/rails_bootstrap_form/components/help_text.rb
|
112
114
|
- lib/rails_bootstrap_form/components/labels.rb
|
115
|
+
- lib/rails_bootstrap_form/components/required_field.rb
|
113
116
|
- lib/rails_bootstrap_form/configuration.rb
|
114
117
|
- lib/rails_bootstrap_form/engine.rb
|
115
118
|
- lib/rails_bootstrap_form/field_wrapper_builder.rb
|
119
|
+
- lib/rails_bootstrap_form/input_group_builder.rb
|
116
120
|
- lib/rails_bootstrap_form/inputs.rb
|
117
121
|
- lib/rails_bootstrap_form/version.rb
|
118
122
|
- sig/rails_bootstrap_form.rbs
|