headmin 0.3.2 → 0.4.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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +27 -0
  3. data/.gitignore +14 -0
  4. data/.nvmrc +1 -0
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +24 -0
  7. data/Gemfile +8 -5
  8. data/Gemfile.lock +197 -25
  9. data/README.md +9 -1
  10. data/Rakefile +1 -7
  11. data/app/assets/images/document.docx +0 -0
  12. data/app/assets/images/document.pdf +0 -0
  13. data/app/assets/images/image.jpg +0 -0
  14. data/app/assets/images/spreadsheet.xls +0 -0
  15. data/app/assets/images/video.mp4 +0 -0
  16. data/app/assets/javascripts/headmin/config/i18n.js +9 -9
  17. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +255 -0
  18. data/app/assets/javascripts/headmin/controllers/blocks_controller.js +74 -79
  19. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +24 -24
  20. data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +23 -25
  21. data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +237 -237
  22. data/app/assets/javascripts/headmin/controllers/filter_controller.js +44 -44
  23. data/app/assets/javascripts/headmin/controllers/filters_controller.js +57 -61
  24. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +29 -29
  25. data/app/assets/javascripts/headmin/controllers/hello_controller.js +3 -3
  26. data/app/assets/javascripts/headmin/controllers/notification_controller.js +7 -6
  27. data/app/assets/javascripts/headmin/controllers/popup_controller.js +51 -52
  28. data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +36 -9
  29. data/app/assets/javascripts/headmin/controllers/repeater_controller.js +122 -125
  30. data/app/assets/javascripts/headmin/controllers/select_controller.js +40 -39
  31. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +88 -77
  32. data/app/assets/javascripts/headmin/controllers/table_controller.js +103 -89
  33. data/app/assets/javascripts/headmin/index.js +38 -39
  34. data/app/assets/javascripts/headmin.js +287 -732
  35. data/app/assets/stylesheets/headmin/forms/autocomplete.scss +21 -0
  36. data/app/assets/stylesheets/headmin/forms/file.scss +46 -0
  37. data/app/assets/stylesheets/headmin/forms/repeater.scss +62 -0
  38. data/app/assets/stylesheets/headmin/forms/search.scss +12 -0
  39. data/app/assets/stylesheets/headmin/forms.scss +11 -0
  40. data/app/assets/stylesheets/headmin/general.scss +5 -0
  41. data/app/assets/stylesheets/headmin/overrides/bootstrap.scss +5 -3
  42. data/app/assets/stylesheets/headmin/overrides/redactorx.scss +74 -0
  43. data/app/assets/stylesheets/headmin/popup.scss +1 -0
  44. data/app/assets/stylesheets/headmin/syntax.scss +36 -349
  45. data/app/assets/stylesheets/headmin/table.scss +1 -1
  46. data/app/assets/stylesheets/headmin/utilities/buttons.scss +19 -0
  47. data/app/assets/stylesheets/headmin/utilities/dropzone.scss +72 -0
  48. data/app/assets/stylesheets/headmin/utilities.scss +2 -68
  49. data/app/assets/stylesheets/headmin/vendor/tom-select-bootstrap.css +1 -2
  50. data/app/assets/stylesheets/headmin.css +206 -206
  51. data/app/assets/stylesheets/headmin.scss +1 -1
  52. data/app/controllers/concerns/headmin/authentication.rb +1 -1
  53. data/app/controllers/concerns/headmin/searchable.rb +1 -1
  54. data/app/controllers/concerns/headmin/sortable.rb +7 -7
  55. data/app/helpers/headmin/admin_helper.rb +1 -2
  56. data/app/helpers/headmin/bootstrap_helper.rb +2 -24
  57. data/app/helpers/headmin/filter_helper.rb +1 -1
  58. data/app/helpers/headmin/form_helper.rb +5 -11
  59. data/app/helpers/headmin/notification_helper.rb +21 -21
  60. data/app/helpers/headmin/request_helper.rb +3 -3
  61. data/app/models/concerns/headmin/block.rb +1 -2
  62. data/app/models/concerns/headmin/blockable.rb +2 -2
  63. data/app/models/concerns/headmin/field.rb +2 -1
  64. data/app/models/concerns/headmin/fieldable.rb +8 -8
  65. data/app/models/concerns/headmin/form/autocompletable.rb +38 -0
  66. data/app/models/concerns/headmin/form/hintable.rb +19 -0
  67. data/app/models/concerns/headmin/form/input_groupable.rb +23 -0
  68. data/app/models/concerns/headmin/form/labelable.rb +33 -0
  69. data/app/models/concerns/headmin/form/listable.rb +28 -0
  70. data/app/models/concerns/headmin/form/placeholderable.rb +13 -0
  71. data/app/models/concerns/headmin/form/validatable.rb +40 -0
  72. data/app/models/concerns/headmin/form/wrappable.rb +21 -0
  73. data/app/models/headmin/.DS_Store +0 -0
  74. data/app/models/headmin/blocks_view.rb +15 -0
  75. data/app/models/headmin/form/blocks_view.rb +29 -0
  76. data/app/models/headmin/form/checkbox_view.rb +52 -0
  77. data/app/models/headmin/form/date_range_view.rb +25 -0
  78. data/app/models/headmin/form/date_view.rb +45 -0
  79. data/app/models/headmin/form/email_view.rb +48 -0
  80. data/app/models/headmin/form/file_view.rb +116 -0
  81. data/app/models/headmin/form/flatpickr_range_view.rb +102 -0
  82. data/app/models/headmin/form/flatpickr_view.rb +37 -0
  83. data/app/models/headmin/form/hidden_view.rb +10 -0
  84. data/app/models/headmin/form/hint_view.rb +6 -0
  85. data/app/models/headmin/form/input_group_view.rb +19 -0
  86. data/app/models/headmin/form/label_view.rb +24 -0
  87. data/app/models/headmin/form/number_view.rb +49 -0
  88. data/app/models/headmin/form/password_view.rb +44 -0
  89. data/app/models/headmin/form/redactorx_view.rb +59 -0
  90. data/app/models/headmin/form/search_view.rb +48 -0
  91. data/app/models/headmin/form/select_view.rb +62 -0
  92. data/app/models/headmin/form/switch_view.rb +23 -0
  93. data/app/models/headmin/form/text_view.rb +48 -0
  94. data/app/models/headmin/form/textarea_view.rb +44 -0
  95. data/app/models/headmin/form/url_view.rb +48 -0
  96. data/app/models/headmin/form/wrapper_view.rb +19 -0
  97. data/app/models/headmin/form/wysiwyg_view.rb +17 -0
  98. data/app/models/headmin/thumbnail_view.rb +66 -0
  99. data/app/models/view_model.rb +58 -0
  100. data/app/views/headmin/_blocks.html.erb +13 -9
  101. data/app/views/headmin/_heading.html.erb +7 -1
  102. data/app/views/headmin/_thumbnail.html.erb +5 -39
  103. data/app/views/headmin/dropdown/_item.html.erb +1 -1
  104. data/app/views/headmin/forms/_autocomplete.html.erb +11 -0
  105. data/app/views/headmin/forms/_blocks.html.erb +16 -17
  106. data/app/views/headmin/forms/_checkbox.html.erb +24 -29
  107. data/app/views/headmin/forms/_datalist.html.erb +3 -0
  108. data/app/views/headmin/forms/_date.html.erb +24 -24
  109. data/app/views/headmin/forms/_date_range.html.erb +19 -21
  110. data/app/views/headmin/forms/_email.html.erb +27 -32
  111. data/app/views/headmin/forms/_errors.html.erb +2 -3
  112. data/app/views/headmin/forms/_file.html.erb +84 -181
  113. data/app/views/headmin/forms/_flatpickr.html.erb +19 -20
  114. data/app/views/headmin/forms/_flatpickr_range.html.erb +28 -37
  115. data/app/views/headmin/forms/_hidden.html.erb +9 -10
  116. data/app/views/headmin/forms/_hint.html.erb +16 -0
  117. data/app/views/headmin/forms/_input_group.html.erb +21 -0
  118. data/app/views/headmin/forms/_label.html.erb +5 -13
  119. data/app/views/headmin/forms/_number.html.erb +23 -35
  120. data/app/views/headmin/forms/_password.html.erb +21 -30
  121. data/app/views/headmin/forms/_redactorx.html.erb +21 -40
  122. data/app/views/headmin/forms/_repeater.html.erb +55 -60
  123. data/app/views/headmin/forms/_search.html.erb +43 -0
  124. data/app/views/headmin/forms/_select.html.erb +24 -49
  125. data/app/views/headmin/forms/_switch.html.erb +29 -0
  126. data/app/views/headmin/forms/_text.html.erb +42 -96
  127. data/app/views/headmin/forms/_textarea.html.erb +21 -32
  128. data/app/views/headmin/forms/_url.html.erb +26 -31
  129. data/app/views/headmin/forms/_validation.html.erb +10 -13
  130. data/app/views/headmin/forms/_wrapper.html.erb +9 -0
  131. data/app/views/headmin/forms/_wysiwyg.html.erb +28 -0
  132. data/app/views/headmin/forms/autocomplete/_item.html.erb +3 -0
  133. data/app/views/headmin/forms/autocomplete/_list.html.erb +3 -0
  134. data/app/views/headmin/forms/fields/_group.html.erb +6 -4
  135. data/app/views/headmin/forms/repeater/_row.html.erb +4 -4
  136. data/app/views/headmin/nav/item/_devise.html.erb +1 -1
  137. data/app/views/headmin/table/_actions.html.erb +1 -1
  138. data/app/views/headmin/table/actions/_action.html.erb +2 -1
  139. data/app/views/headmin/table/actions/_delete.html.erb +1 -1
  140. data/app/views/headmin/views/devise/registrations/_edit.html.erb +2 -2
  141. data/bin/console +0 -1
  142. data/config/initializers/customize_input_error.rb +4 -4
  143. data/config/locales/headmin/forms/en.yml +0 -11
  144. data/config/locales/headmin/forms/nl.yml +0 -11
  145. data/esbuild-css.js +18 -18
  146. data/esbuild-js.js +8 -8
  147. data/headmin.gemspec +1 -3
  148. data/lib/generators/headmin/blocks_generator.rb +8 -8
  149. data/lib/generators/headmin/devise_generator.rb +4 -4
  150. data/lib/generators/headmin/fields_generator.rb +9 -9
  151. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +1 -3
  152. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +1 -3
  153. data/lib/generators/templates/controllers/auth/passwords_controller.rb +1 -3
  154. data/lib/generators/templates/controllers/auth/registrations_controller.rb +1 -3
  155. data/lib/generators/templates/controllers/auth/sessions_controller.rb +1 -3
  156. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +1 -3
  157. data/lib/generators/templates/models/block.rb +1 -1
  158. data/lib/headmin/engine.rb +6 -6
  159. data/lib/headmin/version.rb +1 -3
  160. data/lib/headmin.rb +0 -2
  161. data/package-lock.json +5359 -0
  162. data/package.json +13 -7
  163. data/view_model_benchmark.rb +74 -0
  164. data/yarn-error.log +367 -0
  165. data/yarn.lock +1448 -161
  166. metadata +69 -25
  167. data/.rubocop.yml +0 -13
  168. data/app/assets/stylesheets/headmin/form.scss +0 -132
  169. data/app/assets/stylesheets/headmin/overrides/redactorx.css +0 -3
  170. data/app/helpers/headmin/documentation_helper.rb +0 -35
  171. data/app/models/headmin/documentation_renderer.rb +0 -32
  172. data/app/models/headmin/form/base.rb +0 -79
  173. data/app/models/headmin/form/text.rb +0 -53
  174. data/app/services/block_service.rb +0 -72
  175. data/app/views/headmin/_card.html.erb +0 -52
  176. data/app/views/headmin/forms/_actions.html.erb +0 -28
  177. data/app/views/headmin/forms/_base.html.erb +0 -114
  178. data/app/views/headmin/forms/_image.html.erb +0 -21
  179. data/app/views/headmin/forms/_video.html.erb +0 -21
  180. data/app/views/headmin/forms/actions/_destroy.html.erb +0 -13
  181. data/app/views/headmin/forms/actions/_save.html.erb +0 -12
  182. data/app/views/headmin/forms/actions/_view.html.erb +0 -15
  183. data/docs/blocks-and-fields.md +0 -54
  184. data/docs/blocks.md +0 -48
  185. data/docs/devise.md +0 -41
  186. data/docs/fields.md +0 -79
@@ -9,7 +9,7 @@ module Headmin
9
9
  end
10
10
 
11
11
  def search_params
12
- @search_params ||= params[:search] && params[:search].to_s
12
+ @search_params ||= params[:search]&.to_s
13
13
  end
14
14
  end
15
15
  end
@@ -12,8 +12,8 @@ module Headmin
12
12
 
13
13
  def sort_by_params(collection)
14
14
  sort_params.each do |key, value|
15
- next unless %w(asc desc).include?(value)
16
- attribute = key.gsub('sort_', '')
15
+ next unless %w[asc desc].include?(value)
16
+ attribute = key.gsub("sort_", "")
17
17
 
18
18
  # Sort on model columns first, then check for translation columns
19
19
  if collection.attribute_names.include?(attribute.to_s)
@@ -26,19 +26,19 @@ module Headmin
26
26
 
27
27
  order_scope = "order_by_#{attribute}".to_sym
28
28
  sort_scope = "sort_by_#{attribute}".to_sym
29
- if collection.respond_to?(order_scope)
30
- collection = collection.send(order_scope, value)
29
+ collection = if collection.respond_to?(order_scope)
30
+ collection.send(order_scope, value)
31
31
  elsif collection.respond_to?(sort_scope)
32
- collection = collection.send(sort_scope, value)
32
+ collection.send(sort_scope, value)
33
33
  else
34
- collection = collection.order(column.send(value))
34
+ collection.order(column.send(value))
35
35
  end
36
36
  end
37
37
  collection
38
38
  end
39
39
 
40
40
  def sort_params
41
- params.permit!.select { |p| p.to_s.include?('sort_') }
41
+ params.permit!.select { |p| p.to_s.include?("sort_") }
42
42
  end
43
43
  end
44
44
  end
@@ -5,6 +5,5 @@ module Headmin
5
5
  include Headmin::FormHelper
6
6
  include Headmin::NotificationHelper
7
7
  include Headmin::RequestHelper
8
- include Headmin::DocumentationHelper
9
8
  end
10
- end
9
+ end
@@ -2,30 +2,8 @@ module Headmin
2
2
  module BootstrapHelper
3
3
  def bootstrap_icon(icon, options = {})
4
4
  tag_name = options.extract!(:tag_name).fetch(:tag_name, :i)
5
- options[:class] = ['bi', "bi-#{icon}", options.dig(:class)].compact.join(' ')
5
+ options[:class] = ["bi", "bi-#{icon}", options.dig(:class)].compact.join(" ")
6
6
  content_tag(tag_name, options) {}
7
7
  end
8
-
9
- # References
10
- # https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
11
- def bootstrap_icon_for_mime_type(mime_type, options = {})
12
- type_map = {
13
- image: %w[image/bmp image/gif image/vnd.microsoft.icon image/jpeg image/png image/svg+xml image/tiff image/webp],
14
- play: %w[video/mp4 video/mpeg video/ogg video/mp2t video/webm video/3gpp video/3gpp2],
15
- music: %w[audio/aac audio/midi audio/x-midi audio/mpeg audio/ogg audio/opus audio/wav audio/webm audio/3gpp audio/3gpp2],
16
- word: %w[application/msword application/vnd.openxmlformats-officedocument.wordprocessingml.document],
17
- ppt: %w[application/vnd.ms-powerpoint application/vnd.openxmlformats-officedocument.presentationml.presentation],
18
- excel: %w[application/vnd.ms-excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet],
19
- slides: %w[application/vnd.oasis.opendocument.presentation],
20
- spreadsheet: %w[application/vnd.oasis.opendocument.spreadsheet],
21
- richtext: %w[application/vnd.oasis.opendocument.text],
22
- zip: %w[application/zip application/x-7z-compressed application/x-bzip application/x-bzip2 application/gzip application/vnd.rar],
23
- pdf: %w[application/pdf],
24
- }
25
- icon_name = type_map.find{|key, mime_types| mime_types.include?(mime_type)}.first
26
-
27
- icon = ['file', 'earmark', icon_name].compact.join('-')
28
- bootstrap_icon(icon, options)
29
- end
30
8
  end
31
- end
9
+ end
@@ -13,4 +13,4 @@ module Headmin
13
13
  end
14
14
  end
15
15
  end
16
- end
16
+ end
@@ -1,20 +1,14 @@
1
1
  module Headmin
2
2
  module FormHelper
3
- def form_field_valid?(form, name)
4
- !form.object.errors.has_key?(name)
5
- end
6
-
3
+ # TODO: cleanup after input field refactoring
7
4
  def form_field_validation_id(form, name)
8
- [form.object_name, name.to_s, 'validation'].join('_').parameterize.underscore
5
+ [form.object_name, name.to_s, "validation"].join("_").parameterize.underscore
9
6
  end
10
7
 
8
+ # TODO: cleanup after input field refactoring
11
9
  def form_field_validation_class(form, name)
12
10
  return nil if request.get?
13
- form.object.errors.has_key?(name) ? 'is-invalid' : 'is-valid'
14
- end
15
-
16
- def human_attribute_name(attribute)
17
- attribute.to_s.humanize
11
+ form.object.errors.has_key?(name) ? "is-invalid" : "is-valid"
18
12
  end
19
13
 
20
14
  # Outputs currently present query parameters as hidden fields for a given form
@@ -37,4 +31,4 @@ module Headmin
37
31
  test.join.html_safe
38
32
  end
39
33
  end
40
- end
34
+ end
@@ -2,30 +2,30 @@ module Headmin
2
2
  module NotificationHelper
3
3
  def notification_color(name)
4
4
  color = {
5
- notice: {
6
- background: 'bg-success',
7
- text: 'text-white'
8
- },
9
- error: {
10
- text: 'text-dark',
11
- background: 'bg-danger'
12
- },
13
- alert: {
14
- text: 'text-dark',
15
- background: 'bg-warning'
16
- },
17
- timedout: {
18
- text: 'text-dark',
19
- background: 'bg-warning'
20
- },
21
- fallback: {
22
- text: 'text-light',
23
- background: 'bg-info',
24
- }
5
+ notice: {
6
+ background: "bg-success",
7
+ text: "text-white"
8
+ },
9
+ error: {
10
+ text: "text-dark",
11
+ background: "bg-danger"
12
+ },
13
+ alert: {
14
+ text: "text-dark",
15
+ background: "bg-warning"
16
+ },
17
+ timedout: {
18
+ text: "text-dark",
19
+ background: "bg-warning"
20
+ },
21
+ fallback: {
22
+ text: "text-light",
23
+ background: "bg-info"
24
+ }
25
25
  }
26
26
 
27
27
  name = name.to_sym
28
28
  color.key?(name) ? color[name] : color[:fallback]
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -3,7 +3,7 @@ module Headmin
3
3
  def current_url?(url)
4
4
  uri = URI(url)
5
5
  path = uri.path
6
- query_string = uri.query || ''
6
+ query_string = uri.query || ""
7
7
  matches_path = request.path.include?(path)
8
8
  matches_query = request.query_string.include?(query_string)
9
9
  matches_path && matches_query
@@ -28,7 +28,7 @@ module Headmin
28
28
  end
29
29
 
30
30
  def is_sort_param_key?(key)
31
- key.to_s.include?('sort_')
31
+ key.to_s.include?("sort_")
32
32
  end
33
33
  end
34
- end
34
+ end
@@ -3,9 +3,8 @@ module Headmin
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
-
7
6
  # Associations
8
7
  belongs_to :blockable, polymorphic: true, optional: true, touch: true
9
8
  end
10
9
  end
11
- end
10
+ end
@@ -3,8 +3,8 @@ module Headmin
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- has_many :blocks, as: :blockable
6
+ has_many :blocks, as: :blockable, dependent: :destroy
7
7
  accepts_nested_attributes_for :blocks, allow_destroy: true
8
8
  end
9
9
  end
10
- end
10
+ end
@@ -12,6 +12,7 @@ module Headmin
12
12
  has_many :fields, foreign_key: "parent_id"
13
13
  accepts_nested_attributes_for :fields, allow_destroy: true
14
14
  has_one_attached :file
15
+ accepts_nested_attributes_for :file_attachment
15
16
  end
16
17
  end
17
- end
18
+ end
@@ -24,27 +24,27 @@ module Headmin
24
24
  when Hash
25
25
  fields.build(
26
26
  name: key,
27
- field_type: 'group',
27
+ field_type: "group",
28
28
  fields: parse_fields_hash(value)
29
29
  )
30
30
  when Array
31
31
  fields.build(
32
32
  name: key,
33
- field_type: 'list',
33
+ field_type: "list",
34
34
  fields: value.map do |item|
35
- fields.new(name: 'item', field_type: 'group', fields: parse_fields_hash(item))
35
+ fields.new(name: "item", field_type: "group", fields: parse_fields_hash(item))
36
36
  end
37
37
  )
38
38
  when String
39
39
  fields.build(
40
40
  name: key,
41
- field_type: 'text',
41
+ field_type: "text",
42
42
  value: value
43
43
  )
44
44
  else
45
45
  fields.build(
46
46
  name: key,
47
- field_type: 'file',
47
+ field_type: "file",
48
48
  file: value
49
49
  )
50
50
  end
@@ -52,7 +52,7 @@ module Headmin
52
52
  end
53
53
 
54
54
  def parse_hash_tree(hash_tree)
55
- Hash[hash_tree.map do |field, children|
55
+ hash_tree.map do |field, children|
56
56
  case field.field_type.to_sym
57
57
  when :group
58
58
  children = children.any? ? children : field.hash_tree
@@ -67,8 +67,8 @@ module Headmin
67
67
  else
68
68
  [field.name, field.value]
69
69
  end
70
- end]
70
+ end.to_h
71
71
  end
72
72
  end
73
73
  end
74
- end
74
+ end
@@ -0,0 +1,38 @@
1
+ module Headmin
2
+ module Form
3
+ module Autocompletable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def autocomplete?
8
+ collection.is_a?(String) || collection.is_a?(Array)
9
+ end
10
+
11
+ def autocomplete_options
12
+ {
13
+ collection: collection.is_a?(Array) ? collection : []
14
+ }
15
+ end
16
+
17
+ def autocomplete_input_options
18
+ {
19
+ data: {
20
+ autocomplete_target: autocomplete? ? "input" : nil
21
+ }
22
+ }
23
+ end
24
+
25
+ def autocomplete_input_group_options
26
+ options = {
27
+ data: {
28
+ controller: autocomplete? ? "autocomplete" : nil,
29
+ autocomplete_url_value: collection.is_a?(String) ? collection : nil
30
+ }
31
+ }
32
+ options = options.merge(bypass: false) if autocomplete?
33
+ options
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ module Headmin
2
+ module Form
3
+ module Hintable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def hint?
8
+ hint.present?
9
+ end
10
+
11
+ def hint_options
12
+ {
13
+ content: hint
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module Headmin
2
+ module Form
3
+ module InputGroupable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def input_group_options
8
+ default_input_group_options.merge(@input_group || {})
9
+ end
10
+
11
+ private
12
+
13
+ def default_input_group_options
14
+ {
15
+ bypass: !(prepend || append || @input_group),
16
+ prepend: prepend,
17
+ append: append
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ module Headmin
2
+ module Form
3
+ module Labelable
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ def label?
7
+ label != false
8
+ end
9
+
10
+ def prepend_label?
11
+ label != false && !float
12
+ end
13
+
14
+ def append_label?
15
+ label != false && float
16
+ end
17
+
18
+ def label_input_group_options
19
+ float ? {bypass: true} : {}
20
+ end
21
+
22
+ def label_options
23
+ {
24
+ attribute: attribute,
25
+ form: form,
26
+ required: required,
27
+ text: label
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Headmin
2
+ module Form
3
+ module Listable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def list
8
+ datalist_id if @list
9
+ end
10
+
11
+ def datalist?
12
+ @list.present?
13
+ end
14
+
15
+ def datalist_options
16
+ {
17
+ collection: @list,
18
+ id: datalist_id
19
+ }
20
+ end
21
+
22
+ def datalist_id
23
+ "#{attribute}_list"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ module Headmin
2
+ module Form
3
+ module Placeholderable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def placeholder
8
+ float ? @placeholder || attribute : @placeholder
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ module Headmin
2
+ module Form
3
+ module Validatable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def validation_options
8
+ {
9
+ id: validation_id,
10
+ message: validation_message,
11
+ valid: valid?
12
+ }
13
+ end
14
+
15
+ def validate?
16
+ form.object&.errors&.any?
17
+ end
18
+
19
+ private
20
+
21
+ def valid?
22
+ !form.object&.errors&.has_key?(attribute)
23
+ end
24
+
25
+ def validation_message
26
+ form.object&.errors&.full_messages_for(attribute)&.join(", ")
27
+ end
28
+
29
+ def validation_id
30
+ [attribute.to_s, "validation"].join("_").parameterize.underscore
31
+ end
32
+
33
+ def validation_class
34
+ return unless validate?
35
+ valid? ? "is-valid" : "is-invalid"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ module Headmin
2
+ module Form
3
+ module Wrappable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def wrapper_options
8
+ default_wrapper_options.merge(@wrapper || {})
9
+ end
10
+
11
+ private
12
+
13
+ def default_wrapper_options
14
+ {
15
+ bypass: @wrapper == false
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
Binary file
@@ -0,0 +1,15 @@
1
+ module Headmin
2
+ class BlocksView < ViewModel
3
+ def show_blocks?
4
+ blockable&.respond_to?(:blocks)
5
+ end
6
+
7
+ def paths
8
+ @paths || []
9
+ end
10
+
11
+ def prefixes
12
+ paths + ["website/blocks", "blocks", ""]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ module Headmin
2
+ module Form
3
+ class BlocksView < ViewModel
4
+ def repeater_options
5
+ keys = %i[form attribute names label]
6
+ options = to_h.slice(*keys)
7
+ default_repeater_options.merge(options)
8
+ end
9
+
10
+ def paths
11
+ @paths || []
12
+ end
13
+
14
+ def prefixes
15
+ paths + ["admin/blocks", "blocks", ""]
16
+ end
17
+
18
+ private
19
+
20
+ def default_repeater_options
21
+ {
22
+ attribute: "blocks",
23
+ label: false,
24
+ templates: names
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,52 @@
1
+ module Headmin
2
+ module Form
3
+ class CheckboxView < ViewModel
4
+ include Headmin::Form::Hintable
5
+ include Headmin::Form::Labelable
6
+ include Headmin::Form::Validatable
7
+ include Headmin::Form::Wrappable
8
+
9
+ def checked_value
10
+ @checked_value || "1"
11
+ end
12
+
13
+ def unchecked_value
14
+ @unchecked_value || "0"
15
+ end
16
+
17
+ def input_options
18
+ keys = attributes - %i[attribute form label validate wrapper checked_value unchecked_value]
19
+ options = to_h.slice(*keys)
20
+ default_input_options.merge(options)
21
+ end
22
+
23
+ def label_options
24
+ {
25
+ class: ["form-check-label"],
26
+ attribute: attribute,
27
+ form: form,
28
+ required: required,
29
+ text: label
30
+ }
31
+ end
32
+
33
+ def wrapper_options
34
+ default_wrapper_options.merge(
35
+ {
36
+ class: %w[form-check mb-3]
37
+ }
38
+ ).merge(@wrapper || {})
39
+ end
40
+
41
+ private
42
+
43
+ def default_input_options
44
+ {
45
+ aria: {describedby: validation_id},
46
+ class: ["form-check-input", validation_class],
47
+ placeholder: placeholder
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,25 @@
1
+ module Headmin
2
+ module Form
3
+ class DateRangeView < ViewModel
4
+ def start_options
5
+ default_start_options.merge(@start || {})
6
+ end
7
+
8
+ def end_options
9
+ default_end_options.merge(@end || {})
10
+ end
11
+
12
+ private
13
+
14
+ def default_start_options
15
+ keys = attributes - %i[start]
16
+ to_h.slice(*keys)
17
+ end
18
+
19
+ def default_end_options
20
+ keys = attributes - %i[end]
21
+ to_h.slice(*keys)
22
+ end
23
+ end
24
+ end
25
+ end