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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -0
  3. data/.rubocop.yml +3 -2
  4. data/.travis.yml +7 -1
  5. data/CHANGELOG.md +15 -1
  6. data/CONTRIBUTING.md +11 -0
  7. data/Dangerfile +4 -4
  8. data/Gemfile +7 -2
  9. data/OLD-README.md +795 -0
  10. data/README.md +150 -93
  11. data/Rakefile +2 -4
  12. data/bootstrap_form.gemspec +2 -1
  13. data/demo/.postcssrc.yml +3 -0
  14. data/demo/app/assets/config/manifest.js +2 -0
  15. data/demo/app/assets/stylesheets/actiontext.scss +38 -0
  16. data/demo/app/assets/stylesheets/application.scss +1 -0
  17. data/demo/app/helpers/bootstrap_helper.rb +16 -10
  18. data/demo/app/javascript/channels/consumer.js +6 -0
  19. data/demo/app/javascript/channels/index.js +5 -0
  20. data/demo/app/javascript/packs/application.js +11 -0
  21. data/demo/app/models/user.rb +2 -0
  22. data/demo/app/views/active_storage/blobs/_blob.html.erb +14 -0
  23. data/demo/app/views/bootstrap/form.html.erb +2 -1
  24. data/demo/app/views/layouts/application.html.erb +3 -0
  25. data/demo/bin/webpack +15 -0
  26. data/demo/bin/webpack-dev-server +15 -0
  27. data/demo/config/application.rb +2 -3
  28. data/demo/config/environments/development.rb +3 -1
  29. data/demo/config/environments/production.rb +48 -0
  30. data/demo/config/webpack/development.js +5 -0
  31. data/demo/config/webpack/environment.js +3 -0
  32. data/demo/config/webpack/production.js +5 -0
  33. data/demo/config/webpack/test.js +5 -0
  34. data/demo/config/webpacker.yml +92 -0
  35. data/demo/db/schema.rb +63 -18
  36. data/demo/package.json +13 -1
  37. data/demo/test/fixtures/action_text/rich_texts.yml +4 -0
  38. data/demo/yarn.lock +6257 -0
  39. data/lib/bootstrap_form.rb +34 -8
  40. data/lib/bootstrap_form/action_view_extensions/form_helper.rb +71 -0
  41. data/lib/bootstrap_form/components.rb +17 -0
  42. data/lib/bootstrap_form/components/hints.rb +60 -0
  43. data/lib/bootstrap_form/components/labels.rb +56 -0
  44. data/lib/bootstrap_form/components/layout.rb +39 -0
  45. data/lib/bootstrap_form/components/validation.rb +61 -0
  46. data/lib/bootstrap_form/engine.rb +10 -0
  47. data/lib/bootstrap_form/form_builder.rb +54 -524
  48. data/lib/bootstrap_form/form_group.rb +64 -0
  49. data/lib/bootstrap_form/form_group_builder.rb +103 -0
  50. data/lib/bootstrap_form/helpers.rb +9 -0
  51. data/lib/bootstrap_form/helpers/bootstrap.rb +39 -31
  52. data/lib/bootstrap_form/inputs.rb +40 -0
  53. data/lib/bootstrap_form/inputs/base.rb +40 -0
  54. data/lib/bootstrap_form/inputs/check_box.rb +89 -0
  55. data/lib/bootstrap_form/inputs/collection_check_boxes.rb +23 -0
  56. data/lib/bootstrap_form/inputs/collection_radio_buttons.rb +21 -0
  57. data/lib/bootstrap_form/inputs/collection_select.rb +25 -0
  58. data/lib/bootstrap_form/inputs/color_field.rb +14 -0
  59. data/lib/bootstrap_form/inputs/date_field.rb +14 -0
  60. data/lib/bootstrap_form/inputs/date_select.rb +14 -0
  61. data/lib/bootstrap_form/inputs/datetime_field.rb +14 -0
  62. data/lib/bootstrap_form/inputs/datetime_local_field.rb +14 -0
  63. data/lib/bootstrap_form/inputs/datetime_select.rb +14 -0
  64. data/lib/bootstrap_form/inputs/email_field.rb +14 -0
  65. data/lib/bootstrap_form/inputs/file_field.rb +35 -0
  66. data/lib/bootstrap_form/inputs/grouped_collection_select.rb +29 -0
  67. data/lib/bootstrap_form/inputs/inputs_collection.rb +44 -0
  68. data/lib/bootstrap_form/inputs/month_field.rb +14 -0
  69. data/lib/bootstrap_form/inputs/number_field.rb +14 -0
  70. data/lib/bootstrap_form/inputs/password_field.rb +14 -0
  71. data/lib/bootstrap_form/inputs/phone_field.rb +14 -0
  72. data/lib/bootstrap_form/inputs/radio_button.rb +77 -0
  73. data/lib/bootstrap_form/inputs/range_field.rb +14 -0
  74. data/lib/bootstrap_form/inputs/rich_text_area.rb +23 -0
  75. data/lib/bootstrap_form/inputs/search_field.rb +14 -0
  76. data/lib/bootstrap_form/inputs/select.rb +22 -0
  77. data/lib/bootstrap_form/inputs/telephone_field.rb +14 -0
  78. data/lib/bootstrap_form/inputs/text_area.rb +14 -0
  79. data/lib/bootstrap_form/inputs/text_field.rb +14 -0
  80. data/lib/bootstrap_form/inputs/time_field.rb +14 -0
  81. data/lib/bootstrap_form/inputs/time_select.rb +14 -0
  82. data/lib/bootstrap_form/inputs/time_zone_select.rb +22 -0
  83. data/lib/bootstrap_form/inputs/url_field.rb +14 -0
  84. data/lib/bootstrap_form/inputs/week_field.rb +14 -0
  85. data/lib/bootstrap_form/version.rb +1 -1
  86. metadata +79 -6
  87. data/.rubocop_todo.yml +0 -104
  88. data/lib/bootstrap_form/aliasing.rb +0 -35
  89. data/lib/bootstrap_form/helper.rb +0 -52
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module CollectionCheckBoxes
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+ include InputsCollection
9
+
10
+ included do
11
+ def collection_check_boxes_with_bootstrap(*args)
12
+ html = inputs_collection(*args) do |name, value, options|
13
+ options[:multiple] = true
14
+ check_box(name, options, value, nil)
15
+ end
16
+ hidden_field(args.first, value: "", multiple: true).concat(html)
17
+ end
18
+
19
+ bootstrap_alias :collection_check_boxes
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module CollectionRadioButtons
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+ include InputsCollection
9
+
10
+ included do
11
+ def collection_radio_buttons_with_bootstrap(*args)
12
+ inputs_collection(*args) do |name, value, options|
13
+ radio_button(name, value, options)
14
+ end
15
+ end
16
+
17
+ bootstrap_alias :collection_radio_buttons
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module CollectionSelect
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ # Disabling Metrics/ParameterLists because the upstream Rails method has the same parameters
11
+ # rubocop:disable Metrics/ParameterLists
12
+ def collection_select_with_bootstrap(method, collection, value_method, text_method, options={}, html_options={})
13
+ form_group_builder(method, options, html_options) do
14
+ input_with_error(method) do
15
+ collection_select_without_bootstrap(method, collection, value_method, text_method, options, html_options)
16
+ end
17
+ end
18
+ end
19
+ # rubocop:enable Metrics/ParameterLists
20
+
21
+ bootstrap_alias :collection_select
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module ColorField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :color_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module DateField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :date_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module DateSelect
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_select_group :date_select
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module DatetimeField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :datetime_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module DatetimeLocalField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :datetime_local_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module DatetimeSelect
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_select_group :datetime_select
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module EmailField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :email_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module FileField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ def file_field_with_bootstrap(name, options={})
11
+ options = options.reverse_merge(control_class: "custom-file-input")
12
+ form_group_builder(name, options) do
13
+ content_tag(:div, class: "custom-file") do
14
+ input_with_error(name) do
15
+ file_field_input(name, options)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ bootstrap_alias :file_field
22
+ end
23
+
24
+ private
25
+
26
+ def file_field_input(name, options)
27
+ placeholder = options.delete(:placeholder) || "Choose file"
28
+ placeholder_opts = { class: "custom-file-label" }
29
+ placeholder_opts[:for] = options[:id] if options[:id].present?
30
+
31
+ file_field_without_bootstrap(name, options) + label(name, placeholder, placeholder_opts)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module GroupedCollectionSelect
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ # Disabling Metrics/ParameterLists because the upstream Rails method has the same parameters
11
+ # rubocop:disable Metrics/ParameterLists
12
+ def grouped_collection_select_with_bootstrap(method, collection, group_method,
13
+ group_label_method, option_key_method,
14
+ option_value_method, options={}, html_options={})
15
+ form_group_builder(method, options, html_options) do
16
+ input_with_error(method) do
17
+ grouped_collection_select_without_bootstrap(method, collection, group_method,
18
+ group_label_method, option_key_method,
19
+ option_value_method, options, html_options)
20
+ end
21
+ end
22
+ end
23
+ # rubocop:enable Metrics/ParameterLists
24
+
25
+ bootstrap_alias :grouped_collection_select
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,44 @@
1
+ module BootstrapForm
2
+ module Inputs
3
+ module InputsCollection
4
+ extend ActiveSupport::Concern
5
+
6
+ private
7
+
8
+ def inputs_collection(name, collection, value, text, options={})
9
+ options[:inline] ||= layout_inline?(options[:layout])
10
+
11
+ form_group_builder(name, options) do
12
+ inputs = ActiveSupport::SafeBuffer.new
13
+
14
+ collection.each_with_index do |obj, i|
15
+ input_value = value.respond_to?(:call) ? value.call(obj) : obj.send(value)
16
+ input_options = form_group_collection_input_options(options, text, obj, i, input_value, collection)
17
+ inputs << yield(name, input_value, input_options)
18
+ end
19
+
20
+ inputs
21
+ end
22
+ end
23
+
24
+ # FIXME: Find a way to reduce the parameter list size
25
+ # rubocop:disable Metrics/ParameterLists
26
+ def form_group_collection_input_options(options, text, obj, index, input_value, collection)
27
+ input_options = options.merge(label: text.respond_to?(:call) ? text.call(obj) : obj.send(text))
28
+ if (checked = input_options[:checked])
29
+ input_options[:checked] = form_group_collection_input_checked?(checked, obj, input_value)
30
+ end
31
+
32
+ input_options[:error_message] = index == collection.size - 1
33
+ input_options.except!(:class)
34
+ input_options
35
+ end
36
+ # rubocop:enable Metrics/ParameterLists
37
+
38
+ def form_group_collection_input_checked?(checked, obj, input_value)
39
+ checked == input_value || Array(checked).try(:include?, input_value) ||
40
+ checked == obj || Array(checked).try(:include?, obj)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module MonthField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :month_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module NumberField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :number_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module PasswordField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :password_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module PhoneField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :phone_field
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module RadioButton
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ def radio_button_with_bootstrap(name, value, *args)
11
+ options = args.extract_options!.symbolize_keys!
12
+ radio_button_options = options.except(:class, :label, :label_class, :error_message, :help,
13
+ :inline, :custom, :hide_label, :skip_label, :wrapper_class)
14
+
15
+ radio_button_options[:class] = radio_button_classes(name, options)
16
+
17
+ content_tag(:div, class: radio_button_wrapper_class(options)) do
18
+ html = radio_button_without_bootstrap(name, value, radio_button_options)
19
+ html.concat(radio_button_label(name, value, options)) unless options[:skip_label]
20
+ html.concat(generate_error(name)) if options[:error_message]
21
+ html
22
+ end
23
+ end
24
+
25
+ bootstrap_alias :radio_button
26
+ end
27
+
28
+ private
29
+
30
+ def radio_button_label(name, value, options)
31
+ label_options = { value: value, class: radio_button_label_class(options) }
32
+ label_options[:for] = options[:id] if options[:id].present?
33
+ label(name, options[:label], label_options)
34
+ end
35
+
36
+ def radio_button_classes(name, options)
37
+ classes = [options[:class]]
38
+ classes << (options[:custom] ? "custom-control-input" : "form-check-input")
39
+ classes << "is-invalid" if error?(name)
40
+ classes << "position-static" if options[:skip_label] || options[:hide_label]
41
+ classes.flatten.compact
42
+ end
43
+
44
+ def radio_button_label_class(options)
45
+ classes = []
46
+ classes << (options[:custom] ? "custom-control-label" : "form-check-label")
47
+ classes << options[:label_class]
48
+ classes << hide_class if options[:hide_label]
49
+ classes.flatten.compact
50
+ end
51
+
52
+ def radio_button_wrapper_class(options)
53
+ classes = []
54
+ classes << if options[:custom]
55
+ custom_radio_button_wrapper_class(options)
56
+ else
57
+ standard_radio_button_wrapper_class(options)
58
+ end
59
+ classes << options[:wrapper_class] if options[:wrapper_class].present?
60
+ classes.flatten.compact
61
+ end
62
+
63
+ def standard_radio_button_wrapper_class(options)
64
+ classes = ["form-check"]
65
+ classes << "form-check-inline" if layout_inline?(options[:inline])
66
+ classes << "disabled" if options[:disabled]
67
+ classes
68
+ end
69
+
70
+ def custom_radio_button_wrapper_class(options)
71
+ classes = ["custom-control", "custom-radio"]
72
+ classes << "custom-control-inline" if layout_inline?(options[:inline])
73
+ classes
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BootstrapForm
4
+ module Inputs
5
+ module RangeField
6
+ extend ActiveSupport::Concern
7
+ include Base
8
+
9
+ included do
10
+ bootstrap_field :range_field
11
+ end
12
+ end
13
+ end
14
+ end