headmin 0.1.1 → 0.2.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 (210) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +24 -2
  4. data/README.md +8 -43
  5. data/app/controllers/concerns/headmin/authentication.rb +0 -8
  6. data/app/controllers/concerns/headmin/pagination.rb +1 -1
  7. data/app/helpers/headmin/admin_helper.rb +4 -4
  8. data/app/models/concerns/headmin/block.rb +11 -0
  9. data/app/models/concerns/headmin/blockable.rb +10 -0
  10. data/app/models/concerns/headmin/field.rb +17 -0
  11. data/app/models/concerns/headmin/fieldable.rb +44 -0
  12. data/app/services/block_service.rb +68 -0
  13. data/app/views/{layouts → examples}/admin.html.erb +0 -0
  14. data/app/views/{layouts/admin → examples}/auth.html.erb +0 -0
  15. data/app/views/headmin/_blocks.html.erb +24 -0
  16. data/app/views/headmin/_breadcrumbs.html.erb +9 -5
  17. data/app/views/headmin/_card.html.erb +48 -0
  18. data/app/views/headmin/_dropdown.html.erb +18 -0
  19. data/app/views/headmin/_filters.html.erb +56 -34
  20. data/app/views/headmin/_form.html.erb +60 -6
  21. data/app/views/headmin/_heading.html.erb +8 -4
  22. data/app/views/headmin/_index.html.erb +9 -8
  23. data/app/views/headmin/_notifications.html.erb +8 -0
  24. data/app/views/headmin/_pagination.html.erb +11 -7
  25. data/app/views/headmin/_popup.html.erb +26 -0
  26. data/app/views/headmin/_table.html.erb +11 -4
  27. data/app/views/headmin/dropdown/_button.html.erb +13 -0
  28. data/app/views/headmin/dropdown/_devise.html.erb +21 -0
  29. data/app/views/headmin/{layout/dropdown → dropdown}/_divider.html.erb +1 -1
  30. data/app/views/headmin/dropdown/_item.html.erb +18 -0
  31. data/app/views/headmin/dropdown/_list.html.erb +11 -0
  32. data/app/views/headmin/dropdown/_locale.html.erb +17 -0
  33. data/app/views/headmin/filters/_date.html.erb +21 -16
  34. data/app/views/headmin/filters/_search.html.erb +18 -18
  35. data/app/views/headmin/filters/_select.html.erb +28 -23
  36. data/app/views/headmin/filters/filter/_button.html.erb +15 -6
  37. data/app/views/headmin/filters/filter/_menu_item.html.erb +2 -2
  38. data/app/views/headmin/filters/filter/_template.html.erb +2 -2
  39. data/app/views/headmin/forms/_actions.html.erb +4 -8
  40. data/app/views/headmin/forms/_base.html.erb +60 -0
  41. data/app/views/headmin/forms/_blocks.html.erb +32 -0
  42. data/app/views/headmin/forms/_checkbox.html.erb +39 -0
  43. data/app/views/headmin/forms/_ckeditor.html.erb +42 -0
  44. data/app/views/headmin/forms/_date.html.erb +45 -0
  45. data/app/views/headmin/forms/_email.html.erb +39 -0
  46. data/app/views/headmin/forms/_file.html.erb +40 -0
  47. data/app/views/headmin/forms/_image.html.erb +55 -0
  48. data/app/views/headmin/forms/_label.html.erb +24 -0
  49. data/app/views/headmin/forms/_number.html.erb +50 -0
  50. data/app/views/headmin/forms/_password.html.erb +69 -0
  51. data/app/views/headmin/forms/_redactorx.html.erb +49 -0
  52. data/app/views/headmin/forms/_repeater.html.erb +133 -0
  53. data/app/views/headmin/forms/_select.html.erb +70 -0
  54. data/app/views/headmin/forms/_text.html.erb +62 -0
  55. data/app/views/headmin/forms/_textarea.html.erb +39 -0
  56. data/app/views/headmin/forms/_url.html.erb +39 -0
  57. data/app/views/headmin/forms/_validation.html.erb +21 -0
  58. data/app/views/headmin/forms/actions/_destroy.html.erb +13 -0
  59. data/app/views/headmin/forms/actions/_save.html.erb +12 -0
  60. data/app/views/headmin/forms/actions/_view.html.erb +15 -0
  61. data/app/views/headmin/forms/fields/_base.html.erb +25 -0
  62. data/app/views/headmin/forms/fields/_file.html.erb +15 -22
  63. data/app/views/headmin/forms/fields/_group.html.erb +38 -0
  64. data/app/views/headmin/forms/fields/_image.html.erb +15 -35
  65. data/app/views/headmin/forms/fields/_list.html.erb +26 -0
  66. data/app/views/headmin/forms/fields/_text.html.erb +15 -37
  67. data/app/views/headmin/forms/repeater/_row.html.erb +51 -0
  68. data/app/views/headmin/heading/_title.html.erb +1 -1
  69. data/app/views/headmin/layout/_body.html.erb +1 -1
  70. data/app/views/headmin/layout/_content.html.erb +1 -1
  71. data/app/views/headmin/layout/_footer.html.erb +1 -1
  72. data/app/views/headmin/layout/_header.html.erb +1 -1
  73. data/app/views/headmin/layout/_main.html.erb +2 -2
  74. data/app/views/headmin/layout/_sidebar.html.erb +1 -1
  75. data/app/views/headmin/layout/sidebar/{_menu.html.erb → _nav.html.erb} +1 -1
  76. data/app/views/headmin/nav/_item.html.erb +21 -0
  77. data/app/views/headmin/nav/item/_devise.html.erb +21 -0
  78. data/app/views/headmin/nav/item/_locale.html.erb +17 -0
  79. data/app/views/headmin/pagination/_per_page.html.erb +18 -0
  80. data/app/views/headmin/{kaminari → pagination/kaminari}/_first_page.html.erb +0 -0
  81. data/app/views/headmin/{kaminari → pagination/kaminari}/_gap.html.erb +0 -0
  82. data/app/views/headmin/{kaminari → pagination/kaminari}/_last_page.html.erb +0 -0
  83. data/app/views/headmin/{kaminari → pagination/kaminari}/_next_page.html.erb +0 -0
  84. data/app/views/headmin/{kaminari → pagination/kaminari}/_page.html.erb +1 -1
  85. data/app/views/headmin/{kaminari → pagination/kaminari}/_paginator.html.erb +0 -0
  86. data/app/views/headmin/{kaminari → pagination/kaminari}/_prev_page.html.erb +0 -0
  87. data/app/views/headmin/table/_actions.html.erb +24 -17
  88. data/app/views/headmin/table/_body.html.erb +12 -10
  89. data/app/views/headmin/table/_foot.html.erb +8 -4
  90. data/app/views/headmin/table/_footer.html.erb +3 -7
  91. data/app/views/headmin/table/_head.html.erb +3 -1
  92. data/app/views/headmin/table/_header.html.erb +3 -7
  93. data/app/views/headmin/table/actions/_action.html.erb +26 -9
  94. data/app/views/headmin/table/actions/_delete.html.erb +11 -7
  95. data/app/views/headmin/table/actions/_export.html.erb +11 -7
  96. data/app/views/headmin/table/body/_association.html.erb +1 -1
  97. data/app/views/headmin/table/body/_boolean.erb +1 -1
  98. data/app/views/headmin/table/body/_currency.html.erb +1 -1
  99. data/app/views/headmin/table/body/_date.html.erb +1 -1
  100. data/app/views/headmin/table/body/_id.html.erb +2 -2
  101. data/app/views/headmin/table/body/_row.html.erb +1 -1
  102. data/app/views/headmin/table/body/_string.html.erb +1 -1
  103. data/app/views/headmin/table/body/_text.html.erb +1 -1
  104. data/app/views/headmin/table/foot/_cell.html.erb +1 -1
  105. data/app/views/headmin/table/foot/_id.html.erb +2 -2
  106. data/app/views/headmin/table/head/_cell.html.erb +1 -1
  107. data/app/views/headmin/table/head/_id.html.erb +3 -3
  108. data/app/views/headmin/views/devise/confirmations/_new.html.erb +9 -0
  109. data/app/views/headmin/views/devise/passwords/_edit.html.erb +12 -0
  110. data/app/views/headmin/views/devise/passwords/_new.html.erb +9 -0
  111. data/app/views/{admin/users/registrations/edit.html.erb → headmin/views/devise/registrations/_edit.html.erb} +5 -5
  112. data/app/views/headmin/views/devise/registrations/_new.html.erb +11 -0
  113. data/app/views/headmin/views/devise/sessions/_new.html.erb +13 -0
  114. data/app/views/{admin/users → headmin/views/devise}/shared/_error_messages.html.erb +0 -0
  115. data/app/views/{admin/users → headmin/views/devise}/shared/_links.html.erb +0 -0
  116. data/app/views/headmin/views/devise/unlocks/_new.html.erb +10 -0
  117. data/config/initializers/customize_input_error.rb +9 -0
  118. data/config/locales/devise/en.yml +65 -0
  119. data/config/locales/en.yml +2 -134
  120. data/config/locales/headmin/filters/en.yml +13 -0
  121. data/config/locales/headmin/filters/nl.yml +13 -0
  122. data/config/locales/headmin/forms/en.yml +34 -0
  123. data/config/locales/headmin/forms/nl.yml +33 -0
  124. data/config/locales/headmin/heading/en.yml +5 -0
  125. data/config/locales/headmin/heading/nl.yml +5 -0
  126. data/config/locales/headmin/layout/en.yml +14 -0
  127. data/config/locales/headmin/layout/nl.yml +14 -0
  128. data/config/locales/headmin/pagination/en.yml +21 -0
  129. data/config/locales/headmin/pagination/nl.yml +21 -0
  130. data/config/locales/headmin/table/en.yml +23 -0
  131. data/config/locales/headmin/table/nl.yml +23 -0
  132. data/config/locales/headmin/views/en.yml +58 -0
  133. data/config/locales/headmin/views/nl.yml +58 -0
  134. data/config/locales/nl.yml +2 -135
  135. data/dist/css/headmin.css +3182 -743
  136. data/dist/js/headmin.js +729 -33
  137. data/docs/README.md +2 -1
  138. data/docs/blocks.md +70 -85
  139. data/docs/devise.md +1 -60
  140. data/docs/fields.md +57 -0
  141. data/headmin.gemspec +1 -0
  142. data/lib/generators/headmin/blocks_generator.rb +19 -0
  143. data/lib/generators/headmin/fields_generator.rb +19 -0
  144. data/lib/generators/templates/migrations/create_blocks.rb +10 -0
  145. data/lib/generators/templates/migrations/create_fields.rb +13 -0
  146. data/lib/generators/templates/models/block.rb +3 -0
  147. data/lib/generators/templates/models/field.rb +3 -0
  148. data/lib/headmin/version.rb +1 -1
  149. data/package.json +6 -6
  150. data/src/js/headmin/controllers/blocks_controller.js +103 -0
  151. data/src/js/headmin/controllers/filters_controller.js +23 -12
  152. data/src/js/headmin/controllers/popup_controller.js +68 -0
  153. data/src/js/headmin/controllers/repeater_controller.js +117 -11
  154. data/src/js/headmin/controllers/table_actions_controller.js +16 -5
  155. data/src/js/headmin/controllers/table_controller.js +84 -1
  156. data/src/js/headmin/headmin.js +29 -56
  157. data/src/scss/headmin/filters.scss +0 -14
  158. data/src/scss/headmin/form.scss +43 -3
  159. data/src/scss/headmin/popup.scss +17 -0
  160. data/src/scss/headmin/table.scss +9 -6
  161. data/src/scss/headmin.scss +7 -4
  162. data/src/scss/vendor/redactorx/override.css +3 -0
  163. data/src/scss/vendor/redactorx/redactorx.css +1460 -0
  164. data/yarn.lock +105 -2210
  165. metadata +108 -62
  166. data/app/controllers/admin/users/confirmations_controller.rb +0 -31
  167. data/app/controllers/admin/users/omniauth_callbacks_controller.rb +0 -31
  168. data/app/controllers/admin/users/passwords_controller.rb +0 -35
  169. data/app/controllers/admin/users/registrations_controller.rb +0 -63
  170. data/app/controllers/admin/users/sessions_controller.rb +0 -28
  171. data/app/controllers/admin/users/unlocks_controller.rb +0 -31
  172. data/app/views/admin/users/confirmations/new.html.erb +0 -9
  173. data/app/views/admin/users/mailer/confirmation_instructions.html.erb +0 -5
  174. data/app/views/admin/users/mailer/email_changed.html.erb +0 -7
  175. data/app/views/admin/users/mailer/password_change.html.erb +0 -3
  176. data/app/views/admin/users/mailer/reset_password_instructions.html.erb +0 -8
  177. data/app/views/admin/users/mailer/unlock_instructions.html.erb +0 -7
  178. data/app/views/admin/users/passwords/edit.html.erb +0 -12
  179. data/app/views/admin/users/passwords/new.html.erb +0 -9
  180. data/app/views/admin/users/registrations/new.html.erb +0 -11
  181. data/app/views/admin/users/sessions/new.html.erb +0 -13
  182. data/app/views/admin/users/unlocks/new.html.erb +0 -10
  183. data/app/views/headmin/forms/_group.html.erb +0 -36
  184. data/app/views/headmin/forms/fields/_checkbox.html.erb +0 -23
  185. data/app/views/headmin/forms/fields/_ckeditor.html.erb +0 -28
  186. data/app/views/headmin/forms/fields/_currency.html.erb +0 -24
  187. data/app/views/headmin/forms/fields/_date.html.erb +0 -36
  188. data/app/views/headmin/forms/fields/_email.html.erb +0 -39
  189. data/app/views/headmin/forms/fields/_label.html.erb +0 -9
  190. data/app/views/headmin/forms/fields/_multiple_select.html.erb +0 -37
  191. data/app/views/headmin/forms/fields/_password.html.erb +0 -39
  192. data/app/views/headmin/forms/fields/_repeater.html.erb +0 -48
  193. data/app/views/headmin/forms/fields/_select.html.erb +0 -36
  194. data/app/views/headmin/forms/fields/_select_tags.html.erb +0 -32
  195. data/app/views/headmin/forms/fields/_textarea.html.erb +0 -29
  196. data/app/views/headmin/forms/fields/_url.html.erb +0 -38
  197. data/app/views/headmin/forms/fields/_validation.html.erb +0 -12
  198. data/app/views/headmin/forms/fields/repeater/_row.html.erb +0 -16
  199. data/app/views/headmin/layout/dropdown/_item.html.erb +0 -17
  200. data/app/views/headmin/layout/header/_account.html.erb +0 -25
  201. data/app/views/headmin/layout/header/_locale.html.erb +0 -19
  202. data/app/views/headmin/layout/sidebar/menu/_account.html.erb +0 -25
  203. data/app/views/headmin/layout/sidebar/menu/_item.html.erb +0 -16
  204. data/app/views/headmin/layout/sidebar/menu/_locale.html.erb +0 -18
  205. data/src/js/headmin/controllers/index_controller.js +0 -79
  206. data/src/js/headmin/controllers/repeater_row_controller.js +0 -54
  207. data/src/scss/vendor/choices/cross-inverse.svg +0 -6
  208. data/src/scss/vendor/choices/cross.svg +0 -6
  209. data/src/scss/vendor/choices/custom.scss +0 -28
  210. data/src/scss/vendor/choices/variables.scss +0 -16
@@ -1,5 +1,5 @@
1
1
  import {Controller} from "stimulus"
2
- import {Headmin} from "../headmin";
2
+ import Sortable from "sortablejs";
3
3
 
4
4
  export default class extends Controller {
5
5
  static get values() {
@@ -7,29 +7,135 @@ export default class extends Controller {
7
7
  id: String
8
8
  }
9
9
  }
10
+
10
11
  static get targets() {
11
- return ["links", "template"]
12
+ return ["repeater", "footer", "template", "row", "list", "empty", "addButton"]
13
+ }
14
+
15
+ connect() {
16
+ new Sortable(this.listTarget, {
17
+ animation: 150,
18
+ ghostClass: 'list-group-item-dark',
19
+ draggable: '.repeater-row',
20
+ handle: '.repeater-row-handle',
21
+ onEnd: () => {
22
+ this.resetIndices()
23
+ this.resetPositions()
24
+ }
25
+ })
26
+
27
+ this.toggleEmpty()
28
+ }
29
+
30
+ resetButtonIndices(event) {
31
+ const row = event.target.closest('.repeater-row')
32
+ const index = this.containsRow(row) ? row.dataset.rowIndex : ''
33
+ this.updatePopupButtonIndices(index)
34
+ }
35
+
36
+ containsRow(row) {
37
+ return this.rowTargets.includes(row)
12
38
  }
13
39
 
14
- add_association(event) {
40
+ updatePopupButtonIndices(index) {
41
+ console.log(index)
42
+ const popup = document.querySelector(`[data-popup-target="popup"][data-popup-id="repeater-buttons-${this.idValue}"]`)
43
+ const buttons = popup.querySelectorAll('a')
44
+ buttons.forEach((button) => {
45
+ button.dataset.rowIndex = index
46
+ })
47
+ }
48
+
49
+ addRow(event) {
15
50
  event.preventDefault()
51
+ const button = event.target
52
+ const templateName = button.dataset.templateName
53
+ let rowIndex = button.dataset.rowIndex
16
54
 
17
- let html = this.getTemplateHTML()
55
+ // Prepare html from template
56
+ let html = this.getTemplateHTML(templateName)
18
57
  html = this.replaceIdsWithTimestamps(html)
19
- this.addNewRow(html)
58
+
59
+ // Fallback to last row if no index is set
60
+ if (rowIndex) {
61
+ // Insert new row after defined row
62
+ const row = this.rowTargets[rowIndex]
63
+ row.insertAdjacentHTML('afterend', html)
64
+ } else {
65
+ // Insert before footer
66
+ this.footerTarget.insertAdjacentHTML('beforebegin', html)
67
+ }
68
+
69
+ // Dispatch an event
70
+ document.dispatchEvent(new CustomEvent('headmin:reinit', {bubbles: true}))
71
+
72
+ this.resetIndices()
73
+ this.resetPositions()
74
+ this.toggleEmpty()
75
+ }
76
+
77
+ removeRow(event) {
78
+ event.preventDefault()
79
+
80
+ const row = event.target.closest(".repeater-row")
81
+
82
+ if (row.dataset.newRecord === "true") {
83
+ // New records are simply removed from the page
84
+ row.remove()
85
+ } else {
86
+ // Existing records are hidden and flagged for deletion
87
+ row.querySelector("input[name*='_destroy']").value = 1
88
+ row.style.display = 'none'
89
+ }
90
+
91
+ this.resetIndices()
92
+ this.resetPositions()
93
+ this.toggleEmpty()
20
94
  }
21
95
 
22
- getTemplateHTML() {
23
- return this.templateTarget.innerHTML
96
+ getTemplateHTML(name) {
97
+ const template = this.templateTargets.filter((template) => {
98
+ return template.dataset.templateName === name
99
+ })[0]
100
+ return template.innerHTML
24
101
  }
25
102
 
26
103
  replaceIdsWithTimestamps(html) {
27
- const regex = new RegExp(this.idValue, "g");
104
+ const regex = new RegExp('template_id', "g");
28
105
  return html.replace(regex, new Date().getTime())
29
106
  }
30
107
 
31
- addNewRow(html) {
32
- this.linksTarget.insertAdjacentHTML('beforebegin', html)
33
- Headmin.initPlugins()
108
+ visibleRowsCount() {
109
+ return this.visibleRows().length
110
+ }
111
+
112
+ visibleRows() {
113
+ const rows = this.rowTargets
114
+ return rows.filter((row) => {
115
+ return row.querySelector("input[name*='_destroy']").value !== '1'
116
+ })
117
+ }
118
+
119
+ toggleEmpty() {
120
+ if (this.visibleRowsCount() > 0) {
121
+ this.emptyTarget.classList.add('invisible')
122
+ } else {
123
+ this.emptyTarget.classList.remove('invisible')
124
+ }
125
+ }
126
+
127
+ resetPositions() {
128
+ this.visibleRows().forEach((row, index) => {
129
+ const positionInput = row.querySelector("input[name*='position']")
130
+ if (positionInput) {
131
+ positionInput.value = index
132
+ }
133
+ })
134
+ }
135
+
136
+ resetIndices() {
137
+ this.visibleRows().forEach((row, index) => {
138
+ row.dataset.rowIndex = index
139
+ })
34
140
  }
35
141
  }
@@ -2,7 +2,7 @@ import {Controller} from "stimulus"
2
2
 
3
3
  export default class extends Controller {
4
4
  static get targets() {
5
- return ["form", "select", "method"]
5
+ return ["form", "select", "method", "button"]
6
6
  }
7
7
 
8
8
  connect() {
@@ -12,11 +12,22 @@ export default class extends Controller {
12
12
  update(event) {
13
13
  event.preventDefault()
14
14
  const option = this.selectTarget.options[this.selectTarget.selectedIndex]
15
- const action = this.selectTarget.value
16
- const method = option.dataset.method
17
15
 
18
16
  // Replace form action
19
- this.formTarget.action = action
20
- this.methodTarget.value = method
17
+ this.formTarget.action = this.selectTarget.value
18
+
19
+ // Replace form method
20
+ this.methodTarget.value = option.dataset.method
21
+
22
+ // Set confirm on form button
23
+ const confirm = option.dataset.confirm
24
+ if(confirm) {
25
+ this.buttonTarget.dataset.confirm = confirm
26
+ } else {
27
+ this.buttonTarget.removeAttribute('data-confirm')
28
+ }
29
+
30
+ // Enable button
31
+ this.buttonTarget.removeAttribute('disabled')
21
32
  }
22
33
  }
@@ -8,7 +8,7 @@ export default class extends Controller {
8
8
  }
9
9
 
10
10
  static get targets() {
11
- return ["table", "body"]
11
+ return ["table", "body", "actions", "idCheckbox", "idsCheckbox"]
12
12
  }
13
13
 
14
14
  connect() {
@@ -33,4 +33,87 @@ export default class extends Controller {
33
33
  })
34
34
  return data
35
35
  }
36
+
37
+ toggleIds(event) {
38
+ const checkbox = event.target
39
+ this.toggleIdsCheckboxes(checkbox.checked)
40
+ this.toggleIdCheckboxes(checkbox.checked)
41
+ this.syncFields()
42
+ this.toggleActions()
43
+ }
44
+
45
+ toggleId(event) {
46
+ this.toggleIdsCheckboxes(false)
47
+ this.syncFields()
48
+ this.toggleActions()
49
+ }
50
+
51
+ toggleActions() {
52
+ const idFields = this.getIdFields()
53
+ if(idFields.length > 0) {
54
+ this.actionsTarget.classList.remove('d-none')
55
+ } else {
56
+ this.actionsTarget.classList.add('d-none')
57
+ }
58
+ }
59
+
60
+ toggleIdsCheckboxes(checked) {
61
+ this.idsCheckboxTargets.forEach((checkbox) => {
62
+ checkbox.checked = checked
63
+ });
64
+ }
65
+
66
+ toggleIdCheckboxes(checked) {
67
+ this.idCheckboxTargets.forEach((checkbox) => {
68
+ checkbox.checked = checked
69
+ });
70
+ }
71
+
72
+ syncFields() {
73
+ this.removeIds()
74
+ if(this.idsCheckboxTarget.checked) {
75
+ this.addId('')
76
+ } else {
77
+ this.idCheckboxTargets.forEach((checkbox) => {
78
+ if(checkbox.checked) {
79
+ this.addId(checkbox.value)
80
+ }
81
+ });
82
+ }
83
+ }
84
+
85
+ addId(id) {
86
+ let field = this.getIdField(id)
87
+ if (!field) {
88
+ field = this.newIdField(id)
89
+ this.actionsTarget.querySelector('form').insertAdjacentHTML('afterbegin', field)
90
+ }
91
+ }
92
+
93
+ removeIds() {
94
+ const fields = this.getIdFields()
95
+ fields.forEach((field) => {
96
+ this.actionsTarget.querySelector('form').removeChild(field)
97
+ });
98
+ }
99
+
100
+ removeId(id) {
101
+ const field = this.getIdField(id)
102
+ if (field) {
103
+ this.actionsTarget.querySelector('form').removeChild(field)
104
+ }
105
+ }
106
+
107
+ newIdField(id) {
108
+ const template = this.actionsTarget.querySelector('[data-table-target="idFieldTemplate"]')
109
+ return template.innerHTML.replace(/ID/g, id)
110
+ }
111
+
112
+ getIdFields() {
113
+ return this.actionsTarget.querySelectorAll(`input[name="ids[]"]`);
114
+ }
115
+
116
+ getIdField(id) {
117
+ return this.actionsTarget.querySelector(`input[name="ids[]"][value="${id}"]`);
118
+ }
36
119
  }
@@ -1,6 +1,5 @@
1
1
  import 'ckeditor5-build-classic-simple-upload-adapter-image-resize';
2
- import Choices from "choices.js";
3
- import Sortable from 'sortablejs';
2
+ import TomSelect from "tom-select";
4
3
  import flatpickr from "flatpickr";
5
4
  import bootstrap from "bootstrap/dist/js/bootstrap.bundle";
6
5
  import Rails from "@rails/ujs";
@@ -20,14 +19,33 @@ export class Headmin {
20
19
 
21
20
  // Init Plugins
22
21
  this.initPlugins()
22
+
23
+ // Listen for a headmin:reinit event
24
+ document.addEventListener('headmin:reinit', (e) => {
25
+ this.initPlugins()
26
+ })
27
+
23
28
  }
24
29
 
25
30
  static initPlugins() {
26
- this.initChoices()
31
+ this.initTomSelects()
27
32
  this.initFlatpickrs()
28
33
  this.initToasts()
29
34
  this.initPopovers()
30
35
  this.initCKEditors()
36
+ this.initRedactorX()
37
+ }
38
+
39
+ static initRedactorX() {
40
+ document.querySelectorAll('.redactorx').forEach((element) => {
41
+ if (typeof RedactorX == 'undefined') {
42
+ console.error("RedactorX is a paid module and is not included in Headmin. Please purchase it and import it as a JS module")
43
+ return false;
44
+ }
45
+
46
+ const options = JSON.parse(element.getAttribute('data-redactor-options'))
47
+ RedactorX(element, options);
48
+ })
31
49
  }
32
50
 
33
51
  static initFlatpickrs() {
@@ -55,6 +73,10 @@ export class Headmin {
55
73
  }
56
74
 
57
75
  static initCKEditor(element) {
76
+
77
+ // Check if CKEditor is already initialized
78
+ if (element.nextElementSibling && element.nextElementSibling.classList.contains('ck-editor')) return
79
+
58
80
  const defaultToolbarItems = [
59
81
  'heading', '|', 'bold', 'italic', 'bulletedList', 'numberedList', '|', 'outdent',
60
82
  'indent', '|', 'link', 'imageUpload', 'blockQuote', 'insertTable', 'mediaEmbed', '|', 'undo', 'redo'
@@ -96,59 +118,10 @@ export class Headmin {
96
118
  })
97
119
  }
98
120
 
99
- static initChoices() {
100
- this.initChoicesSelectTags()
101
- this.initChoicesMultipleSelect()
102
- }
103
-
104
- static initChoicesSelectTags() {
105
- document.querySelectorAll('.select-tags').forEach((select) => {
106
-
107
- // Skip if already initialized
108
- if (select.dataset.choice === 'active') {
109
- return
110
- }
111
-
112
- // Create a new instance
113
- new Choices(select, {
114
- removeItemButton: true,
115
- loadingText: 'Loading...',
116
- noResultsText: 'No results found',
117
- noChoicesText: 'No choices to choose from',
118
- itemSelectText: 'Press to select',
119
- addItems: true,
120
- addItemText: (value) => {
121
- return `Press Enter to add <b>"${value}"</b>`;
122
- },
123
- maxItemText: (maxItemCount) => {
124
- return `Only ${maxItemCount} values can be added`;
125
- },
126
- });
127
- })
128
- }
129
-
130
- static initChoicesMultipleSelect() {
131
- document.querySelectorAll('.multiple-select').forEach((select) => {
132
-
133
- // Skip if already initialized
134
- if (select.dataset.choice === 'active') {
135
- return
136
- }
137
-
138
- // Create a new instance
139
- new Choices(select, {
140
- removeItemButton: true,
141
- loadingText: 'Loading...',
142
- noResultsText: 'No results found',
143
- noChoicesText: 'No choices to choose from',
144
- itemSelectText: 'Press to select',
145
- addItems: true,
146
- addItemText: (value) => {
147
- return `Press Enter to add <b>"${value}"</b>`;
148
- },
149
- maxItemText: (maxItemCount) => {
150
- return `Only ${maxItemCount} values can be added`;
151
- },
121
+ static initTomSelects() {
122
+ document.querySelectorAll('select[multiple]').forEach((select) => {
123
+ new TomSelect(select, {
124
+ create: select.dataset['tags'] === "true"
152
125
  });
153
126
  })
154
127
  }
@@ -1,14 +0,0 @@
1
- .h-filters, .h-filters-search {
2
- width: 100%;
3
- @include media-breakpoint-up(md) {
4
- width: auto;
5
- }
6
- }
7
-
8
- .h-filters .separator {
9
- display: block;
10
- width: 1px;
11
- height: 30px;
12
- background: $input-border-color;
13
- margin: 0 15px 0 0;
14
- }
@@ -1,3 +1,15 @@
1
+ input[type="search"] {
2
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%236c757d' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'/%3E%3C/svg%3E%0A");
3
+ background-repeat: no-repeat;
4
+ background-position: 10px center;
5
+ padding-left: 35px
6
+ }
7
+
8
+ .form-label[required="required"]:after {
9
+ content: '*';
10
+ margin-left: 1px;
11
+ }
12
+
1
13
  .forms-group {
2
14
  .card-footer {
3
15
  border-top: none;
@@ -19,21 +31,49 @@
19
31
  & > .repeater-row-add {
20
32
  visibility: visible;
21
33
  }
34
+
35
+ & > .repeater-row-handle {
36
+ visibility: visible;
37
+ }
22
38
  }
23
39
  }
24
40
 
25
41
  .repeater-row-remove {
26
42
  position: absolute;
27
- top: calc(50% - 18px);
43
+ top: calc(50% - 17px);
28
44
  right: -22px;
29
45
  z-index: 2;
30
46
  visibility: hidden;
47
+
48
+ i.bi {
49
+ background: white;
50
+ border-radius: 50%;
51
+ }
31
52
  }
32
53
 
33
54
  .repeater-row-add {
34
55
  position: absolute;
35
- top: calc(100% - 19px);
36
- right: calc(50% - 18px);
56
+ top: calc(100% - 18px);
57
+ right: calc(50% - 17px);
37
58
  z-index: 2;
38
59
  visibility: hidden;
60
+
61
+ i.bi {
62
+ background: white;
63
+ border-radius: 50%;
64
+ }
39
65
  }
66
+
67
+ .repeater-row-handle {
68
+ position: absolute;
69
+ top: 0;
70
+ left: 0;
71
+ height: 100%;
72
+ width: 18px;
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ z-index: 2;
77
+ visibility: hidden;
78
+ cursor: move;
79
+ }
@@ -0,0 +1,17 @@
1
+ .h-popup {
2
+ padding: 10px;
3
+ background: $white;
4
+ z-index: $zindex-popover;
5
+ width: $popover-max-width;
6
+ @include reset-text();
7
+ @include font-size($popover-font-size);
8
+ word-wrap: break-word;
9
+ background-color: $popover-bg;
10
+ background-clip: padding-box;
11
+ @include border-radius($popover-border-radius);
12
+ @include box-shadow($popover-box-shadow);
13
+
14
+ &.closed {
15
+ display: none;
16
+ }
17
+ }
@@ -21,12 +21,15 @@
21
21
  }
22
22
 
23
23
  .h-table-actions {
24
- width: 100%;
25
- @include media-breakpoint-up(md) {
26
- width: auto;
27
- }
24
+ position: absolute;
25
+ top: 0;
26
+ right: 0;
27
+ width: calc(100% - 54px);
28
+ background: $table-striped-bg;
29
+ padding: 0.3rem 0.3rem 0.26rem 0.3rem !important;
28
30
 
29
- select {
30
- min-width: 100%;
31
+ .form-select {
32
+ width: 300px;
33
+ max-width: 100%;
31
34
  }
32
35
  }
@@ -39,14 +39,16 @@
39
39
  @import "~bootstrap/scss/helpers.scss";
40
40
  @import "~bootstrap/scss/utilities/api.scss";
41
41
 
42
- // Choices
43
- @import "vendor/choices/variables"; // Choices overrides
44
- @import "~choices.js/src/styles/choices.scss";
45
- @import "vendor/choices/custom"; // Choices custom styling
42
+ // Tom select
43
+ @import "~tom-select/dist/scss/tom-select.bootstrap5";
46
44
 
47
45
  // Flatpickr
48
46
  @import "~flatpickr/dist/flatpickr";
49
47
 
48
+ // Redactor
49
+ @import "vendor/redactorx/redactorx";
50
+ @import "vendor/redactorx/override";
51
+
50
52
  // Headmin
51
53
  @import "headmin/filters";
52
54
  @import "headmin/form";
@@ -56,3 +58,4 @@
56
58
  @import "headmin/table";
57
59
  @import "headmin/utilities";
58
60
  @import "headmin/filter";
61
+ @import "headmin/popup";
@@ -0,0 +1,3 @@
1
+ .rx-container {
2
+ width: 100%;
3
+ }