headmin 0.4.2 → 0.5.2

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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -3
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +78 -1
  5. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +12 -6
  6. data/app/assets/javascripts/headmin/controllers/filter_controller.js +61 -11
  7. data/app/assets/javascripts/headmin/controllers/filter_row_controller.js +50 -0
  8. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +2 -6
  9. data/app/assets/javascripts/headmin/controllers/media_controller.js +237 -0
  10. data/app/assets/javascripts/headmin/controllers/media_modal_controller.js +110 -0
  11. data/app/assets/javascripts/headmin/controllers/popup_controller.js +3 -1
  12. data/app/assets/javascripts/headmin/controllers/remote_modal_controller.js +10 -0
  13. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +16 -21
  14. data/app/assets/javascripts/headmin/controllers/textarea_controller.js +34 -0
  15. data/app/assets/javascripts/headmin/index.js +10 -0
  16. data/app/assets/javascripts/headmin.js +413 -38
  17. data/app/assets/stylesheets/headmin/filter.scss +74 -0
  18. data/app/assets/stylesheets/headmin/forms/file.scss +40 -5
  19. data/app/assets/stylesheets/headmin/forms/media.scss +10 -0
  20. data/app/assets/stylesheets/headmin/forms/repeater.scss +4 -0
  21. data/app/assets/stylesheets/headmin/forms.scss +7 -0
  22. data/app/assets/stylesheets/headmin/general.scss +0 -1
  23. data/app/assets/stylesheets/headmin/layout/body.scss +5 -0
  24. data/app/assets/stylesheets/headmin/layout/sidebar.scss +0 -1
  25. data/app/assets/stylesheets/headmin/media/index.scss +9 -0
  26. data/app/assets/stylesheets/headmin/media.scss +1 -0
  27. data/app/assets/stylesheets/headmin/popup.scss +0 -1
  28. data/app/assets/stylesheets/headmin/table.scss +15 -0
  29. data/app/assets/stylesheets/headmin.css +137 -9
  30. data/app/assets/stylesheets/headmin.scss +1 -0
  31. data/app/controllers/concerns/headmin/filterable.rb +27 -0
  32. data/app/controllers/headmin/media_controller.rb +52 -0
  33. data/app/controllers/headmin_controller.rb +2 -0
  34. data/app/models/concerns/headmin/field.rb +0 -1
  35. data/app/models/concerns/headmin/fieldable.rb +10 -1
  36. data/app/models/concerns/headmin/form/hintable.rb +6 -1
  37. data/app/models/headmin/blocks_view.rb +1 -1
  38. data/app/models/headmin/filter/base.rb +238 -0
  39. data/app/models/headmin/filter/base_view.rb +64 -0
  40. data/app/models/headmin/filter/boolean.rb +15 -0
  41. data/app/models/headmin/filter/boolean_view.rb +61 -0
  42. data/app/models/headmin/filter/button_view.rb +25 -0
  43. data/app/models/headmin/filter/conditional_view.rb +16 -0
  44. data/app/models/headmin/filter/date.rb +67 -0
  45. data/app/models/headmin/filter/date_view.rb +52 -0
  46. data/app/models/headmin/filter/flatpickr_view.rb +54 -0
  47. data/app/models/headmin/filter/menu_item_view.rb +6 -0
  48. data/app/models/headmin/filter/money.rb +13 -0
  49. data/app/models/headmin/filter/number.rb +27 -0
  50. data/app/models/headmin/filter/number_view.rb +54 -0
  51. data/app/models/headmin/filter/operator_view.rb +30 -0
  52. data/app/models/headmin/filter/options_view.rb +61 -0
  53. data/app/models/headmin/filter/row_view.rb +13 -0
  54. data/app/models/headmin/filter/search.rb +18 -0
  55. data/app/models/headmin/filter/search_view.rb +31 -0
  56. data/app/models/headmin/filter/text.rb +25 -0
  57. data/app/models/headmin/filter/text_view.rb +53 -0
  58. data/app/models/headmin/filters.rb +29 -0
  59. data/app/models/headmin/form/color_view.rb +48 -0
  60. data/app/models/headmin/form/datetime_range_view.rb +25 -0
  61. data/app/models/headmin/form/datetime_view.rb +45 -0
  62. data/app/models/headmin/form/flatpickr_range_view.rb +4 -15
  63. data/app/models/headmin/form/flatpickr_view.rb +3 -12
  64. data/app/models/headmin/form/media_view.rb +113 -0
  65. data/app/models/headmin/form/textarea_view.rb +6 -1
  66. data/app/models/view_model.rb +1 -1
  67. data/app/views/headmin/_blocks.html.erb +3 -3
  68. data/app/views/headmin/_breadcrumbs.html.erb +1 -1
  69. data/app/views/headmin/_dropdown.html.erb +1 -1
  70. data/app/views/headmin/_filters.html.erb +9 -9
  71. data/app/views/headmin/_heading.html.erb +1 -1
  72. data/app/views/headmin/_notifications.html.erb +1 -1
  73. data/app/views/headmin/_pagination.html.erb +2 -2
  74. data/app/views/headmin/dropdown/_devise.html.erb +7 -7
  75. data/app/views/headmin/dropdown/_list.html.erb +1 -1
  76. data/app/views/headmin/filters/_base.html.erb +95 -0
  77. data/app/views/headmin/filters/_boolean.html.erb +23 -0
  78. data/app/views/headmin/filters/_date.html.erb +14 -38
  79. data/app/views/headmin/filters/_flatpickr.html.erb +15 -48
  80. data/app/views/headmin/filters/_number.html.erb +23 -0
  81. data/app/views/headmin/filters/_options.html.erb +24 -0
  82. data/app/views/headmin/filters/_search.html.erb +14 -12
  83. data/app/views/headmin/filters/_text.html.erb +23 -0
  84. data/app/views/headmin/filters/filter/_button.html.erb +9 -10
  85. data/app/views/headmin/filters/filter/_conditional.html.erb +18 -0
  86. data/app/views/headmin/filters/filter/_menu_item.html.erb +5 -2
  87. data/app/views/headmin/filters/filter/_null_select.html.erb +8 -0
  88. data/app/views/headmin/filters/filter/_operator.html.erb +16 -0
  89. data/app/views/headmin/filters/filter/_row.html.erb +11 -0
  90. data/app/views/headmin/forms/_autocomplete.html.erb +2 -2
  91. data/app/views/headmin/forms/_blocks.html.erb +3 -3
  92. data/app/views/headmin/forms/_checkbox.html.erb +5 -5
  93. data/app/views/headmin/forms/_color.html.erb +32 -0
  94. data/app/views/headmin/forms/_date.html.erb +8 -8
  95. data/app/views/headmin/forms/_datetime.html.erb +41 -0
  96. data/app/views/headmin/forms/_datetime_range.html.erb +40 -0
  97. data/app/views/headmin/forms/_email.html.erb +9 -9
  98. data/app/views/headmin/forms/_file.html.erb +9 -9
  99. data/app/views/headmin/forms/_flatpickr.html.erb +1 -1
  100. data/app/views/headmin/forms/_flatpickr_range.html.erb +9 -10
  101. data/app/views/headmin/forms/_hidden.html.erb +1 -1
  102. data/app/views/headmin/forms/_hint.html.erb +7 -2
  103. data/app/views/headmin/forms/_media.html.erb +58 -0
  104. data/app/views/headmin/forms/_number.html.erb +8 -8
  105. data/app/views/headmin/forms/_password.html.erb +7 -7
  106. data/app/views/headmin/forms/_redactorx.html.erb +2 -2
  107. data/app/views/headmin/forms/_search.html.erb +9 -9
  108. data/app/views/headmin/forms/_select.html.erb +8 -8
  109. data/app/views/headmin/forms/_switch.html.erb +2 -2
  110. data/app/views/headmin/forms/_text.html.erb +9 -9
  111. data/app/views/headmin/forms/_textarea.html.erb +7 -7
  112. data/app/views/headmin/forms/_url.html.erb +9 -9
  113. data/app/views/headmin/forms/_validation.html.erb +1 -1
  114. data/app/views/headmin/forms/_wysiwyg.html.erb +2 -2
  115. data/app/views/headmin/forms/fields/_base.html.erb +1 -1
  116. data/app/views/headmin/forms/fields/_file.html.erb +1 -1
  117. data/app/views/headmin/forms/fields/_files.html.erb +1 -1
  118. data/app/views/headmin/forms/fields/_group.html.erb +2 -2
  119. data/app/views/headmin/forms/fields/_list.html.erb +1 -1
  120. data/app/views/headmin/forms/fields/_text.html.erb +1 -1
  121. data/app/views/headmin/forms/media/_item.html.erb +32 -0
  122. data/app/views/headmin/forms/media/_validation.html.erb +10 -0
  123. data/app/views/headmin/forms/repeater/_row.html.erb +12 -11
  124. data/app/views/headmin/layout/_footer.html.erb +1 -1
  125. data/app/views/headmin/layout/_main.html.erb +2 -0
  126. data/app/views/headmin/layout/_remote_modal.html.erb +1 -0
  127. data/app/views/headmin/layout/_sidebar.html.erb +1 -1
  128. data/app/views/headmin/media/_item.html.erb +17 -0
  129. data/app/views/headmin/media/_media_item_modal.html.erb +51 -0
  130. data/app/views/headmin/media/_modal.html.erb +35 -0
  131. data/app/views/headmin/media/create.turbo_stream.erb +5 -0
  132. data/app/views/headmin/media/index.html.erb +3 -0
  133. data/app/views/headmin/media/show.html.erb +9 -0
  134. data/app/views/headmin/media/update.turbo_stream.erb +3 -0
  135. data/app/views/headmin/nav/item/_devise.html.erb +7 -7
  136. data/app/views/headmin/table/_actions.html.erb +1 -4
  137. data/app/views/headmin/table/actions/_action.html.erb +3 -3
  138. data/app/views/headmin/table/actions/_delete.html.erb +2 -2
  139. data/app/views/headmin/table/actions/_export.html.erb +1 -1
  140. data/app/views/headmin/table/body/_color.html.erb +10 -0
  141. data/app/views/headmin/table/body/_image.html.erb +18 -0
  142. data/app/views/headmin/table/foot/_cell.html.erb +1 -1
  143. data/app/views/headmin/table/foot/_id.html.erb +1 -1
  144. data/app/views/headmin/views/devise/confirmations/_new.html.erb +2 -2
  145. data/app/views/headmin/views/devise/passwords/_edit.html.erb +2 -2
  146. data/app/views/headmin/views/devise/passwords/_new.html.erb +2 -2
  147. data/app/views/headmin/views/devise/registrations/_edit.html.erb +1 -1
  148. data/app/views/headmin/views/devise/registrations/_new.html.erb +2 -2
  149. data/app/views/headmin/views/devise/sessions/_new.html.erb +1 -1
  150. data/app/views/headmin/views/devise/unlocks/_new.html.erb +2 -2
  151. data/config/locales/devise/nl.yml +1 -1
  152. data/config/locales/en.yml +4 -0
  153. data/config/locales/headmin/dropdown/en.yml +6 -0
  154. data/config/locales/headmin/dropdown/nl.yml +6 -0
  155. data/config/locales/headmin/filters/en.yml +26 -1
  156. data/config/locales/headmin/filters/nl.yml +26 -1
  157. data/config/locales/headmin/forms/en.yml +8 -0
  158. data/config/locales/headmin/forms/nl.yml +8 -0
  159. data/config/locales/headmin/layout/en.yml +0 -9
  160. data/config/locales/headmin/layout/nl.yml +0 -9
  161. data/config/locales/headmin/media/en.yml +23 -0
  162. data/config/locales/headmin/media/nl.yml +22 -0
  163. data/config/locales/headmin/nav/en.yml +7 -0
  164. data/config/locales/headmin/nav/nl.yml +7 -0
  165. data/config/locales/headmin/table/en.yml +2 -0
  166. data/config/locales/headmin/table/nl.yml +2 -0
  167. data/config/locales/nl.yml +4 -0
  168. data/config/routes.rb +10 -0
  169. data/lib/generators/templates/views/auth/confirmations/new.html.erb +1 -1
  170. data/lib/generators/templates/views/auth/mailer/confirmation_instructions.html.erb +1 -1
  171. data/lib/generators/templates/views/auth/mailer/email_changed.html.erb +1 -1
  172. data/lib/generators/templates/views/auth/mailer/password_change.html.erb +1 -1
  173. data/lib/generators/templates/views/auth/mailer/reset_password_instructions.html.erb +1 -1
  174. data/lib/generators/templates/views/auth/mailer/unlock_instructions.html.erb +1 -1
  175. data/lib/generators/templates/views/auth/passwords/edit.html.erb +1 -1
  176. data/lib/generators/templates/views/auth/passwords/new.html.erb +1 -1
  177. data/lib/generators/templates/views/auth/registrations/edit.html.erb +1 -1
  178. data/lib/generators/templates/views/auth/registrations/new.html.erb +1 -1
  179. data/lib/generators/templates/views/auth/sessions/new.html.erb +1 -1
  180. data/lib/generators/templates/views/auth/unlocks/new.html.erb +1 -1
  181. data/lib/headmin/version.rb +1 -1
  182. data/package.json +1 -1
  183. metadata +70 -7
  184. data/.lock-487e157d270f3062a98b7b2a012753708-1272821827 +0 -0
  185. data/app/controllers/concerns/headmin/filter.rb +0 -5
  186. data/app/controllers/concerns/headmin/searchable.rb +0 -15
  187. data/app/views/headmin/filters/_select.html.erb +0 -45
  188. data/app/views/headmin/filters/filter/_template.html.erb +0 -13
@@ -0,0 +1,30 @@
1
+ module Headmin
2
+ module Filter
3
+ class OperatorView < ViewModel
4
+ def allowed_operators
5
+ @allowed_operators || []
6
+ end
7
+
8
+ def selected
9
+ @selected || nil
10
+ end
11
+
12
+ def operator_symbol
13
+ {
14
+ eq: "&equals; #{I18n.t("headmin.filters.operators.eq")}",
15
+ not_eq: "&ne; #{I18n.t("headmin.filters.operators.not_eq")}",
16
+ gt: "&gt; #{I18n.t("headmin.filters.operators.gt")}",
17
+ gteq: "&ge; #{I18n.t("headmin.filters.operators.gteq")}",
18
+ lt: "&lt; #{I18n.t("headmin.filters.operators.lt")}",
19
+ lteq: "&le; #{I18n.t("headmin.filters.operators.lteq")}",
20
+ starts_with: "&sqsub; #{I18n.t("headmin.filters.operators.starts_with")}",
21
+ ends_with: "&sqsup; #{I18n.t("headmin.filters.operators.ends_with")}",
22
+ matches: "&approx; #{I18n.t("headmin.filters.operators.matches")}",
23
+ does_not_match: "&napprox; #{I18n.t("headmin.filters.operators.does_not_match")}",
24
+ is_null: "&#9675; #{I18n.t("headmin.filters.operators.is_null")}",
25
+ is_not_null: "&#9679; #{I18n.t("headmin.filters.operators.is_not_null")}"
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ module Headmin
2
+ module Filter
3
+ class OptionsView < ViewModel
4
+ def base_options
5
+ keys = %i[name label form]
6
+ options = to_h.slice(*keys)
7
+ default_base_options.merge(options)
8
+ end
9
+
10
+ def input_options
11
+ keys = %i[form]
12
+ options = to_h.slice(*keys)
13
+ default_input_options.merge(options)
14
+ end
15
+
16
+ def collection
17
+ @collection || []
18
+ end
19
+
20
+ private
21
+
22
+ def id
23
+ "#{name}_value"
24
+ end
25
+
26
+ def name
27
+ @name || attribute
28
+ end
29
+
30
+ def label
31
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
32
+ end
33
+
34
+ def default_base_options
35
+ {
36
+ label: label,
37
+ name: attribute,
38
+ display_values: collection,
39
+ filter: Headmin::Filter::Text.new(name, @params),
40
+ allowed_operators: Headmin::Filter::Text::OPERATORS - %w[starts_with ends_with in not_in]
41
+ }
42
+ end
43
+
44
+ def default_input_options
45
+ {
46
+ label: false,
47
+ wrapper: false,
48
+ id: id,
49
+ data: {
50
+ action: "change->filter#updateHiddenValue",
51
+ filter_target: "value",
52
+ filter_row_target: "original"
53
+ },
54
+ collection: collection,
55
+ selected: selected,
56
+ class: "form-select"
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,13 @@
1
+ module Headmin
2
+ module Filter
3
+ class RowView < ViewModel
4
+ def operator
5
+ @operator || nil
6
+ end
7
+
8
+ def value
9
+ @value || nil
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Headmin
2
+ module Filter
3
+ class Search < Headmin::Filter::Base
4
+ def query(collection)
5
+ return collection unless @instructions.any?
6
+ collection.search(raw_value)
7
+ end
8
+
9
+ def cast_value(value)
10
+ value
11
+ end
12
+
13
+ def display_value(value)
14
+ value.downcase
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module Headmin
2
+ module Filter
3
+ class SearchView < ViewModel
4
+ def input_options
5
+ keys = attributes - %i[params]
6
+ options = to_h.slice(*keys)
7
+ options = default_input_options.merge(options)
8
+ options.merge(label: false)
9
+ end
10
+
11
+ private
12
+
13
+ def default_input_options
14
+ {
15
+ name: name,
16
+ value: params[name],
17
+ wrapper: false,
18
+ placeholder: placeholder
19
+ }
20
+ end
21
+
22
+ def name
23
+ @name || attribute || :search
24
+ end
25
+
26
+ def placeholder
27
+ @placeholder || I18n.t("headmin.filters.search.placeholder", resource: label)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module Headmin
2
+ module Filter
3
+ class Text < Headmin::Filter::Base
4
+ OPERATORS = %w[eq not_eq in not_in matches does_not_match starts_with ends_with is_null is_not_null starts_with ends_with]
5
+
6
+ def cast_value(value)
7
+ value
8
+ end
9
+
10
+ def display_value(value)
11
+ value.downcase
12
+ end
13
+
14
+ private
15
+
16
+ def convert_to_ends(value)
17
+ "%#{value}"
18
+ end
19
+
20
+ def convert_to_starts(value)
21
+ "#{value}%"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,53 @@
1
+ module Headmin
2
+ module Filter
3
+ class TextView < ViewModel
4
+ def base_options
5
+ keys = %i[name label form]
6
+ options = to_h.slice(*keys)
7
+ default_base_options.merge(options)
8
+ end
9
+
10
+ def input_options
11
+ keys = %i[form]
12
+ options = to_h.slice(*keys)
13
+ default_input_options.merge(options)
14
+ end
15
+
16
+ private
17
+
18
+ def id
19
+ "#{name}_value"
20
+ end
21
+
22
+ def name
23
+ @name || attribute
24
+ end
25
+
26
+ def label
27
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
28
+ end
29
+
30
+ def default_base_options
31
+ {
32
+ label: label,
33
+ name: attribute,
34
+ filter: Headmin::Filter::Text.new(name, @params),
35
+ allowed_operators: Headmin::Filter::Text::OPERATORS - %w[in not_in]
36
+ }
37
+ end
38
+
39
+ def default_input_options
40
+ {
41
+ label: false,
42
+ wrapper: false,
43
+ id: id,
44
+ data: {
45
+ action: "change->filter#updateHiddenValue",
46
+ filter_target: "value",
47
+ filter_row_target: "original"
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,29 @@
1
+ module Headmin
2
+ class Filters
3
+ # Example:
4
+ #
5
+ # @orders = Headmin::Filters.new(params, {
6
+ # status: :text,
7
+ # price: :number,
8
+ # in_stock: :boolean
9
+ # }).query(Order)
10
+
11
+ def initialize(params, param_types)
12
+ @params = params
13
+ @param_types = param_types
14
+ end
15
+
16
+ def parse(attribute, type)
17
+ class_name = "Headmin::Filter::#{type.to_s.classify}".constantize
18
+ class_name.new(attribute, @params)
19
+ end
20
+
21
+ def query(collection)
22
+ @param_types.each do |attribute, type|
23
+ filter = parse(attribute, type)
24
+ collection = filter.query(collection)
25
+ end
26
+ collection
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ module Headmin
2
+ module Form
3
+ class ColorView < ViewModel
4
+ include Headmin::Form::Hintable
5
+ include Headmin::Form::Labelable
6
+ include Headmin::Form::Validatable
7
+ include Headmin::Form::Wrappable
8
+
9
+ def input_options
10
+ keys = attributes - %i[attribute form label validate wrapper]
11
+ options = to_h.slice(*keys)
12
+ default_input_options.deep_merge(options)
13
+ end
14
+
15
+ def label_options
16
+ {
17
+ class: ["form-label"],
18
+ attribute: attribute,
19
+ form: form,
20
+ required: required,
21
+ text: label
22
+ }
23
+ end
24
+
25
+ def value
26
+ @form.object&.send(@attribute) || "#000000"
27
+ end
28
+
29
+ def wrapper_options
30
+ default_wrapper_options.deep_merge(
31
+ {
32
+ }
33
+ ).deep_merge(@wrapper || {})
34
+ end
35
+
36
+ private
37
+
38
+ def default_input_options
39
+ {
40
+ aria: {describedby: validation_id},
41
+ class: ["form-control form-control-color", validation_class],
42
+ placeholder: placeholder,
43
+ title: value
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ module Headmin
2
+ module Form
3
+ class DatetimeRangeView < ViewModel
4
+ def start_options
5
+ default_start_options.deep_merge(@start || {})
6
+ end
7
+
8
+ def end_options
9
+ default_end_options.deep_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
@@ -0,0 +1,45 @@
1
+ module Headmin
2
+ module Form
3
+ class DatetimeView < ViewModel
4
+ include Headmin::Form::Hintable
5
+ include Headmin::Form::InputGroupable
6
+ include Headmin::Form::Labelable
7
+ include Headmin::Form::Listable
8
+ include Headmin::Form::Placeholderable
9
+ include Headmin::Form::Validatable
10
+ include Headmin::Form::Wrappable
11
+
12
+ def input_options
13
+ keys = attributes - %i[append attribute float form input_group input_group label prepend validate wrapper]
14
+ options = to_h.slice(*keys)
15
+ default_input_options.deep_merge(options)
16
+ end
17
+
18
+ def input_group_options
19
+ default_input_group_options
20
+ .deep_merge(label_input_group_options)
21
+ .deep_merge(@input_group || {})
22
+ end
23
+
24
+ def wrapper_options
25
+ default_wrapper_options.deep_merge({
26
+ class: ["mb-3", ("form-floating" if float)]
27
+ }).deep_merge(@wrapper || {})
28
+ end
29
+
30
+ private
31
+
32
+ def default_input_options
33
+ {
34
+ aria: {describedby: validation_id},
35
+ class: [form_control_class, validation_class],
36
+ placeholder: placeholder
37
+ }
38
+ end
39
+
40
+ def form_control_class
41
+ plaintext ? "form-control-plaintext" : "form-control"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -43,10 +43,7 @@ module Headmin
43
43
 
44
44
  def wrapper_options
45
45
  default_wrapper_options.deep_merge({
46
- class: ["mb-3", ("form-floating" if float)],
47
- data: {
48
- controller: "flatpickr date-range"
49
- }
46
+ class: ["mb-3", ("form-floating" if float)]
50
47
  }).deep_merge(@wrapper || {})
51
48
  end
52
49
 
@@ -59,19 +56,11 @@ module Headmin
59
56
  end
60
57
 
61
58
  def default_start_options
62
- {
63
- data: {
64
- 'date-range-target': "startDateInput"
65
- }
66
- }
59
+ {}
67
60
  end
68
61
 
69
62
  def default_end_options
70
- {
71
- data: {
72
- 'date-range-target': "endDateInput"
73
- }
74
- }
63
+ {}
75
64
  end
76
65
 
77
66
  def default_input_options
@@ -81,7 +70,7 @@ module Headmin
81
70
  placeholder: placeholder,
82
71
  name: nil,
83
72
  data: {
84
- "flatpickr-target": "input",
73
+ controller: "flatpickr date-range",
85
74
  action: "change->date-range#update",
86
75
  flatpickr: {
87
76
  mode: "range",
@@ -2,7 +2,7 @@ module Headmin
2
2
  module Form
3
3
  class FlatpickrView < ViewModel
4
4
  def options
5
- keys = attributes - %i[data wrapper]
5
+ keys = attributes - %i[data]
6
6
  options = to_h.slice(*keys)
7
7
  default_options.deep_merge(options)
8
8
  end
@@ -11,27 +11,18 @@ module Headmin
11
11
 
12
12
  def default_options
13
13
  {
14
- data: default_data.deep_merge(data || {}),
15
- wrapper: default_wrapper_options.deep_merge(wrapper || {})
14
+ data: default_data.deep_merge(data || {})
16
15
  }
17
16
  end
18
17
 
19
18
  def default_data
20
19
  {
21
- "flatpickr-target": "input",
20
+ controller: "flatpickr",
22
21
  flatpickr: {
23
22
  defaultDate: form.object&.send(attribute)&.strftime("%d/%m/%Y")
24
23
  }
25
24
  }
26
25
  end
27
-
28
- def default_wrapper_options
29
- {
30
- data: {
31
- controller: "flatpickr"
32
- }
33
- }
34
- end
35
26
  end
36
27
  end
37
28
  end
@@ -0,0 +1,113 @@
1
+ module Headmin
2
+ module Form
3
+ class MediaView < ViewModel
4
+ include Rails.application.routes.url_helpers
5
+ include Headmin::Form::Hintable
6
+ include Headmin::Form::Labelable
7
+ include Headmin::Form::Placeholderable
8
+ include Headmin::Form::Validatable
9
+ include Headmin::Form::Wrappable
10
+
11
+ def input_group_options
12
+ default_input_group_options
13
+ .deep_merge(label_input_group_options)
14
+ .deep_merge(@input_group || {})
15
+ end
16
+
17
+ def wrapper_options
18
+ default_wrapper_options.deep_merge({
19
+ class: ["mb-3", ("form-floating" if float)],
20
+ data: {
21
+ controller: "media",
22
+ name: "#{attribute}_#{object_id}",
23
+ min: min,
24
+ max: max,
25
+ sort: sort,
26
+ required: required.nil? ? 0 : required
27
+ }
28
+ }).deep_merge(@wrapper || {})
29
+ end
30
+
31
+ def custom_validation_options
32
+ {
33
+ form: form,
34
+ attribute: attribute,
35
+ min: min,
36
+ max: max
37
+ }
38
+ end
39
+
40
+ def association_object
41
+ if attached.is_a?(ActiveStorage::Attached::Many)
42
+ result = form.object.send(nested_attribute)
43
+ result = result.order(position: :asc) if sort
44
+ result
45
+ else
46
+ form.object.send(nested_attribute)
47
+ end
48
+ end
49
+
50
+ def attachments
51
+ if attached.is_a?(ActiveStorage::Attached::Many)
52
+ result = form.object.send(nested_attribute)
53
+ result = result.order(position: :asc) if sort
54
+ result.to_a.compact
55
+ else
56
+ [form.object.send(nested_attribute)].compact
57
+ end
58
+ end
59
+
60
+ def attached
61
+ form.object.send(attribute)
62
+ end
63
+
64
+ def build_nested_attribute
65
+ if attached.is_a?(ActiveStorage::Attached::Many)
66
+ form.object.send(nested_attribute).build
67
+ else
68
+ form.object.send("build_#{nested_attribute}")
69
+ end
70
+ end
71
+
72
+ def nested_attribute
73
+ if attached.is_a?(ActiveStorage::Attached::Many)
74
+ :"#{attribute}_attachments"
75
+ else
76
+ :"#{attribute}_attachment"
77
+ end
78
+ end
79
+
80
+ def min
81
+ if @required
82
+ @min.to_i < 1 ? 1 : @min.to_i
83
+ else
84
+ @min.to_i < 1 ? 0 : @min.to_i
85
+ end
86
+ end
87
+
88
+ def max
89
+ if attached.is_a?(ActiveStorage::Attached::Many)
90
+ @max
91
+ else
92
+ 1
93
+ end
94
+ end
95
+
96
+ def required
97
+ @required ? 1 : nil
98
+ end
99
+
100
+ def blob_ids
101
+ attachments.map { |attachment| attachment.blob_id }
102
+ end
103
+
104
+ def media_modal_url
105
+ headmin_media_url(name: "#{attribute}_#{object_id}", ids: blob_ids, min: min, max: max)
106
+ end
107
+
108
+ def sort
109
+ @sort == true
110
+ end
111
+ end
112
+ end
113
+ end
@@ -22,7 +22,8 @@ module Headmin
22
22
 
23
23
  def wrapper_options
24
24
  default_wrapper_options.deep_merge({
25
- class: ["mb-3", ("form-floating" if float)]
25
+ class: ["mb-3", ("form-floating" if float)],
26
+ data: {controller: :textarea}
26
27
  }).deep_merge(@wrapper || {})
27
28
  end
28
29
 
@@ -32,6 +33,10 @@ module Headmin
32
33
  {
33
34
  aria: {describedby: validation_id},
34
35
  class: [form_control_class, validation_class],
36
+ data: {
37
+ textarea_target: :textarea,
38
+ action: "input->textarea#update"
39
+ },
35
40
  placeholder: placeholder
36
41
  }
37
42
  end
@@ -33,7 +33,7 @@ class ViewModel
33
33
  end
34
34
 
35
35
  def to_hash
36
- attributes.map { |attribute| {attribute => value_for(attribute)} }.inject(:merge)
36
+ attributes.map { |attribute| {attribute => value_for(attribute)} }.inject(:merge) || {}
37
37
  end
38
38
 
39
39
  alias_method :to_h, :to_hash
@@ -9,13 +9,13 @@
9
9
  #
10
10
  # ==== Examples
11
11
  # Basic version. (looks in views/website/blocks, views/blocks or views directory )
12
- # <%= render "headmin/blocks", blockable: @page %#>
12
+ # <%= render 'headmin/blocks', blockable: @page %#>
13
13
  #
14
14
  # Define one ore more path where the templates could be located:
15
- # <%= render "headmin/blocks", blockable: @page, paths: %w(website/pages/blocks) %#>
15
+ # <%= render 'headmin/blocks', blockable: @page, paths: %w(website/pages/blocks) %#>
16
16
 
17
17
  blocks = Headmin::BlocksView.new(local_assigns)
18
- @lookup_context.prefixes = @lookup_context.prefixes + blocks.prefixes
18
+ @lookup_context.prefixes = blocks.prefixes + @lookup_context.prefixes
19
19
  %>
20
20
 
21
21
  <% if blockable && blockable.respond_to?(:blocks) %>
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # ==== Examples
8
8
  # Basic version. This will use the publicly available `breadcrumbs` variable
9
- # <%= render "headmin/breadcrumbs" %#>
9
+ # <%= render 'headmin/breadcrumbs' %#>
10
10
  %>
11
11
 
12
12
  <nav aria-label="breadcrumb">
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # ==== Examples
8
8
  # Basic version
9
- # <%= render "headmin/dropdown" do %#>
9
+ # <%= render 'headmin/dropdown' do %#>
10
10
  # Your content
11
11
  # <% end %#>
12
12