headmin 0.4.0 → 0.4.1

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +84 -21
  4. data/app/assets/javascripts/headmin/controllers/popup_controller.js +11 -4
  5. data/app/assets/javascripts/headmin.js +67 -18
  6. data/app/assets/stylesheets/headmin/general.scss +9 -0
  7. data/app/assets/stylesheets/headmin.css +4 -0
  8. data/app/models/headmin/form/blocks_view.rb +1 -1
  9. data/app/models/headmin/form/checkbox_view.rb +3 -3
  10. data/app/models/headmin/form/date_range_view.rb +2 -2
  11. data/app/models/headmin/form/date_view.rb +5 -5
  12. data/app/models/headmin/form/email_view.rb +7 -7
  13. data/app/models/headmin/form/file_view.rb +6 -6
  14. data/app/models/headmin/form/flatpickr_range_view.rb +7 -7
  15. data/app/models/headmin/form/flatpickr_view.rb +3 -3
  16. data/app/models/headmin/form/input_group_view.rb +1 -1
  17. data/app/models/headmin/form/label_view.rb +1 -1
  18. data/app/models/headmin/form/number_view.rb +5 -5
  19. data/app/models/headmin/form/password_view.rb +5 -5
  20. data/app/models/headmin/form/redactorx_view.rb +2 -2
  21. data/app/models/headmin/form/search_view.rb +7 -7
  22. data/app/models/headmin/form/select_view.rb +6 -6
  23. data/app/models/headmin/form/switch_view.rb +1 -1
  24. data/app/models/headmin/form/text_view.rb +7 -7
  25. data/app/models/headmin/form/textarea_view.rb +5 -5
  26. data/app/models/headmin/form/url_view.rb +7 -7
  27. data/app/models/headmin/form/wrapper_view.rb +1 -1
  28. data/app/models/headmin/form/wysiwyg_view.rb +1 -1
  29. data/app/views/headmin/forms/fields/_group.html.erb +5 -0
  30. data/config/locales/headmin/forms/en.yml +1 -1
  31. data/config/locales/headmin/forms/nl.yml +1 -1
  32. data/lib/headmin/version.rb +1 -1
  33. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b427a7de1334a6a27a66b145247d4d09379f25c446e01ff87bb17e46fb6098c6
4
- data.tar.gz: bda5b5c568a4872ce1be8e2da62a10d801370967c5beffed0ff27eb12576d407
3
+ metadata.gz: 503fa2fc7ec041e2a3baca7937f969f7cc8061da02fcb698924f43f3ccc384f9
4
+ data.tar.gz: 88ad583e50e5d72b8f08c6212bdee24ce1f504d4776bcf0ff6c21faadb37db6e
5
5
  SHA512:
6
- metadata.gz: 8b0363d0ee6aec32484806ef1e655d681127ae1318f0e391585f81d97b7cce1f28af1368c9038570a28aa0333abfafbc59dbcc65de49862f8248ff2a574edd83
7
- data.tar.gz: 4aaaff3a6a1550829bd10e4af436fc6a5bc0515ff6098b1b6761e577365b5816c0bbea2d65e3c2bee1633944a10890079cdb34a263998524e1adaf45e5887df0
6
+ metadata.gz: 6bc9c3497c44c255eca104e024d672fa37041029c0da730ee257078f42a72b2d299b427c636b52ee6d0a370c41576d16af83b2ec55db4ad90418f104dbe406e9
7
+ data.tar.gz: ccecbb9860f879f0bd398954e67f546671e090a230a5f812bff8c59dd268e62755147ee4d14b3eafd7a59f182c39ee012f70e234ea14b47e58a63ef60dea71c7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- headmin (0.3.4)
4
+ headmin (0.4.0)
5
5
  closure_tree (~> 7.4)
6
6
  inline_svg (~> 1.7)
7
7
  redcarpet (~> 3.5)
@@ -1,4 +1,4 @@
1
- /* global fetch */
1
+ /* global fetch, Event */
2
2
  import { Controller } from '@hotwired/stimulus'
3
3
 
4
4
  export default class extends Controller {
@@ -18,11 +18,16 @@ export default class extends Controller {
18
18
  this.show()
19
19
  })
20
20
 
21
- // Typing
21
+ // Navigation
22
22
  this.inputTarget.addEventListener('keydown', (event) => {
23
23
  this.handleKeydown(event)
24
24
  })
25
25
 
26
+ // Typing
27
+ this.inputTarget.addEventListener('keyup', (event) => {
28
+ this.handleKeyup(event)
29
+ })
30
+
26
31
  // Clicked outside dropdown
27
32
  document.addEventListener('click', (event) => {
28
33
  this.handleOutsideClick(event)
@@ -30,20 +35,33 @@ export default class extends Controller {
30
35
  }
31
36
 
32
37
  handleKeydown (event) {
33
- this.show()
34
-
35
38
  const keyCode = parseInt(event.keyCode, 10)
36
39
  if (this.isArrowKey(keyCode)) {
37
40
  this.handleArrowKey(keyCode)
38
- } else if (this.isEnterKey(keyCode)) {
39
- this.selectActiveItem()
40
- } else {
41
- this.handleTextKey()
41
+ }
42
+
43
+ if (this.isEnterKey(keyCode)) {
44
+ this.selectActiveItem(event)
42
45
  }
43
46
  }
44
47
 
45
- selectActiveItem () {
46
- this.activeItem().click()
48
+ handleKeyup (event) {
49
+ // Ignore arrow keys or enters
50
+ const keyCode = parseInt(event.keyCode, 10)
51
+ if (this.isArrowKey(keyCode) || this.isEnterKey(keyCode)) {
52
+ return false
53
+ }
54
+
55
+ this.handleTextKey()
56
+ }
57
+
58
+ selectActiveItem (event) {
59
+ const activeItem = this.activeItem()
60
+ if (activeItem) {
61
+ this.deselectAll()
62
+ this.setValue(activeItem.getAttribute('value'))
63
+ event.preventDefault()
64
+ }
47
65
  }
48
66
 
49
67
  isEnterKey (keyCode) {
@@ -51,6 +69,7 @@ export default class extends Controller {
51
69
  }
52
70
 
53
71
  handleArrowKey (keyCode) {
72
+ this.show()
54
73
  switch (keyCode) {
55
74
  case 38:
56
75
  this.handleArrowUp()
@@ -72,8 +91,10 @@ export default class extends Controller {
72
91
 
73
92
  selectNextItem () {
74
93
  const next = this.nextItem()
75
- this.deselectAll()
76
- next.classList.add('active')
94
+ if (next) {
95
+ this.deselectAll()
96
+ next.classList.add('active')
97
+ }
77
98
  }
78
99
 
79
100
  nextItem () {
@@ -94,8 +115,10 @@ export default class extends Controller {
94
115
 
95
116
  selectPreviousItem () {
96
117
  const previous = this.previousItem()
97
- this.deselectAll()
98
- previous.classList.add('active')
118
+ if (previous) {
119
+ this.deselectAll()
120
+ previous.classList.add('active')
121
+ }
99
122
  }
100
123
 
101
124
  previousItem () {
@@ -160,13 +183,22 @@ export default class extends Controller {
160
183
  // 2. render html
161
184
  this.renderCollection(html)
162
185
  }).then(() => {
163
- // 3. sort by relevance
164
- // ...
165
- // 4. Highlight
186
+ // 3. Highlight
166
187
  this.highlight()
188
+ }).then(() => {
189
+ // 4. Preselect first result
190
+ this.activateFirstItem()
191
+ }).then(() => {
192
+ // 5. Show results
193
+ this.show()
167
194
  })
168
195
  }
169
196
 
197
+ activateFirstItem () {
198
+ this.deselectAll()
199
+ this.firstItem().classList.add('active')
200
+ }
201
+
170
202
  show () {
171
203
  if (this.isDropdownEmpty()) {
172
204
  this.dropdownTarget.classList.remove('d-none')
@@ -190,7 +222,7 @@ export default class extends Controller {
190
222
 
191
223
  fetchCollection () {
192
224
  if (this.isRemote()) {
193
- return fetch(this.urlValue).then((response) => {
225
+ return fetch(this.remoteURL()).then((response) => {
194
226
  return response.text()
195
227
  }).catch((error) => {
196
228
  console.error('The URL you provided for the autocomplete collection didn\'t return a successful result', error)
@@ -200,6 +232,29 @@ export default class extends Controller {
200
232
  }
201
233
  }
202
234
 
235
+ remoteURL () {
236
+ // Set dummy base in case a relative path is provided as remote URL
237
+ const base = 'https://example.com'
238
+ const url = new URL(this.urlValue, base)
239
+
240
+ // Update pagination params
241
+ const params = new URLSearchParams(url.search)
242
+ params.set('search', this.value())
243
+ params.set('page', '1')
244
+ params.set('per_page', '6')
245
+ url.search = params.toString()
246
+
247
+ // Convert to string
248
+ let urlString = url.toString()
249
+
250
+ // Convert back to relative url if needed
251
+ if (urlString.includes(base)) {
252
+ urlString = urlString.replace(base, '')
253
+ }
254
+
255
+ return urlString
256
+ }
257
+
203
258
  renderCollection (html) {
204
259
  this.dropdownTarget.innerHTML = html
205
260
  }
@@ -217,15 +272,23 @@ export default class extends Controller {
217
272
  text = text.replace(/<mark.*?>(.*?)<\/mark>/ig, '$1')
218
273
 
219
274
  // Highlight query
220
- const regex2 = new RegExp(`(${query})`, 'gi')
221
- text = text.replace(regex2, '<mark>$1</mark>')
275
+ if (query && query.length > 0) {
276
+ // Ignore all strings inside < >
277
+ const regex2 = new RegExp(`(?<!<[^>]*?)(&nbsp;)?(${query})`, 'gi')
278
+ text = text.replace(regex2, '<mark>$2</mark>')
279
+ }
222
280
 
223
281
  dropdownItem.innerHTML = text
224
282
  })
225
283
  }
226
284
 
227
285
  select (event) {
228
- this.inputTarget.value = event.target.getAttribute('value')
286
+ this.setValue(event.currentTarget.getAttribute('value'))
287
+ }
288
+
289
+ setValue (value) {
290
+ this.inputTarget.value = value
291
+ this.inputTarget.dispatchEvent(new Event('change'))
229
292
  this.hide()
230
293
  }
231
294
 
@@ -1,3 +1,4 @@
1
+ /* global HTMLInputElement */
1
2
  import { Controller } from '@hotwired/stimulus'
2
3
  import { createPopper } from '@popperjs/core'
3
4
 
@@ -32,14 +33,20 @@ export default class extends Controller {
32
33
  const popup = this.popupById(button.dataset.popupId)
33
34
  const passThru = button.dataset.popupPassThru
34
35
 
36
+ // Open the popup
37
+ createPopper(button, popup)
38
+ this.openPopup(popup)
39
+
35
40
  if (passThru) {
36
41
  // Pass click event to an element inside the popup
37
42
  const passThruElement = popup.querySelector(passThru)
38
43
  passThruElement.click()
39
- } else {
40
- // Open the popup
41
- createPopper(button, popup)
42
- this.openPopup(popup)
44
+
45
+ // Focus and select value if it's an input element
46
+ if (passThruElement instanceof HTMLInputElement) {
47
+ passThruElement.focus()
48
+ passThruElement.select()
49
+ }
43
50
  }
44
51
  }
45
52
 
@@ -4979,28 +4979,42 @@ var autocomplete_controller_default = class extends Controller {
4979
4979
  this.inputTarget.addEventListener("keydown", (event) => {
4980
4980
  this.handleKeydown(event);
4981
4981
  });
4982
+ this.inputTarget.addEventListener("keyup", (event) => {
4983
+ this.handleKeyup(event);
4984
+ });
4982
4985
  document.addEventListener("click", (event) => {
4983
4986
  this.handleOutsideClick(event);
4984
4987
  });
4985
4988
  }
4986
4989
  handleKeydown(event) {
4987
- this.show();
4988
4990
  const keyCode = parseInt(event.keyCode, 10);
4989
4991
  if (this.isArrowKey(keyCode)) {
4990
4992
  this.handleArrowKey(keyCode);
4991
- } else if (this.isEnterKey(keyCode)) {
4992
- this.selectActiveItem();
4993
- } else {
4994
- this.handleTextKey();
4993
+ }
4994
+ if (this.isEnterKey(keyCode)) {
4995
+ this.selectActiveItem(event);
4995
4996
  }
4996
4997
  }
4997
- selectActiveItem() {
4998
- this.activeItem().click();
4998
+ handleKeyup(event) {
4999
+ const keyCode = parseInt(event.keyCode, 10);
5000
+ if (this.isArrowKey(keyCode) || this.isEnterKey(keyCode)) {
5001
+ return false;
5002
+ }
5003
+ this.handleTextKey();
5004
+ }
5005
+ selectActiveItem(event) {
5006
+ const activeItem = this.activeItem();
5007
+ if (activeItem) {
5008
+ this.deselectAll();
5009
+ this.setValue(activeItem.getAttribute("value"));
5010
+ event.preventDefault();
5011
+ }
4999
5012
  }
5000
5013
  isEnterKey(keyCode) {
5001
5014
  return keyCode === 13;
5002
5015
  }
5003
5016
  handleArrowKey(keyCode) {
5017
+ this.show();
5004
5018
  switch (keyCode) {
5005
5019
  case 38:
5006
5020
  this.handleArrowUp();
@@ -5019,8 +5033,10 @@ var autocomplete_controller_default = class extends Controller {
5019
5033
  }
5020
5034
  selectNextItem() {
5021
5035
  const next = this.nextItem();
5022
- this.deselectAll();
5023
- next.classList.add("active");
5036
+ if (next) {
5037
+ this.deselectAll();
5038
+ next.classList.add("active");
5039
+ }
5024
5040
  }
5025
5041
  nextItem() {
5026
5042
  const current = this.activeItem();
@@ -5036,8 +5052,10 @@ var autocomplete_controller_default = class extends Controller {
5036
5052
  }
5037
5053
  selectPreviousItem() {
5038
5054
  const previous = this.previousItem();
5039
- this.deselectAll();
5040
- previous.classList.add("active");
5055
+ if (previous) {
5056
+ this.deselectAll();
5057
+ previous.classList.add("active");
5058
+ }
5041
5059
  }
5042
5060
  previousItem() {
5043
5061
  const current = this.activeItem();
@@ -5087,8 +5105,16 @@ var autocomplete_controller_default = class extends Controller {
5087
5105
  this.renderCollection(html);
5088
5106
  }).then(() => {
5089
5107
  this.highlight();
5108
+ }).then(() => {
5109
+ this.activateFirstItem();
5110
+ }).then(() => {
5111
+ this.show();
5090
5112
  });
5091
5113
  }
5114
+ activateFirstItem() {
5115
+ this.deselectAll();
5116
+ this.firstItem().classList.add("active");
5117
+ }
5092
5118
  show() {
5093
5119
  if (this.isDropdownEmpty()) {
5094
5120
  this.dropdownTarget.classList.remove("d-none");
@@ -5108,7 +5134,7 @@ var autocomplete_controller_default = class extends Controller {
5108
5134
  }
5109
5135
  fetchCollection() {
5110
5136
  if (this.isRemote()) {
5111
- return fetch(this.urlValue).then((response) => {
5137
+ return fetch(this.remoteURL()).then((response) => {
5112
5138
  return response.text();
5113
5139
  }).catch((error2) => {
5114
5140
  console.error("The URL you provided for the autocomplete collection didn't return a successful result", error2);
@@ -5117,6 +5143,20 @@ var autocomplete_controller_default = class extends Controller {
5117
5143
  return Promise.resolve(this.dropdownTarget.innerHTML);
5118
5144
  }
5119
5145
  }
5146
+ remoteURL() {
5147
+ const base = "https://example.com";
5148
+ const url = new URL(this.urlValue, base);
5149
+ const params = new URLSearchParams(url.search);
5150
+ params.set("search", this.value());
5151
+ params.set("page", "1");
5152
+ params.set("per_page", "6");
5153
+ url.search = params.toString();
5154
+ let urlString = url.toString();
5155
+ if (urlString.includes(base)) {
5156
+ urlString = urlString.replace(base, "");
5157
+ }
5158
+ return urlString;
5159
+ }
5120
5160
  renderCollection(html) {
5121
5161
  this.dropdownTarget.innerHTML = html;
5122
5162
  }
@@ -5128,13 +5168,19 @@ var autocomplete_controller_default = class extends Controller {
5128
5168
  this.dropdownItemTargets.forEach((dropdownItem) => {
5129
5169
  let text = dropdownItem.innerHTML;
5130
5170
  text = text.replace(/<mark.*?>(.*?)<\/mark>/ig, "$1");
5131
- const regex2 = new RegExp(`(${query})`, "gi");
5132
- text = text.replace(regex2, "<mark>$1</mark>");
5171
+ if (query && query.length > 0) {
5172
+ const regex2 = new RegExp(`(?<!<[^>]*?)(&nbsp;)?(${query})`, "gi");
5173
+ text = text.replace(regex2, "<mark>$2</mark>");
5174
+ }
5133
5175
  dropdownItem.innerHTML = text;
5134
5176
  });
5135
5177
  }
5136
5178
  select(event) {
5137
- this.inputTarget.value = event.target.getAttribute("value");
5179
+ this.setValue(event.currentTarget.getAttribute("value"));
5180
+ }
5181
+ setValue(value) {
5182
+ this.inputTarget.value = value;
5183
+ this.inputTarget.dispatchEvent(new Event("change"));
5138
5184
  this.hide();
5139
5185
  }
5140
5186
  value() {
@@ -15046,12 +15092,15 @@ var popup_controller_default = class extends Controller {
15046
15092
  const button = event.target.closest('[data-popup-target="button"]');
15047
15093
  const popup = this.popupById(button.dataset.popupId);
15048
15094
  const passThru = button.dataset.popupPassThru;
15095
+ createPopper3(button, popup);
15096
+ this.openPopup(popup);
15049
15097
  if (passThru) {
15050
15098
  const passThruElement = popup.querySelector(passThru);
15051
15099
  passThruElement.click();
15052
- } else {
15053
- createPopper3(button, popup);
15054
- this.openPopup(popup);
15100
+ if (passThruElement instanceof HTMLInputElement) {
15101
+ passThruElement.focus();
15102
+ passThruElement.select();
15103
+ }
15055
15104
  }
15056
15105
  }
15057
15106
  close(event) {
@@ -1,5 +1,14 @@
1
1
  html {
2
2
  height: 100%;
3
+ background: red;
4
+ }
5
+
6
+ .list-group-item {
7
+ &.active {
8
+ .text-muted {
9
+ color: $list-group-active-color !important;
10
+ }
11
+ }
3
12
  }
4
13
 
5
14
  mark {
@@ -13103,6 +13103,10 @@ input[type=search] {
13103
13103
  }
13104
13104
  html {
13105
13105
  height: 100%;
13106
+ background: red;
13107
+ }
13108
+ .list-group-item.active .text-muted {
13109
+ color: #fff !important;
13106
13110
  }
13107
13111
  mark,
13108
13112
  .mark {
@@ -4,7 +4,7 @@ module Headmin
4
4
  def repeater_options
5
5
  keys = %i[form attribute names label]
6
6
  options = to_h.slice(*keys)
7
- default_repeater_options.merge(options)
7
+ default_repeater_options.deep_merge(options)
8
8
  end
9
9
 
10
10
  def paths
@@ -17,7 +17,7 @@ module Headmin
17
17
  def input_options
18
18
  keys = attributes - %i[attribute form label validate wrapper checked_value unchecked_value]
19
19
  options = to_h.slice(*keys)
20
- default_input_options.merge(options)
20
+ default_input_options.deep_merge(options)
21
21
  end
22
22
 
23
23
  def label_options
@@ -31,11 +31,11 @@ module Headmin
31
31
  end
32
32
 
33
33
  def wrapper_options
34
- default_wrapper_options.merge(
34
+ default_wrapper_options.deep_merge(
35
35
  {
36
36
  class: %w[form-check mb-3]
37
37
  }
38
- ).merge(@wrapper || {})
38
+ ).deep_merge(@wrapper || {})
39
39
  end
40
40
 
41
41
  private
@@ -2,11 +2,11 @@ module Headmin
2
2
  module Form
3
3
  class DateRangeView < ViewModel
4
4
  def start_options
5
- default_start_options.merge(@start || {})
5
+ default_start_options.deep_merge(@start || {})
6
6
  end
7
7
 
8
8
  def end_options
9
- default_end_options.merge(@end || {})
9
+ default_end_options.deep_merge(@end || {})
10
10
  end
11
11
 
12
12
  private
@@ -12,19 +12,19 @@ module Headmin
12
12
  def input_options
13
13
  keys = attributes - %i[append attribute float form input_group input_group label prepend validate wrapper]
14
14
  options = to_h.slice(*keys)
15
- default_input_options.merge(options)
15
+ default_input_options.deep_merge(options)
16
16
  end
17
17
 
18
18
  def input_group_options
19
19
  default_input_group_options
20
- .merge(label_input_group_options)
21
- .merge(@input_group || {})
20
+ .deep_merge(label_input_group_options)
21
+ .deep_merge(@input_group || {})
22
22
  end
23
23
 
24
24
  def wrapper_options
25
- default_wrapper_options.merge({
25
+ default_wrapper_options.deep_merge({
26
26
  class: ["mb-3", ("form-floating" if float)]
27
- }).merge(@wrapper || {})
27
+ }).deep_merge(@wrapper || {})
28
28
  end
29
29
 
30
30
  private
@@ -13,21 +13,21 @@ module Headmin
13
13
  def input_options
14
14
  keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
15
  options = to_h.slice(*keys)
16
- options = default_input_options.merge(options)
17
- options.merge(autocomplete_input_options)
16
+ options = default_input_options.deep_merge(options)
17
+ options.deep_merge(autocomplete_input_options)
18
18
  end
19
19
 
20
20
  def input_group_options
21
21
  default_input_group_options
22
- .merge(autocomplete_input_group_options)
23
- .merge(label_input_group_options)
24
- .merge(@input_group || {})
22
+ .deep_merge(autocomplete_input_group_options)
23
+ .deep_merge(label_input_group_options)
24
+ .deep_merge(@input_group || {})
25
25
  end
26
26
 
27
27
  def wrapper_options
28
- default_wrapper_options.merge({
28
+ default_wrapper_options.deep_merge({
29
29
  class: ["mb-3", ("form-floating" if float)]
30
- }).merge(@wrapper || {})
30
+ }).deep_merge(@wrapper || {})
31
31
  end
32
32
 
33
33
  private
@@ -11,24 +11,24 @@ module Headmin
11
11
  def input_options
12
12
  keys = attributes - %i[append attribute dropzone destroy form input_group label prepend preview validate wrapper]
13
13
  options = to_h.slice(*keys)
14
- options = default_input_options.merge(options)
15
- options = options.merge(required: false) if attachments.any?
14
+ options = default_input_options.deep_merge(options)
15
+ options = options.deep_merge(required: false) if attachments.any?
16
16
  options
17
17
  end
18
18
 
19
19
  def input_group_options
20
20
  default_input_group_options
21
- .merge(label_input_group_options)
22
- .merge(@input_group || {})
21
+ .deep_merge(label_input_group_options)
22
+ .deep_merge(@input_group || {})
23
23
  end
24
24
 
25
25
  def wrapper_options
26
- default_wrapper_options.merge({
26
+ default_wrapper_options.deep_merge({
27
27
  class: ["mb-3 h-form-file", ("form-floating" if float)],
28
28
  data: {
29
29
  controller: ("file-preview" if preview)
30
30
  }
31
- }).merge(@wrapper || {})
31
+ }).deep_merge(@wrapper || {})
32
32
  end
33
33
 
34
34
  def preview
@@ -22,32 +22,32 @@ module Headmin
22
22
  end
23
23
 
24
24
  def start_options
25
- default_start_options.merge(@start || {})
25
+ default_start_options.deep_merge(@start || {})
26
26
  end
27
27
 
28
28
  def end_options
29
- default_end_options.merge(@end || {})
29
+ default_end_options.deep_merge(@end || {})
30
30
  end
31
31
 
32
32
  def input_options
33
33
  keys = attributes - %i[append attribute end float form input_group label prepend start validate wrapper]
34
34
  options = to_h.slice(*keys)
35
- default_input_options.merge(options)
35
+ default_input_options.deep_merge(options)
36
36
  end
37
37
 
38
38
  def input_group_options
39
39
  default_input_group_options
40
- .merge(label_input_group_options)
41
- .merge(@input_group || {})
40
+ .deep_merge(label_input_group_options)
41
+ .deep_merge(@input_group || {})
42
42
  end
43
43
 
44
44
  def wrapper_options
45
- default_wrapper_options.merge({
45
+ default_wrapper_options.deep_merge({
46
46
  class: ["mb-3", ("form-floating" if float)],
47
47
  data: {
48
48
  controller: "flatpickr date-range"
49
49
  }
50
- }).merge(@wrapper || {})
50
+ }).deep_merge(@wrapper || {})
51
51
  end
52
52
 
53
53
  private
@@ -4,15 +4,15 @@ module Headmin
4
4
  def options
5
5
  keys = attributes - %i[data wrapper]
6
6
  options = to_h.slice(*keys)
7
- default_options.merge(options)
7
+ default_options.deep_merge(options)
8
8
  end
9
9
 
10
10
  private
11
11
 
12
12
  def default_options
13
13
  {
14
- data: default_data.merge(data || {}),
15
- wrapper: default_wrapper_options.merge(wrapper || {})
14
+ data: default_data.deep_merge(data || {}),
15
+ wrapper: default_wrapper_options.deep_merge(wrapper || {})
16
16
  }
17
17
  end
18
18
 
@@ -4,7 +4,7 @@ module Headmin
4
4
  def options
5
5
  keys = attributes - %i[bypass append prepend]
6
6
  options = to_h.slice(*keys)
7
- default_options.merge(options)
7
+ default_options.deep_merge(options)
8
8
  end
9
9
 
10
10
  private
@@ -8,7 +8,7 @@ module Headmin
8
8
  def options
9
9
  keys = attributes - %i[attribute form text]
10
10
  options = to_h.slice(*keys)
11
- default_options.merge(options)
11
+ default_options.deep_merge(options)
12
12
  end
13
13
 
14
14
  private
@@ -12,19 +12,19 @@ module Headmin
12
12
  def input_options
13
13
  keys = attributes - %i[append attribute float form input_group label prepend validate wrapper]
14
14
  options = to_h.slice(*keys)
15
- default_input_options.merge(options)
15
+ default_input_options.deep_merge(options)
16
16
  end
17
17
 
18
18
  def input_group_options
19
19
  default_input_group_options
20
- .merge(label_input_group_options)
21
- .merge(@input_group || {})
20
+ .deep_merge(label_input_group_options)
21
+ .deep_merge(@input_group || {})
22
22
  end
23
23
 
24
24
  def wrapper_options
25
- default_wrapper_options.merge({
25
+ default_wrapper_options.deep_merge({
26
26
  class: ["mb-3", float_class]
27
- }).merge(@wrapper || {})
27
+ }).deep_merge(@wrapper || {})
28
28
  end
29
29
 
30
30
  private
@@ -11,19 +11,19 @@ module Headmin
11
11
  def input_options
12
12
  keys = attributes - %i[append attribute float form input_group label prepend validate wrapper]
13
13
  options = to_h.slice(*keys)
14
- default_input_options.merge(options)
14
+ default_input_options.deep_merge(options)
15
15
  end
16
16
 
17
17
  def input_group_options
18
18
  default_input_group_options
19
- .merge(label_input_group_options)
20
- .merge(@input_group || {})
19
+ .deep_merge(label_input_group_options)
20
+ .deep_merge(@input_group || {})
21
21
  end
22
22
 
23
23
  def wrapper_options
24
- default_wrapper_options.merge({
24
+ default_wrapper_options.deep_merge({
25
25
  class: ["mb-3", ("form-floating" if float)]
26
- }).merge(@wrapper || {})
26
+ }).deep_merge(@wrapper || {})
27
27
  end
28
28
 
29
29
  private
@@ -2,7 +2,7 @@ module Headmin
2
2
  module Form
3
3
  class RedactorxView < ViewModel
4
4
  def options
5
- default_options.merge(to_h)
5
+ default_options.deep_merge(to_h)
6
6
  end
7
7
 
8
8
  private
@@ -39,7 +39,7 @@ module Headmin
39
39
  attr_reader :topbar
40
40
 
41
41
  def redactor_options
42
- default_redactor_options.merge(redactor || {})
42
+ default_redactor_options.deep_merge(redactor || {})
43
43
  end
44
44
 
45
45
  def default_redactor_options
@@ -13,21 +13,21 @@ module Headmin
13
13
  def input_options
14
14
  keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
15
  options = to_h.slice(*keys)
16
- options = default_input_options.merge(options)
17
- options.merge(autocomplete_input_options)
16
+ options = default_input_options.deep_merge(options)
17
+ options.deep_merge(autocomplete_input_options)
18
18
  end
19
19
 
20
20
  def input_group_options
21
21
  default_input_group_options
22
- .merge(autocomplete_input_group_options)
23
- .merge(label_input_group_options)
24
- .merge(@input_group || {})
22
+ .deep_merge(autocomplete_input_group_options)
23
+ .deep_merge(label_input_group_options)
24
+ .deep_merge(@input_group || {})
25
25
  end
26
26
 
27
27
  def wrapper_options
28
- default_wrapper_options.merge({
28
+ default_wrapper_options.deep_merge({
29
29
  class: ["mb-3", ("form-floating" if float)]
30
- }).merge(@wrapper || {})
30
+ }).deep_merge(@wrapper || {})
31
31
  end
32
32
 
33
33
  private
@@ -12,25 +12,25 @@ module Headmin
12
12
  def input_options
13
13
  keys = attributes - %i[append attribute collection float form input_group include_blank label prepend validate selected tags wrapper]
14
14
  options = to_h.slice(*keys)
15
- default_input_options.merge(options)
15
+ default_input_options.deep_merge(options)
16
16
  end
17
17
 
18
18
  def input_group_options
19
19
  default_input_group_options
20
- .merge(label_input_group_options)
21
- .merge(@input_group || {})
20
+ .deep_merge(label_input_group_options)
21
+ .deep_merge(@input_group || {})
22
22
  end
23
23
 
24
24
  def wrapper_options
25
- default_wrapper_options.merge({
25
+ default_wrapper_options.deep_merge({
26
26
  class: ["mb-3", ("form-floating" if float)]
27
- }).merge(@wrapper || {})
27
+ }).deep_merge(@wrapper || {})
28
28
  end
29
29
 
30
30
  def select_options
31
31
  keys = %i[include_blank selected]
32
32
  options = to_h.slice(*keys)
33
- default_options.merge(options)
33
+ default_options.deep_merge(options)
34
34
  end
35
35
 
36
36
  private
@@ -2,7 +2,7 @@ module Headmin
2
2
  module Form
3
3
  class SwitchView < ViewModel
4
4
  def options
5
- default_options.merge(to_h)
5
+ default_options.deep_merge(to_h)
6
6
  end
7
7
 
8
8
  private
@@ -13,21 +13,21 @@ module Headmin
13
13
  def input_options
14
14
  keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
15
  options = to_h.slice(*keys)
16
- options = default_input_options.merge(options)
17
- options.merge(autocomplete_input_options)
16
+ options = default_input_options.deep_merge(options)
17
+ options.deep_merge(autocomplete_input_options)
18
18
  end
19
19
 
20
20
  def input_group_options
21
21
  default_input_group_options
22
- .merge(autocomplete_input_group_options)
23
- .merge(label_input_group_options)
24
- .merge(@input_group || {})
22
+ .deep_merge(autocomplete_input_group_options)
23
+ .deep_merge(label_input_group_options)
24
+ .deep_merge(@input_group || {})
25
25
  end
26
26
 
27
27
  def wrapper_options
28
- default_wrapper_options.merge({
28
+ default_wrapper_options.deep_merge({
29
29
  class: ["mb-3", ("form-floating" if float)]
30
- }).merge(@wrapper || {})
30
+ }).deep_merge(@wrapper || {})
31
31
  end
32
32
 
33
33
  private
@@ -11,19 +11,19 @@ module Headmin
11
11
  def input_options
12
12
  keys = attributes - %i[attribute float form input_group label validate wrapper]
13
13
  options = to_h.slice(*keys)
14
- default_input_options.merge(options)
14
+ default_input_options.deep_merge(options)
15
15
  end
16
16
 
17
17
  def input_group_options
18
18
  default_input_group_options
19
- .merge(label_input_group_options)
20
- .merge(@input_group || {})
19
+ .deep_merge(label_input_group_options)
20
+ .deep_merge(@input_group || {})
21
21
  end
22
22
 
23
23
  def wrapper_options
24
- default_wrapper_options.merge({
24
+ default_wrapper_options.deep_merge({
25
25
  class: ["mb-3", ("form-floating" if float)]
26
- }).merge(@wrapper || {})
26
+ }).deep_merge(@wrapper || {})
27
27
  end
28
28
 
29
29
  private
@@ -13,21 +13,21 @@ module Headmin
13
13
  def input_options
14
14
  keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
15
  options = to_h.slice(*keys)
16
- options = default_input_options.merge(options)
17
- options.merge(autocomplete_input_options)
16
+ options = default_input_options.deep_merge(options)
17
+ options.deep_merge(autocomplete_input_options)
18
18
  end
19
19
 
20
20
  def input_group_options
21
21
  default_input_group_options
22
- .merge(autocomplete_input_group_options)
23
- .merge(label_input_group_options)
24
- .merge(@input_group || {})
22
+ .deep_merge(autocomplete_input_group_options)
23
+ .deep_merge(label_input_group_options)
24
+ .deep_merge(@input_group || {})
25
25
  end
26
26
 
27
27
  def wrapper_options
28
- default_wrapper_options.merge({
28
+ default_wrapper_options.deep_merge({
29
29
  class: ["mb-3", ("form-floating" if float)]
30
- }).merge(@wrapper || {})
30
+ }).deep_merge(@wrapper || {})
31
31
  end
32
32
 
33
33
  private
@@ -4,7 +4,7 @@ module Headmin
4
4
  def options
5
5
  keys = attributes - %i[bypass]
6
6
  options = to_h.slice(*keys)
7
- default_options.merge(options)
7
+ default_options.deep_merge(options)
8
8
  end
9
9
 
10
10
  private
@@ -2,7 +2,7 @@ module Headmin
2
2
  module Form
3
3
  class WysiwygView < ViewModel
4
4
  def options
5
- default_options.merge(to_h)
5
+ default_options.deep_merge(to_h)
6
6
  end
7
7
 
8
8
  private
@@ -24,6 +24,7 @@
24
24
  # <% end %#>
25
25
 
26
26
  label = local_assigns.has_key?(:label) ? label : nil
27
+ wrapper = local_assigns.has_key?(:wrapper) ? local_assigns[:wrapper] : true
27
28
  show_label = label != false
28
29
  %>
29
30
 
@@ -32,9 +33,13 @@
32
33
  <%= render 'headmin/forms/label', form: form, attribute: :value, text: label || field_label %>
33
34
  <% end %>
34
35
 
36
+ <% if wrapper %>
35
37
  <ul class="list-group mb-3">
36
38
  <li class="list-group-item">
37
39
  <%= yield group %>
38
40
  </li>
39
41
  </ul>
42
+ <% else %>
43
+ <%= yield group %>
44
+ <% end %>
40
45
  <% end %>
@@ -22,7 +22,7 @@ en:
22
22
  blank: Make a choice
23
23
  repeater:
24
24
  add: "Add %{name}"
25
- empty: This list is empty for now.
25
+ empty: Start by adding your first block
26
26
  row:
27
27
  add: Add row
28
28
  remove: Remove row
@@ -21,7 +21,7 @@ nl:
21
21
  blank: Maak een keuze
22
22
  repeater:
23
23
  add: "%{name} toevoegen"
24
- empty: Deze lijst is voorlopig nog leeg.
24
+ empty: Voeg je eerste blok toe om te beginnen
25
25
  row:
26
26
  add: Rij toevoegen
27
27
  remove: Rij verwijderen
@@ -1,3 +1,3 @@
1
1
  module Headmin
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: headmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jef Vlamings
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-14 00:00:00.000000000 Z
11
+ date: 2022-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: closure_tree