headmin 0.3.4 → 0.4.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 (162) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +27 -0
  3. data/.gitignore +14 -0
  4. data/.lock-487e157d270f3062a98b7b2a012753708-1272821827 +0 -0
  5. data/.nvmrc +1 -0
  6. data/CHANGELOG.md +31 -0
  7. data/Gemfile +7 -4
  8. data/Gemfile.lock +191 -25
  9. data/README.md +7 -0
  10. data/Rakefile +1 -7
  11. data/app/assets/javascripts/headmin/config/i18n.js +9 -9
  12. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +318 -0
  13. data/app/assets/javascripts/headmin/controllers/blocks_controller.js +74 -79
  14. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +24 -24
  15. data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +23 -25
  16. data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +237 -237
  17. data/app/assets/javascripts/headmin/controllers/filter_controller.js +44 -44
  18. data/app/assets/javascripts/headmin/controllers/filters_controller.js +57 -61
  19. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +29 -29
  20. data/app/assets/javascripts/headmin/controllers/hello_controller.js +3 -3
  21. data/app/assets/javascripts/headmin/controllers/notification_controller.js +7 -6
  22. data/app/assets/javascripts/headmin/controllers/popup_controller.js +57 -51
  23. data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +36 -9
  24. data/app/assets/javascripts/headmin/controllers/repeater_controller.js +122 -125
  25. data/app/assets/javascripts/headmin/controllers/select_controller.js +40 -39
  26. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +100 -101
  27. data/app/assets/javascripts/headmin/controllers/table_controller.js +115 -115
  28. data/app/assets/javascripts/headmin/index.js +38 -35
  29. data/app/assets/javascripts/headmin.js +295 -37
  30. data/app/assets/stylesheets/headmin/forms/autocomplete.scss +21 -0
  31. data/app/assets/stylesheets/headmin/forms/file.scss +46 -0
  32. data/app/assets/stylesheets/headmin/forms/repeater.scss +62 -0
  33. data/app/assets/stylesheets/headmin/forms/search.scss +12 -0
  34. data/app/assets/stylesheets/headmin/forms.scss +11 -0
  35. data/app/assets/stylesheets/headmin/general.scss +14 -0
  36. data/app/assets/stylesheets/headmin/overrides/bootstrap.scss +5 -3
  37. data/app/assets/stylesheets/headmin/overrides/redactorx.scss +74 -0
  38. data/app/assets/stylesheets/headmin/popup.scss +1 -0
  39. data/app/assets/stylesheets/headmin/syntax.scss +36 -349
  40. data/app/assets/stylesheets/headmin/table.scss +1 -1
  41. data/app/assets/stylesheets/headmin/utilities/buttons.scss +19 -0
  42. data/app/assets/stylesheets/headmin/utilities/dropzone.scss +72 -0
  43. data/app/assets/stylesheets/headmin/utilities.scss +2 -68
  44. data/app/assets/stylesheets/headmin.css +209 -205
  45. data/app/assets/stylesheets/headmin.scss +1 -1
  46. data/app/helpers/headmin/admin_helper.rb +0 -1
  47. data/app/helpers/headmin/form_helper.rb +2 -8
  48. data/app/models/concerns/headmin/blockable.rb +1 -1
  49. data/app/models/concerns/headmin/field.rb +4 -1
  50. data/app/models/concerns/headmin/fieldable.rb +138 -44
  51. data/app/models/concerns/headmin/form/autocompletable.rb +38 -0
  52. data/app/models/concerns/headmin/form/hintable.rb +19 -0
  53. data/app/models/concerns/headmin/form/input_groupable.rb +23 -0
  54. data/app/models/concerns/headmin/form/labelable.rb +33 -0
  55. data/app/models/concerns/headmin/form/listable.rb +28 -0
  56. data/app/models/concerns/headmin/form/placeholderable.rb +13 -0
  57. data/app/models/concerns/headmin/form/validatable.rb +40 -0
  58. data/app/models/concerns/headmin/form/wrappable.rb +21 -0
  59. data/app/models/headmin/.DS_Store +0 -0
  60. data/app/models/headmin/blocks_view.rb +15 -0
  61. data/app/models/headmin/form/blocks_view.rb +29 -0
  62. data/app/models/headmin/form/checkbox_view.rb +52 -0
  63. data/app/models/headmin/form/date_range_view.rb +25 -0
  64. data/app/models/headmin/form/date_view.rb +45 -0
  65. data/app/models/headmin/form/email_view.rb +48 -0
  66. data/app/models/headmin/form/file_view.rb +116 -0
  67. data/app/models/headmin/form/flatpickr_range_view.rb +102 -0
  68. data/app/models/headmin/form/flatpickr_view.rb +37 -0
  69. data/app/models/headmin/form/hidden_view.rb +10 -0
  70. data/app/models/headmin/form/hint_view.rb +6 -0
  71. data/app/models/headmin/form/input_group_view.rb +19 -0
  72. data/app/models/headmin/form/label_view.rb +24 -0
  73. data/app/models/headmin/form/number_view.rb +49 -0
  74. data/app/models/headmin/form/password_view.rb +44 -0
  75. data/app/models/headmin/form/redactorx_view.rb +59 -0
  76. data/app/models/headmin/form/search_view.rb +48 -0
  77. data/app/models/headmin/form/select_view.rb +62 -0
  78. data/app/models/headmin/form/switch_view.rb +23 -0
  79. data/app/models/headmin/form/text_view.rb +48 -0
  80. data/app/models/headmin/form/textarea_view.rb +44 -0
  81. data/app/models/headmin/form/url_view.rb +48 -0
  82. data/app/models/headmin/form/wrapper_view.rb +19 -0
  83. data/app/models/headmin/form/wysiwyg_view.rb +17 -0
  84. data/app/models/headmin/{thumbnail.rb → thumbnail_view.rb} +6 -1
  85. data/app/models/view_model.rb +58 -0
  86. data/app/views/headmin/_blocks.html.erb +13 -9
  87. data/app/views/headmin/_heading.html.erb +7 -1
  88. data/app/views/headmin/_thumbnail.html.erb +1 -37
  89. data/app/views/headmin/forms/_autocomplete.html.erb +11 -0
  90. data/app/views/headmin/forms/_blocks.html.erb +16 -17
  91. data/app/views/headmin/forms/_checkbox.html.erb +24 -29
  92. data/app/views/headmin/forms/_datalist.html.erb +3 -0
  93. data/app/views/headmin/forms/_date.html.erb +24 -24
  94. data/app/views/headmin/forms/_date_range.html.erb +19 -21
  95. data/app/views/headmin/forms/_email.html.erb +27 -32
  96. data/app/views/headmin/forms/_errors.html.erb +2 -3
  97. data/app/views/headmin/forms/_file.html.erb +84 -181
  98. data/app/views/headmin/forms/_flatpickr.html.erb +19 -20
  99. data/app/views/headmin/forms/_flatpickr_range.html.erb +28 -37
  100. data/app/views/headmin/forms/_hidden.html.erb +9 -10
  101. data/app/views/headmin/forms/_hint.html.erb +16 -0
  102. data/app/views/headmin/forms/_input_group.html.erb +21 -0
  103. data/app/views/headmin/forms/_label.html.erb +5 -13
  104. data/app/views/headmin/forms/_number.html.erb +23 -35
  105. data/app/views/headmin/forms/_password.html.erb +21 -30
  106. data/app/views/headmin/forms/_redactorx.html.erb +21 -40
  107. data/app/views/headmin/forms/_repeater.html.erb +55 -60
  108. data/app/views/headmin/forms/_search.html.erb +43 -0
  109. data/app/views/headmin/forms/_select.html.erb +24 -49
  110. data/app/views/headmin/forms/_switch.html.erb +29 -0
  111. data/app/views/headmin/forms/_text.html.erb +42 -96
  112. data/app/views/headmin/forms/_textarea.html.erb +21 -32
  113. data/app/views/headmin/forms/_url.html.erb +26 -31
  114. data/app/views/headmin/forms/_validation.html.erb +10 -13
  115. data/app/views/headmin/forms/_wrapper.html.erb +9 -0
  116. data/app/views/headmin/forms/_wysiwyg.html.erb +28 -0
  117. data/app/views/headmin/forms/autocomplete/_item.html.erb +3 -0
  118. data/app/views/headmin/forms/autocomplete/_list.html.erb +3 -0
  119. data/app/views/headmin/forms/fields/_file.html.erb +1 -1
  120. data/app/views/headmin/forms/fields/_files.html.erb +17 -0
  121. data/app/views/headmin/forms/fields/_group.html.erb +9 -2
  122. data/app/views/headmin/forms/repeater/_row.html.erb +4 -4
  123. data/bin/console +0 -1
  124. data/config/locales/headmin/forms/en.yml +1 -12
  125. data/config/locales/headmin/forms/nl.yml +1 -12
  126. data/esbuild-css.js +18 -18
  127. data/esbuild-js.js +8 -8
  128. data/headmin.gemspec +1 -3
  129. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +0 -2
  130. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +0 -2
  131. data/lib/generators/templates/controllers/auth/passwords_controller.rb +0 -2
  132. data/lib/generators/templates/controllers/auth/registrations_controller.rb +0 -2
  133. data/lib/generators/templates/controllers/auth/sessions_controller.rb +0 -2
  134. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +0 -2
  135. data/lib/headmin/version.rb +1 -3
  136. data/lib/headmin.rb +0 -2
  137. data/package-lock.json +5359 -0
  138. data/package.json +12 -4
  139. data/view_model_benchmark.rb +74 -0
  140. data/yarn-error.log +17 -12
  141. data/yarn.lock +1575 -31
  142. metadata +64 -25
  143. data/app/assets/stylesheets/headmin/form.scss +0 -132
  144. data/app/assets/stylesheets/headmin/overrides/redactorx.css +0 -3
  145. data/app/helpers/headmin/documentation_helper.rb +0 -35
  146. data/app/models/headmin/documentation_renderer.rb +0 -32
  147. data/app/models/headmin/form/base.rb +0 -78
  148. data/app/models/headmin/form/text.rb +0 -51
  149. data/app/services/block_service.rb +0 -72
  150. data/app/views/headmin/_card.html.erb +0 -52
  151. data/app/views/headmin/forms/_actions.html.erb +0 -28
  152. data/app/views/headmin/forms/_base.html.erb +0 -114
  153. data/app/views/headmin/forms/_image.html.erb +0 -21
  154. data/app/views/headmin/forms/_video.html.erb +0 -21
  155. data/app/views/headmin/forms/actions/_destroy.html.erb +0 -13
  156. data/app/views/headmin/forms/actions/_save.html.erb +0 -12
  157. data/app/views/headmin/forms/actions/_view.html.erb +0 -15
  158. data/app/views/headmin/forms/fields/_image.html.erb +0 -17
  159. data/docs/blocks-and-fields.md +0 -54
  160. data/docs/blocks.md +0 -48
  161. data/docs/devise.md +0 -41
  162. data/docs/fields.md +0 -79
@@ -0,0 +1,318 @@
1
+ /* global fetch, Event */
2
+ import { Controller } from '@hotwired/stimulus'
3
+
4
+ export default class extends Controller {
5
+ static get targets () {
6
+ return ['input', 'dropdown', 'dropdownItem']
7
+ }
8
+
9
+ static get values () {
10
+ return {
11
+ url: String
12
+ }
13
+ }
14
+
15
+ connect () {
16
+ // Focus
17
+ this.inputTarget.addEventListener('focus', (event) => {
18
+ this.show()
19
+ })
20
+
21
+ // Navigation
22
+ this.inputTarget.addEventListener('keydown', (event) => {
23
+ this.handleKeydown(event)
24
+ })
25
+
26
+ // Typing
27
+ this.inputTarget.addEventListener('keyup', (event) => {
28
+ this.handleKeyup(event)
29
+ })
30
+
31
+ // Clicked outside dropdown
32
+ document.addEventListener('click', (event) => {
33
+ this.handleOutsideClick(event)
34
+ })
35
+ }
36
+
37
+ handleKeydown (event) {
38
+ const keyCode = parseInt(event.keyCode, 10)
39
+ if (this.isArrowKey(keyCode)) {
40
+ this.handleArrowKey(keyCode)
41
+ }
42
+
43
+ if (this.isEnterKey(keyCode)) {
44
+ this.selectActiveItem(event)
45
+ }
46
+ }
47
+
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
+ }
65
+ }
66
+
67
+ isEnterKey (keyCode) {
68
+ return keyCode === 13
69
+ }
70
+
71
+ handleArrowKey (keyCode) {
72
+ this.show()
73
+ switch (keyCode) {
74
+ case 38:
75
+ this.handleArrowUp()
76
+ break
77
+ case 40:
78
+ this.handleArrowDown()
79
+ break
80
+ default:
81
+ }
82
+ }
83
+
84
+ handleArrowUp () {
85
+ this.selectPreviousItem()
86
+ }
87
+
88
+ handleArrowDown () {
89
+ this.selectNextItem()
90
+ }
91
+
92
+ selectNextItem () {
93
+ const next = this.nextItem()
94
+ if (next) {
95
+ this.deselectAll()
96
+ next.classList.add('active')
97
+ }
98
+ }
99
+
100
+ nextItem () {
101
+ const current = this.activeItem()
102
+
103
+ // Select first item if nothing selected
104
+ if (!this.hasSelectedItem()) {
105
+ return this.firstItem()
106
+ }
107
+
108
+ if (this.isItemLast(current)) {
109
+ return this.firstItem()
110
+ } else {
111
+ const index = this.itemIndex(current)
112
+ return this.itemAtIndex(index + 1)
113
+ }
114
+ }
115
+
116
+ selectPreviousItem () {
117
+ const previous = this.previousItem()
118
+ if (previous) {
119
+ this.deselectAll()
120
+ previous.classList.add('active')
121
+ }
122
+ }
123
+
124
+ previousItem () {
125
+ const current = this.activeItem()
126
+
127
+ // Select last item if nothing selected
128
+ if (!this.hasSelectedItem()) {
129
+ return this.lastItem()
130
+ }
131
+
132
+ if (this.isItemFirst(current)) {
133
+ return this.lastItem()
134
+ } else {
135
+ const index = this.itemIndex(current)
136
+ return this.itemAtIndex(index - 1)
137
+ }
138
+ }
139
+
140
+ deselectAll () {
141
+ this.dropdownItemTargets.forEach(dropdownItem => {
142
+ dropdownItem.classList.remove('active')
143
+ })
144
+ }
145
+
146
+ itemAtIndex (index) {
147
+ return this.dropdownItemTargets[index]
148
+ }
149
+
150
+ firstItem () {
151
+ return this.itemAtIndex(0)
152
+ }
153
+
154
+ lastItem () {
155
+ return this.itemAtIndex(this.dropdownItemTargets.length - 1)
156
+ }
157
+
158
+ hasSelectedItem () {
159
+ return this.activeItem() !== undefined
160
+ }
161
+
162
+ activeItem () {
163
+ return this.dropdownItemTargets.find((item) => {
164
+ return item.classList.contains('active')
165
+ })
166
+ }
167
+
168
+ isItemLast (item) {
169
+ return this.itemIndex(item) === this.dropdownItemTargets.length - 1
170
+ }
171
+
172
+ isItemFirst (item) {
173
+ return this.itemIndex(item) === 0
174
+ }
175
+
176
+ itemIndex (item) {
177
+ return Array.from(this.dropdownItemTargets).indexOf(item)
178
+ }
179
+
180
+ handleTextKey () {
181
+ // 1. fetch info
182
+ this.fetchCollection().then((html) => {
183
+ // 2. render html
184
+ this.renderCollection(html)
185
+ }).then(() => {
186
+ // 3. Highlight
187
+ this.highlight()
188
+ }).then(() => {
189
+ // 4. Preselect first result
190
+ this.activateFirstItem()
191
+ }).then(() => {
192
+ // 5. Show results
193
+ this.show()
194
+ })
195
+ }
196
+
197
+ activateFirstItem () {
198
+ this.deselectAll()
199
+ this.firstItem().classList.add('active')
200
+ }
201
+
202
+ show () {
203
+ if (this.isDropdownEmpty()) {
204
+ this.dropdownTarget.classList.remove('d-none')
205
+ } else {
206
+ this.hide()
207
+ }
208
+ }
209
+
210
+ hide () {
211
+ this.dropdownTarget.classList.add('d-none')
212
+ }
213
+
214
+ isDropdownEmpty () {
215
+ return this.dropdownTarget.textContent.trim().length > 0
216
+ }
217
+
218
+ isArrowKey (keyCode) {
219
+ const arrowKeyCodes = [37, 38, 39, 40]
220
+ return arrowKeyCodes.includes(keyCode)
221
+ }
222
+
223
+ fetchCollection () {
224
+ if (this.isRemote()) {
225
+ return fetch(this.remoteURL()).then((response) => {
226
+ return response.text()
227
+ }).catch((error) => {
228
+ console.error('The URL you provided for the autocomplete collection didn\'t return a successful result', error)
229
+ })
230
+ } else {
231
+ return Promise.resolve(this.dropdownTarget.innerHTML)
232
+ }
233
+ }
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
+
258
+ renderCollection (html) {
259
+ this.dropdownTarget.innerHTML = html
260
+ }
261
+
262
+ isRemote () {
263
+ return this.hasUrlValue
264
+ }
265
+
266
+ highlight () {
267
+ const query = this.value()
268
+ this.dropdownItemTargets.forEach(dropdownItem => {
269
+ let text = dropdownItem.innerHTML
270
+
271
+ // Clean up past results
272
+ text = text.replace(/<mark.*?>(.*?)<\/mark>/ig, '$1')
273
+
274
+ // Highlight query
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
+ }
280
+
281
+ dropdownItem.innerHTML = text
282
+ })
283
+ }
284
+
285
+ select (event) {
286
+ this.setValue(event.currentTarget.getAttribute('value'))
287
+ }
288
+
289
+ setValue (value) {
290
+ this.inputTarget.value = value
291
+ this.inputTarget.dispatchEvent(new Event('change'))
292
+ this.hide()
293
+ }
294
+
295
+ value () {
296
+ return this.inputTarget.value
297
+ }
298
+
299
+ numberOfCharacters () {
300
+ return this.value().length
301
+ }
302
+
303
+ handleOutsideClick (event) {
304
+ if (!this.isClickedInside(event)) {
305
+ this.hide()
306
+ }
307
+ }
308
+
309
+ isClickedInside (event) {
310
+ if (!event) {
311
+ return false
312
+ }
313
+ const inInput = this.inputTarget.contains(event.target)
314
+ const inDropdown = this.dropdownTarget.contains(event.target)
315
+
316
+ return (inInput || inDropdown)
317
+ }
318
+ }
@@ -1,102 +1,97 @@
1
- import {Controller} from "@hotwired/stimulus"
2
- import Sortable from "sortablejs";
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import Sortable from 'sortablejs'
3
3
 
4
4
  export default class extends Controller {
5
- static get targets() {
6
- return ["templateBlock", "block", "blocks", "templateEmpty", "button", "buttons"]
7
- }
8
-
9
- connect() {
10
- new Sortable(this.blocksTarget, {
11
- onEnd: () => {
12
- this.reorderPositions()
13
- }
14
- })
15
-
16
- this.toggleEmpty()
17
- }
5
+ static get targets () {
6
+ return ['templateBlock', 'block', 'blocks', 'templateEmpty', 'button', 'buttons']
7
+ }
18
8
 
19
- toggleEmpty() {
20
- if(this.blockCount() > 0) {
21
- const empty = this.blocksTarget.querySelector('#blocks-empty')
22
- if(empty) {
23
- empty.remove()
24
- }
25
- } else {
26
- const empty = this.templateEmptyTarget.innerHTML
27
- this.blocksTarget.insertAdjacentHTML('beforeend', empty)
28
- }
9
+ connect () {
10
+ Sortable.create(this.blocksTarget, {
11
+ onEnd: () => {
12
+ this.reorderPositions()
13
+ }
14
+ })
15
+
16
+ this.toggleEmpty()
17
+ }
18
+
19
+ toggleEmpty () {
20
+ if (this.blockCount() > 0) {
21
+ const empty = this.blocksTarget.querySelector('#blocks-empty')
22
+ if (empty) {
23
+ empty.remove()
24
+ }
25
+ } else {
26
+ const empty = this.templateEmptyTarget.innerHTML
27
+ this.blocksTarget.insertAdjacentHTML('beforeend', empty)
29
28
  }
29
+ }
30
30
 
31
- add(event) {
32
- event.preventDefault()
33
- const blockType = event.target.dataset.type
34
- let html = this.templateBlockTargets.filter(blockTarget => blockTarget.id === blockType)[0].innerHTML
35
-
36
- html = this.setPosition(html)
37
-
38
- const element = this.blocksTarget.querySelector(`li[data-position='${event.target.dataset.position}']`)
31
+ add (event) {
32
+ event.preventDefault()
33
+ const blockType = event.target.dataset.type
34
+ let html = this.templateBlockTargets.filter(blockTarget => blockTarget.id === blockType)[0].innerHTML
39
35
 
40
- if (element) {
41
- element.insertAdjacentHTML('afterend', html)
42
- }
43
- else {
44
- this.blocksTarget.insertAdjacentHTML('afterbegin', html)
45
- }
36
+ html = this.setPosition(html)
46
37
 
47
- // Dispatch an event
48
- this.blocksTarget.dispatchEvent(new CustomEvent('headmin:reinit', {bubbles: true}))
38
+ const element = this.blocksTarget.querySelector(`li[data-position='${event.target.dataset.position}']`)
49
39
 
50
- this.reorderPositions()
51
- this.toggleEmpty()
40
+ if (element) {
41
+ element.insertAdjacentHTML('afterend', html)
42
+ } else {
43
+ this.blocksTarget.insertAdjacentHTML('afterbegin', html)
52
44
  }
53
45
 
54
- remove(event) {
55
- event.preventDefault()
46
+ this.reorderPositions()
47
+ this.toggleEmpty()
48
+ }
56
49
 
57
- const block = event.target.closest(".list-group-item")
58
- const destroyInput = block.querySelector("input[name*='_destroy']")
50
+ remove (event) {
51
+ event.preventDefault()
59
52
 
60
- if (destroyInput) {
61
- destroyInput.value = 1
62
- block.style.display = 'none'
63
- } else {
64
- block.remove()
65
- }
53
+ const block = event.target.closest('.list-group-item')
54
+ const destroyInput = block.querySelector("input[name*='_destroy']")
66
55
 
67
- this.reorderPositions()
68
- this.toggleEmpty()
56
+ if (destroyInput) {
57
+ destroyInput.value = 1
58
+ block.style.display = 'none'
59
+ } else {
60
+ block.remove()
69
61
  }
70
62
 
71
- setPosition(html) {
72
- const position = this.retrieveLastPosition() + 1
63
+ this.reorderPositions()
64
+ this.toggleEmpty()
65
+ }
73
66
 
74
- const regex = new RegExp('99999', "g");
75
- return html.replace(regex, position)
76
- }
67
+ setPosition (html) {
68
+ const position = this.retrieveLastPosition() + 1
77
69
 
78
- retrieveLastPosition() {
79
- const blocks = Array.from(this.blockTargets)
80
- if (blocks.length < 1) {
81
- return 0
82
- }
70
+ return html.replace(/99999/g, position)
71
+ }
83
72
 
84
- const lastBlock = blocks.slice(-1)[0]
85
- return parseInt(lastBlock.querySelector("[name*='position']").value)
73
+ retrieveLastPosition () {
74
+ const blocks = Array.from(this.blockTargets)
75
+ if (blocks.length < 1) {
76
+ return 0
86
77
  }
87
78
 
88
- reorderPositions() {
89
- for (let [index, block] of this.blockTargets.entries()) {
90
- this.changePositionInfo(block, index)
91
- }
92
- }
79
+ const lastBlock = blocks.slice(-1)[0]
80
+ return parseInt(lastBlock.querySelector("[name*='position']").value)
81
+ }
93
82
 
94
- changePositionInfo(block, index) {
95
- block.setAttribute("data-position", index)
96
- block.querySelector("input[name*='position']").value = index
83
+ reorderPositions () {
84
+ for (const [index, block] of this.blockTargets.entries()) {
85
+ this.changePositionInfo(block, index)
97
86
  }
87
+ }
98
88
 
99
- blockCount() {
100
- return this.blockTargets.length;
101
- }
102
- }
89
+ changePositionInfo (block, index) {
90
+ block.setAttribute('data-position', index)
91
+ block.querySelector("input[name*='position']").value = index
92
+ }
93
+
94
+ blockCount () {
95
+ return this.blockTargets.length
96
+ }
97
+ }
@@ -1,32 +1,32 @@
1
- import {Controller} from "@hotwired/stimulus"
1
+ import { Controller } from '@hotwired/stimulus'
2
2
 
3
3
  export default class extends Controller {
4
- static get targets() {
5
- return ["dateInput", "startDateInput", "endDateInput"]
6
- }
4
+ static get targets () {
5
+ return ['dateInput', 'startDateInput', 'endDateInput']
6
+ }
7
7
 
8
- update(event) {
9
- const flatpickr = event.target._flatpickr
10
- const startDate = flatpickr.selectedDates[0]
11
- const endDate = flatpickr.selectedDates[1]
8
+ update (event) {
9
+ const flatpickr = event.target._flatpickr
10
+ const startDate = flatpickr.selectedDates[0]
11
+ const endDate = flatpickr.selectedDates[1]
12
12
 
13
- this.setStartDateInputValue(this.formatDate(startDate))
14
- this.setEndDateInputValue(this.formatDate(endDate))
15
- }
13
+ this.setStartDateInputValue(this.formatDate(startDate))
14
+ this.setEndDateInputValue(this.formatDate(endDate))
15
+ }
16
16
 
17
- setStartDateInputValue(value) {
18
- this.startDateInputTarget.value = value
19
- }
17
+ setStartDateInputValue (value) {
18
+ this.startDateInputTarget.value = value
19
+ }
20
20
 
21
- setEndDateInputValue(value) {
22
- this.endDateInputTarget.value = value
23
- }
21
+ setEndDateInputValue (value) {
22
+ this.endDateInputTarget.value = value
23
+ }
24
24
 
25
- formatDate(date) {
26
- if(date instanceof Date) {
27
- return date.toLocaleDateString('nl-BE', {day: '2-digit', month: '2-digit', year: 'numeric'})
28
- } else {
29
- return null;
30
- }
25
+ formatDate (date) {
26
+ if (date instanceof Date) {
27
+ return date.toLocaleDateString('nl-BE', { day: '2-digit', month: '2-digit', year: 'numeric' })
28
+ } else {
29
+ return null
31
30
  }
32
- }
31
+ }
32
+ }
@@ -1,33 +1,31 @@
1
- import {Controller} from "@hotwired/stimulus"
1
+ import { Controller } from '@hotwired/stimulus'
2
2
 
3
3
  // References:
4
4
  // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API
5
5
 
6
6
  export default class extends Controller {
7
- static get targets() {
8
- return ["input"]
9
- }
7
+ static get targets () {
8
+ return ['input']
9
+ }
10
10
 
11
- connect() {
12
- this.element.classList.add('h-dropzone')
11
+ connect () {
12
+ // Drag
13
+ this.inputTarget.addEventListener('dragover', (event) => {
14
+ this.element.classList.add('focus')
15
+ })
16
+ this.inputTarget.addEventListener('dragleave', (event) => {
17
+ this.element.classList.remove('focus')
18
+ })
19
+ this.inputTarget.addEventListener('drop', (event) => {
20
+ this.element.classList.remove('focus')
21
+ })
13
22
 
14
- // Drag
15
- this.inputTarget.addEventListener('dragover', (event) => {
16
- this.element.classList.add('dragover')
17
- })
18
- this.inputTarget.addEventListener('dragleave', (event) => {
19
- this.element.classList.remove('dragover')
20
- })
21
- this.inputTarget.addEventListener('drop', (event) => {
22
- this.element.classList.remove('dragover')
23
- })
24
-
25
- // Focus
26
- this.inputTarget.addEventListener('focusin', (event) => {
27
- this.element.classList.add('active')
28
- })
29
- this.inputTarget.addEventListener('focusout', (event) => {
30
- this.element.classList.remove('active')
31
- })
32
- }
23
+ // Focus
24
+ this.inputTarget.addEventListener('focusin', (event) => {
25
+ this.element.classList.add('focus')
26
+ })
27
+ this.inputTarget.addEventListener('focusout', (event) => {
28
+ this.element.classList.remove('focus')
29
+ })
30
+ }
33
31
  }