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,110 @@
1
+ /* global CustomEvent */
2
+ import { Controller } from '@hotwired/stimulus'
3
+
4
+ export default class extends Controller {
5
+ static get targets () {
6
+ return ['idCheckbox', 'item', 'form', 'selectButton', 'placeholder', 'count']
7
+ }
8
+
9
+ connect () {
10
+ this.validate()
11
+ this.updateCount()
12
+ }
13
+
14
+ // Actions
15
+ select () {
16
+ this.dispatchSelectionEvent()
17
+ }
18
+
19
+ submitForm () {
20
+ this.hidePlaceholder()
21
+ this.triggerFormSubmission()
22
+ }
23
+
24
+ inputChange () {
25
+ this.handleInputChange()
26
+ this.updateCount()
27
+ }
28
+
29
+ // Methods
30
+ hidePlaceholder() {
31
+ this.placeholderTarget.classList.add('d-none')
32
+ }
33
+
34
+ handleInputChange() {
35
+ this.validate()
36
+ }
37
+
38
+ dispatchSelectionEvent () {
39
+ document.dispatchEvent(
40
+ new CustomEvent(
41
+ 'mediaSelectionSubmitted',
42
+ {
43
+ detail: {
44
+ name: this.element.dataset.name,
45
+ items: this.renderItemsForEvent(this.selectedItems())
46
+ }
47
+ }
48
+ )
49
+ )
50
+ }
51
+
52
+ triggerFormSubmission () {
53
+ this.formTarget.requestSubmit()
54
+ }
55
+
56
+ renderItemsForEvent (items) {
57
+ return items.map((item) => this.renderItemForEvent(item))
58
+ }
59
+
60
+ renderItemForEvent (item) {
61
+ return {
62
+ blobId: item.querySelector('input[type="checkbox"]').value,
63
+ thumbnail: item.querySelector('.h-thumbnail')
64
+ }
65
+ }
66
+
67
+ selectedItems () {
68
+ return this.itemTargets.filter((item) => {
69
+ const checkbox = item.querySelector('input[type="checkbox"]')
70
+ return checkbox.checked
71
+ })
72
+ }
73
+
74
+ selectedItemsCount () {
75
+ return this.selectedItems().length
76
+ }
77
+
78
+ minSelectedItems () {
79
+ return parseInt(this.element.dataset.min, 10) || 0
80
+ }
81
+
82
+ maxSelectedItems () {
83
+ return parseInt(this.element.dataset.max, 10) || Infinity
84
+ }
85
+
86
+ validate () {
87
+ if (this.isValid()) {
88
+ this.enableSelectButton()
89
+ } else {
90
+ this.disableSelectButton()
91
+ }
92
+ }
93
+
94
+ enableSelectButton () {
95
+ this.selectButtonTarget.removeAttribute('disabled')
96
+ }
97
+
98
+ disableSelectButton () {
99
+ this.selectButtonTarget.setAttribute('disabled', '')
100
+ }
101
+
102
+ isValid () {
103
+ const count = this.selectedItemsCount()
104
+ return count >= this.minSelectedItems() && count <= this.maxSelectedItems()
105
+ }
106
+
107
+ updateCount() {
108
+ this.countTarget.innerHTML = this.idCheckboxTargets.filter(checkbox => checkbox.checked).length;
109
+ }
110
+ }
@@ -19,6 +19,9 @@ export default class extends Controller {
19
19
  }
20
20
 
21
21
  handleOutsideClick (event) {
22
+ const itemRemoved = !document.body.contains(event.target) // Ignore items that were removed from DOM (else this triggers a close)
23
+ if (itemRemoved) return
24
+
22
25
  const inPopup = event.target.closest('[data-popup-target="popup"]') !== null
23
26
  const inButton = event.target.closest('[data-popup-target="button"]') !== null
24
27
  const openPopup = document.querySelector('[data-popup-target="popup"]:not(.closed)')
@@ -53,7 +56,6 @@ export default class extends Controller {
53
56
  close (event) {
54
57
  const button = event.target.closest('[data-popup-target="button"]')
55
58
  const popup = this.popupById(button.dataset.popupId)
56
-
57
59
  this.closePopup(popup)
58
60
  }
59
61
 
@@ -0,0 +1,10 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import { Modal } from 'bootstrap'
3
+
4
+ export default class extends Controller {
5
+
6
+ connect () {
7
+ this.modal = new Modal(this.element)
8
+ this.modal.show()
9
+ }
10
+ }
@@ -2,12 +2,12 @@ import { Controller } from '@hotwired/stimulus'
2
2
 
3
3
  export default class extends Controller {
4
4
  static get targets () {
5
- return ['wrapper', 'form', 'select', 'method', 'button', 'idInputTemplate', 'id', 'counter']
5
+ return ['wrapper', 'form', 'select', 'method', 'button', 'idInput', 'counter']
6
6
  }
7
7
 
8
8
  connect () {
9
9
  this.wrapperTarget.addEventListener('idSelectionChanged', (event) => {
10
- this.updateIdFields(event.detail.ids)
10
+ this.updateIdInput(event.detail.ids)
11
11
  this.updateCounter(event.detail.count)
12
12
  this.toggleCounter(event.detail.count)
13
13
  })
@@ -21,17 +21,24 @@ export default class extends Controller {
21
21
  this.enableButton()
22
22
  }
23
23
 
24
- updateIdFields (ids) {
25
- this.removeIds()
26
- if (ids instanceof Array) {
27
- ids.forEach((id) => {
28
- this.addId(id)
29
- })
24
+ updateIdInput (ids) {
25
+ if (ids == null) {
26
+ this.disableIdInput()
27
+ this.idInputTarget.value = ''
30
28
  } else {
31
- this.addId('')
29
+ this.enableIdInput()
30
+ this.idInputTarget.value = `in:${ids.join(',')}`
32
31
  }
33
32
  }
34
33
 
34
+ disableIdInput () {
35
+ this.idInputTarget.removeAttribute('name')
36
+ }
37
+
38
+ enableIdInput () {
39
+ this.idInputTarget.setAttribute('name', 'id')
40
+ }
41
+
35
42
  updateCounter (count) {
36
43
  let htmlString = ''
37
44
  switch (count) {
@@ -94,16 +101,4 @@ export default class extends Controller {
94
101
  enableButton () {
95
102
  this.buttonTarget.removeAttribute('disabled')
96
103
  }
97
-
98
- addId (id) {
99
- const template = this.idInputTemplateTarget
100
- const input = template.innerHTML.replace(/ID/g, id)
101
- this.formTarget.insertAdjacentHTML('afterbegin', input)
102
- }
103
-
104
- removeIds () {
105
- this.idTargets.forEach((input) => {
106
- this.formTarget.removeChild(input)
107
- })
108
- }
109
104
  }
@@ -0,0 +1,34 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ static get targets () {
5
+ return ['textarea', 'count']
6
+ }
7
+
8
+ connect () {
9
+ this.update()
10
+ }
11
+
12
+ update () {
13
+ this.resize()
14
+ this.updateCount()
15
+ }
16
+
17
+ resize () {
18
+ this.textareaTarget.style.height = 'auto'
19
+ this.textareaTarget.setAttribute('style', 'height:' + (this.textareaTarget.scrollHeight) + 'px;overflow-y:hidden;')
20
+ }
21
+
22
+ updateCount () {
23
+ if (this.textareaTarget.getAttribute('maxlength')) {
24
+ this.updateCountLength()
25
+ }
26
+ }
27
+
28
+ updateCountLength () {
29
+ const current_length = this.textareaTarget.value.length
30
+ const maximum_length = this.textareaTarget.getAttribute('maxlength')
31
+
32
+ this.countTarget.textContent = `${current_length}/${maximum_length}`
33
+ }
34
+ }
@@ -6,16 +6,21 @@ import DateRangeController from './controllers/date_range_controller'
6
6
  import DropzoneController from './controllers/dropzone_controller'
7
7
  import FilePreviewController from './controllers/file_preview_controller'
8
8
  import FilterController from './controllers/filter_controller'
9
+ import FilterRowController from './controllers/filter_row_controller'
9
10
  import FiltersController from './controllers/filters_controller'
10
11
  import FlatpickrController from './controllers/flatpickr_controller'
11
12
  import HelloController from './controllers/hello_controller'
13
+ import MediaController from './controllers/media_controller'
14
+ import MediaModalController from './controllers/media_modal_controller'
12
15
  import NotificationController from './controllers/notification_controller'
13
16
  import PopupController from './controllers/popup_controller'
14
17
  import RedactorxController from './controllers/redactorx_controller'
18
+ import RemoteModalController from './controllers/remote_modal_controller'
15
19
  import RepeaterController from './controllers/repeater_controller'
16
20
  import SelectController from './controllers/select_controller'
17
21
  import TableActionsController from './controllers/table_actions_controller'
18
22
  import TableController from './controllers/table_controller'
23
+ import TextareaController from './controllers/textarea_controller'
19
24
 
20
25
  export class Headmin {
21
26
  static start () {
@@ -26,15 +31,20 @@ export class Headmin {
26
31
  Stimulus.register('dropzone', DropzoneController)
27
32
  Stimulus.register('file-preview', FilePreviewController)
28
33
  Stimulus.register('filter', FilterController)
34
+ Stimulus.register('filter-row', FilterRowController)
29
35
  Stimulus.register('filters', FiltersController)
30
36
  Stimulus.register('flatpickr', FlatpickrController)
31
37
  Stimulus.register('hello', HelloController)
38
+ Stimulus.register('media', MediaController)
39
+ Stimulus.register('media-modal', MediaModalController)
32
40
  Stimulus.register('notification', NotificationController)
33
41
  Stimulus.register('popup', PopupController)
34
42
  Stimulus.register('redactorx', RedactorxController)
43
+ Stimulus.register('remote-modal', RemoteModalController)
35
44
  Stimulus.register('repeater', RepeaterController)
36
45
  Stimulus.register('select', SelectController)
37
46
  Stimulus.register('table', TableController)
38
47
  Stimulus.register('table-actions', TableActionsController)
48
+ Stimulus.register('textarea', TextareaController)
39
49
  }
40
50
  }