headmin 0.2.8 → 0.3.4

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 (271) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +29 -3
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +39 -24
  6. data/README.md +65 -57
  7. data/app/assets/config/headmin_manifest.js +2 -0
  8. data/app/assets/images/document.docx +0 -0
  9. data/{src/scss/headmin/filters.scss → app/assets/images/document.pdf} +0 -0
  10. data/app/assets/images/image.jpg +0 -0
  11. data/app/assets/images/spreadsheet.xls +0 -0
  12. data/app/assets/images/video.mp4 +0 -0
  13. data/app/assets/javascripts/headmin/config/i18n.js +11 -0
  14. data/{src/js → app/assets/javascripts}/headmin/controllers/blocks_controller.js +0 -1
  15. data/{src/js → app/assets/javascripts}/headmin/controllers/date_range_controller.js +0 -2
  16. data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +33 -0
  17. data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +244 -0
  18. data/{src/js → app/assets/javascripts}/headmin/controllers/filter_controller.js +12 -6
  19. data/{src/js → app/assets/javascripts}/headmin/controllers/filters_controller.js +0 -0
  20. data/{src/js → app/assets/javascripts}/headmin/controllers/flatpickr_controller.js +2 -1
  21. data/app/assets/javascripts/headmin/controllers/hello_controller.js +7 -0
  22. data/app/assets/javascripts/headmin/controllers/notification_controller.js +8 -0
  23. data/{src/js → app/assets/javascripts}/headmin/controllers/popup_controller.js +0 -1
  24. data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +13 -0
  25. data/{src/js → app/assets/javascripts}/headmin/controllers/repeater_controller.js +0 -0
  26. data/app/assets/javascripts/headmin/controllers/select_controller.js +48 -0
  27. data/{src/js → app/assets/javascripts}/headmin/controllers/table_actions_controller.js +18 -6
  28. data/{src/js → app/assets/javascripts}/headmin/controllers/table_controller.js +28 -14
  29. data/app/assets/javascripts/headmin/index.js +37 -0
  30. data/app/assets/javascripts/headmin.js +15280 -0
  31. data/{src/scss → app/assets/stylesheets}/headmin/filter.scss +0 -0
  32. data/app/assets/stylesheets/headmin/filters.scss +0 -0
  33. data/{src/scss → app/assets/stylesheets}/headmin/form.scss +53 -4
  34. data/{src/scss → app/assets/stylesheets}/headmin/general.scss +0 -0
  35. data/{src/scss → app/assets/stylesheets}/headmin/layout/body.scss +0 -0
  36. data/{src/scss → app/assets/stylesheets}/headmin/layout/sidebar.scss +0 -0
  37. data/{src/scss → app/assets/stylesheets}/headmin/layout.scss +0 -0
  38. data/{src/scss → app/assets/stylesheets}/headmin/login.scss +0 -0
  39. data/{src/scss/vendor/bootstrap/variables.scss → app/assets/stylesheets/headmin/overrides/bootstrap.scss} +0 -0
  40. data/{src/scss/vendor/redactorx/override.css → app/assets/stylesheets/headmin/overrides/redactorx.css} +0 -0
  41. data/{src/scss → app/assets/stylesheets}/headmin/popup.scss +0 -0
  42. data/app/assets/stylesheets/headmin/syntax.scss +349 -0
  43. data/{src/scss → app/assets/stylesheets}/headmin/table.scss +0 -0
  44. data/app/assets/stylesheets/headmin/thumbnail.scss +20 -0
  45. data/app/assets/stylesheets/headmin/utilities.scss +68 -0
  46. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_accordion.scss +118 -0
  47. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_alert.scss +57 -0
  48. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_badge.scss +29 -0
  49. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_breadcrumb.scss +28 -0
  50. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_button-group.scss +139 -0
  51. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_buttons.scss +111 -0
  52. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_card.scss +216 -0
  53. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_carousel.scss +229 -0
  54. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_close.scss +40 -0
  55. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_containers.scss +41 -0
  56. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_dropdown.scss +240 -0
  57. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_forms.scss +9 -0
  58. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_functions.scss +302 -0
  59. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_grid.scss +33 -0
  60. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_helpers.scss +9 -0
  61. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_images.scss +42 -0
  62. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_list-group.scss +174 -0
  63. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_mixins.scss +43 -0
  64. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_modal.scss +209 -0
  65. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_nav.scss +139 -0
  66. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_navbar.scss +335 -0
  67. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_offcanvas.scss +83 -0
  68. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_pagination.scss +64 -0
  69. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_placeholders.scss +51 -0
  70. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_popover.scss +158 -0
  71. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_progress.scss +48 -0
  72. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_reboot.scss +625 -0
  73. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_root.scss +54 -0
  74. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_spinners.scss +69 -0
  75. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_tables.scss +155 -0
  76. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_toasts.scss +51 -0
  77. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_tooltip.scss +115 -0
  78. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_transitions.scss +27 -0
  79. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_type.scss +104 -0
  80. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_utilities.scss +630 -0
  81. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/_variables.scss +1641 -0
  82. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/bootstrap-grid.scss +67 -0
  83. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/bootstrap-reboot.scss +13 -0
  84. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/bootstrap-utilities.scss +18 -0
  85. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/bootstrap.scss +53 -0
  86. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_floating-labels.scss +63 -0
  87. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_form-check.scss +152 -0
  88. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_form-control.scss +219 -0
  89. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_form-range.scss +91 -0
  90. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_form-select.scss +72 -0
  91. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_form-text.scss +11 -0
  92. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_input-group.scss +121 -0
  93. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_labels.scss +36 -0
  94. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/forms/_validation.scss +12 -0
  95. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_clearfix.scss +3 -0
  96. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_colored-links.scss +12 -0
  97. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_position.scss +30 -0
  98. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_ratio.scss +26 -0
  99. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_stacks.scss +15 -0
  100. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_stretched-link.scss +15 -0
  101. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_text-truncation.scss +7 -0
  102. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_visually-hidden.scss +8 -0
  103. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/helpers/_vr.scss +8 -0
  104. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_alert.scss +11 -0
  105. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_backdrop.scss +14 -0
  106. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_border-radius.scss +78 -0
  107. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_box-shadow.scss +18 -0
  108. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_breakpoints.scss +127 -0
  109. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_buttons.scss +133 -0
  110. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_caret.scss +64 -0
  111. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_clearfix.scss +9 -0
  112. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_color-scheme.scss +7 -0
  113. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_container.scss +9 -0
  114. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_deprecate.scss +10 -0
  115. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_forms.scss +144 -0
  116. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_gradients.scss +47 -0
  117. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_grid.scss +151 -0
  118. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_image.scss +16 -0
  119. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_list-group.scss +24 -0
  120. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_lists.scss +7 -0
  121. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_pagination.scss +31 -0
  122. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_reset-text.scss +17 -0
  123. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_resize.scss +6 -0
  124. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_table-variants.scss +21 -0
  125. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_text-truncate.scss +8 -0
  126. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_transition.scss +26 -0
  127. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_utilities.scss +89 -0
  128. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/mixins/_visually-hidden.scss +29 -0
  129. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/utilities/_api.scss +47 -0
  130. data/app/assets/stylesheets/headmin/vendor/bootstrap/scss/vendor/_rfs.scss +354 -0
  131. data/app/assets/stylesheets/headmin/vendor/flatpickr.css +903 -0
  132. data/{src/scss/vendor/redactorx → app/assets/stylesheets/headmin/vendor}/redactorx.css +0 -0
  133. data/app/assets/stylesheets/headmin/vendor/tom-select-bootstrap.css +536 -0
  134. data/app/assets/stylesheets/headmin.css +13454 -0
  135. data/app/assets/stylesheets/headmin.scss +65 -0
  136. data/app/controllers/concerns/headmin/authentication.rb +1 -1
  137. data/app/controllers/concerns/headmin/searchable.rb +1 -1
  138. data/app/controllers/concerns/headmin/sortable.rb +7 -7
  139. data/app/helpers/headmin/admin_helper.rb +2 -1
  140. data/app/helpers/headmin/bootstrap_helper.rb +4 -4
  141. data/app/helpers/headmin/documentation_helper.rb +35 -0
  142. data/app/helpers/headmin/filter_helper.rb +1 -1
  143. data/app/helpers/headmin/form_helper.rb +7 -3
  144. data/app/helpers/headmin/notification_helper.rb +21 -21
  145. data/app/helpers/headmin/request_helper.rb +5 -10
  146. data/app/models/concerns/headmin/block.rb +1 -2
  147. data/app/models/concerns/headmin/blockable.rb +1 -1
  148. data/app/models/concerns/headmin/field.rb +1 -1
  149. data/app/models/concerns/headmin/fieldable.rb +8 -8
  150. data/app/models/headmin/documentation_renderer.rb +32 -0
  151. data/app/models/headmin/form/base.rb +78 -0
  152. data/app/models/headmin/form/text.rb +51 -0
  153. data/app/models/headmin/thumbnail.rb +61 -0
  154. data/app/services/block_service.rb +53 -53
  155. data/app/views/examples/admin.html.erb +1 -1
  156. data/app/views/headmin/_blocks.html.erb +2 -2
  157. data/app/views/headmin/_breadcrumbs.html.erb +1 -1
  158. data/app/views/headmin/_card.html.erb +8 -6
  159. data/app/views/headmin/_dropdown.html.erb +1 -1
  160. data/app/views/headmin/_filters.html.erb +20 -8
  161. data/app/views/headmin/_form.html.erb +14 -14
  162. data/app/views/headmin/_heading.html.erb +1 -1
  163. data/app/views/headmin/_notifications.html.erb +1 -1
  164. data/app/views/headmin/_pagination.html.erb +1 -1
  165. data/app/views/headmin/_popup.html.erb +10 -4
  166. data/app/views/headmin/_table.html.erb +2 -2
  167. data/app/views/headmin/_thumbnail.html.erb +47 -0
  168. data/app/views/headmin/dropdown/_devise.html.erb +2 -2
  169. data/app/views/headmin/dropdown/_item.html.erb +1 -1
  170. data/app/views/headmin/dropdown/_list.html.erb +3 -6
  171. data/app/views/headmin/filters/_date.html.erb +4 -10
  172. data/app/views/headmin/filters/_flatpickr.html.erb +5 -5
  173. data/app/views/headmin/filters/_search.html.erb +5 -5
  174. data/app/views/headmin/filters/_select.html.erb +6 -6
  175. data/app/views/headmin/filters/filter/_button.html.erb +7 -7
  176. data/app/views/headmin/filters/filter/_template.html.erb +1 -1
  177. data/app/views/headmin/forms/_actions.html.erb +1 -1
  178. data/app/views/headmin/forms/_base.html.erb +98 -45
  179. data/app/views/headmin/forms/_blocks.html.erb +4 -4
  180. data/app/views/headmin/forms/_checkbox.html.erb +4 -4
  181. data/app/views/headmin/forms/_date.html.erb +29 -45
  182. data/app/views/headmin/forms/_date_range.html.erb +24 -66
  183. data/app/views/headmin/forms/_email.html.erb +35 -26
  184. data/app/views/headmin/forms/_file.html.erb +186 -34
  185. data/app/views/headmin/forms/_flatpickr.html.erb +18 -39
  186. data/app/views/headmin/forms/_flatpickr_range.html.erb +34 -45
  187. data/app/views/headmin/forms/_hidden.html.erb +13 -12
  188. data/app/views/headmin/forms/_image.html.erb +11 -45
  189. data/app/views/headmin/forms/_label.html.erb +18 -14
  190. data/app/views/headmin/forms/_number.html.erb +40 -37
  191. data/app/views/headmin/forms/_password.html.erb +37 -58
  192. data/app/views/headmin/forms/_redactorx.html.erb +8 -7
  193. data/app/views/headmin/forms/_repeater.html.erb +7 -7
  194. data/app/views/headmin/forms/_select.html.erb +43 -48
  195. data/app/views/headmin/forms/_text.html.erb +95 -58
  196. data/app/views/headmin/forms/_textarea.html.erb +37 -26
  197. data/app/views/headmin/forms/_url.html.erb +35 -26
  198. data/app/views/headmin/forms/_validation.html.erb +3 -3
  199. data/app/views/headmin/forms/_video.html.erb +21 -0
  200. data/app/views/headmin/forms/actions/_destroy.html.erb +3 -3
  201. data/app/views/headmin/forms/fields/_base.html.erb +3 -3
  202. data/app/views/headmin/forms/fields/_file.html.erb +2 -2
  203. data/app/views/headmin/forms/fields/_group.html.erb +4 -4
  204. data/app/views/headmin/forms/fields/_image.html.erb +2 -2
  205. data/app/views/headmin/forms/fields/_list.html.erb +3 -3
  206. data/app/views/headmin/forms/fields/_text.html.erb +2 -2
  207. data/app/views/headmin/forms/repeater/_row.html.erb +1 -1
  208. data/app/views/headmin/heading/_title.html.erb +1 -1
  209. data/app/views/headmin/layout/_body.html.erb +1 -1
  210. data/app/views/headmin/layout/_content.html.erb +1 -1
  211. data/app/views/headmin/layout/_footer.html.erb +1 -1
  212. data/app/views/headmin/layout/_header.html.erb +1 -1
  213. data/app/views/headmin/layout/_main.html.erb +1 -1
  214. data/app/views/headmin/layout/_sidebar.html.erb +3 -3
  215. data/app/views/headmin/layout/sidebar/_bottom.html.erb +1 -1
  216. data/app/views/headmin/layout/sidebar/_nav.html.erb +1 -1
  217. data/app/views/headmin/nav/_dropdown.html.erb +34 -0
  218. data/app/views/headmin/nav/_item.html.erb +22 -13
  219. data/app/views/headmin/nav/item/_devise.html.erb +1 -1
  220. data/app/views/headmin/table/_actions.html.erb +2 -2
  221. data/app/views/headmin/table/_body.html.erb +1 -1
  222. data/app/views/headmin/table/_foot.html.erb +1 -1
  223. data/app/views/headmin/table/_footer.html.erb +1 -1
  224. data/app/views/headmin/table/_head.html.erb +1 -1
  225. data/app/views/headmin/table/_header.html.erb +1 -1
  226. data/app/views/headmin/table/actions/_action.html.erb +6 -5
  227. data/app/views/headmin/table/actions/_delete.html.erb +2 -2
  228. data/app/views/headmin/table/actions/_export.html.erb +1 -1
  229. data/app/views/headmin/table/body/_row.html.erb +2 -2
  230. data/app/views/headmin/views/devise/registrations/_edit.html.erb +2 -2
  231. data/config/importmap.rb +2 -0
  232. data/config/initializers/customize_input_error.rb +4 -4
  233. data/config/locales/en.yml +0 -3
  234. data/config/locales/headmin/forms/en.yml +5 -0
  235. data/config/locales/headmin/forms/nl.yml +5 -0
  236. data/config/locales/headmin/popup/en.yml +4 -0
  237. data/config/locales/headmin/popup/nl.yml +4 -0
  238. data/config/locales/headmin/thumbnail/en.yml +4 -0
  239. data/config/locales/headmin/thumbnail/nl.yml +4 -0
  240. data/config/locales/nl.yml +0 -3
  241. data/esbuild-css.js +25 -0
  242. data/esbuild-js.js +11 -0
  243. data/headmin.gemspec +4 -1
  244. data/lib/generators/headmin/blocks_generator.rb +8 -8
  245. data/lib/generators/headmin/devise_generator.rb +4 -4
  246. data/lib/generators/headmin/fields_generator.rb +9 -9
  247. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +1 -1
  248. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +1 -1
  249. data/lib/generators/templates/controllers/auth/passwords_controller.rb +1 -1
  250. data/lib/generators/templates/controllers/auth/registrations_controller.rb +1 -1
  251. data/lib/generators/templates/controllers/auth/sessions_controller.rb +1 -1
  252. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +1 -1
  253. data/lib/generators/templates/models/block.rb +1 -1
  254. data/lib/headmin/engine.rb +18 -3
  255. data/lib/headmin/version.rb +1 -1
  256. data/lib/headmin.rb +1 -1
  257. data/package.json +16 -34
  258. data/src/js/headmin.js +1 -1
  259. data/src/scss/headmin.scss +1 -61
  260. data/yarn-error.log +362 -0
  261. data/yarn.lock +234 -5275
  262. metadata +194 -38
  263. data/.nvmrc +0 -1
  264. data/.rubocop.yml +0 -13
  265. data/app/controllers/concerns/headmin/ckeditor.rb +0 -27
  266. data/app/views/headmin/forms/_ckeditor.html.erb +0 -42
  267. data/dist/css/headmin.css +0 -12357
  268. data/dist/js/headmin.js +0 -1115
  269. data/src/js/headmin/headmin.js +0 -158
  270. data/src/scss/headmin/utilities.scss +0 -19
  271. data/webpack.config.js +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97d58b9cf116a2017929bd0460593bedc48a2be8e8d53011b6db46fc3ee1df5f
4
- data.tar.gz: 379caa2715bb6c22efe961996420ce9fe0c8a6dc17ee88847d0d9661da768328
3
+ metadata.gz: ad3c5fca4f0e3c7c03fcf5a1b45887c7e247bb21b37b521a46afed5fe25fdfb6
4
+ data.tar.gz: 1c2a9d3d91fa0bdc3162e12ddffd44147943ed5035d40919bebf11d8f6e6447d
5
5
  SHA512:
6
- metadata.gz: 5d0452d83d31e5ac38ce1d75fc3d189d0400343d1f0ca82690e9d4c284a5acdae9dba36862b0a2aeba0784ca1c6cb1241970752de836b03cf62a08cbedf32b23
7
- data.tar.gz: 01e9857909d763690fbf63ab0efe901f49894594060e3945b777b025414a5c294c2a5af475f47d1cc21ac9757cd5341610ee555a197eb30340e949219ac1accf
6
+ metadata.gz: ee176196b6f86c2253b5564b9e49b16f58c2b24789856a126a3c98d76a32759d17fa9c0c985206cec590a967de9da26657d04fd3ecba176dbaef20c613558ff3
7
+ data.tar.gz: ebd63d265dcbfba01c31a84304634dacb4e8a5642577cffab64eddbdcc91a7c2fd1f51d162b67b7bc3ec1fee2ef0695f3c509510f98e6ba7c322c2adaea75c37
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-3.0.0
1
+ ruby-3.1.0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
- ## [Unreleased]
1
+ # Headmin Changelog
2
2
 
3
- ## [0.0.1] - 2021-03-14
3
+ ## 0.3
4
4
 
5
- - Initial release
5
+ - Support for import maps added
6
+ - Headmin is now works with Rails 7
7
+ - All JS is moved to Stimulus controllers thus deprecating the need for a custom initialization process
8
+ - Makeover of `headmin/forms/file`
9
+ - added attribute `dropzone` to enable drag&drop
10
+ - added attribute `preview` to enable previews
11
+ - Image previews for `headmin/forms/image` are not enabled by default anymore. To enable you can add `preview: true`. To
12
+ render previews for attachments add them as nested_attributes to your model
13
+
14
+ ```rb
15
+ has_one_attached :image
16
+ accepts_nested_attributes_for :image_attachment
17
+ ```
18
+
19
+ - **BREAK**: CKEditor has been removed in favor of RedactorX.
20
+ Download a purchased copy of RedactorX and add it to your `<head>` like this:
21
+
22
+ ```html
23
+
24
+ <head>
25
+ <script src="<%= asset_path('redactorx') %>" type="module"></script>
26
+ </head>
27
+ ```
28
+
29
+ ## 0.2.8
30
+
31
+ - ...
data/Gemfile CHANGED
@@ -8,4 +8,4 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
- gem "rubocop", "~> 1.7"
11
+ gem "standard", "~> 1.7"
data/Gemfile.lock CHANGED
@@ -1,56 +1,71 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- headmin (0.2.7)
5
- closure_tree
4
+ headmin (0.3.3)
5
+ closure_tree (~> 7.4)
6
+ inline_svg (~> 1.7)
7
+ redcarpet (~> 3.5)
8
+ rouge (~> 3.27)
6
9
 
7
10
  GEM
8
11
  remote: https://rubygems.org/
9
12
  specs:
10
- activemodel (6.1.4.1)
11
- activesupport (= 6.1.4.1)
12
- activerecord (6.1.4.1)
13
- activemodel (= 6.1.4.1)
14
- activesupport (= 6.1.4.1)
15
- activesupport (6.1.4.1)
13
+ activemodel (7.0.1)
14
+ activesupport (= 7.0.1)
15
+ activerecord (7.0.1)
16
+ activemodel (= 7.0.1)
17
+ activesupport (= 7.0.1)
18
+ activesupport (7.0.1)
16
19
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
20
  i18n (>= 1.6, < 2)
18
21
  minitest (>= 5.1)
19
22
  tzinfo (~> 2.0)
20
- zeitwerk (~> 2.3)
21
23
  ast (2.4.2)
22
24
  closure_tree (7.4.0)
23
25
  activerecord (>= 4.2.10)
24
26
  with_advisory_lock (>= 4.0.0)
25
27
  concurrent-ruby (1.1.9)
26
- i18n (1.8.11)
28
+ i18n (1.9.1)
27
29
  concurrent-ruby (~> 1.0)
30
+ inline_svg (1.8.0)
31
+ activesupport (>= 3.0)
32
+ nokogiri (>= 1.6)
28
33
  minitest (5.14.4)
29
- parallel (1.20.1)
30
- parser (3.0.0.0)
34
+ nokogiri (1.13.1-x86_64-darwin)
35
+ racc (~> 1.4)
36
+ parallel (1.21.0)
37
+ parser (3.1.0.0)
31
38
  ast (~> 2.4.1)
32
- rainbow (3.0.0)
39
+ racc (1.6.0)
40
+ rainbow (3.1.1)
33
41
  rake (13.0.3)
34
- regexp_parser (2.1.1)
35
- rexml (3.2.4)
36
- rubocop (1.11.0)
42
+ redcarpet (3.5.1)
43
+ regexp_parser (2.2.0)
44
+ rexml (3.2.5)
45
+ rouge (3.27.0)
46
+ rubocop (1.25.0)
37
47
  parallel (~> 1.10)
38
- parser (>= 3.0.0.0)
48
+ parser (>= 3.1.0.0)
39
49
  rainbow (>= 2.2.2, < 4.0)
40
50
  regexp_parser (>= 1.8, < 3.0)
41
51
  rexml
42
- rubocop-ast (>= 1.2.0, < 2.0)
52
+ rubocop-ast (>= 1.15.1, < 2.0)
43
53
  ruby-progressbar (~> 1.7)
44
54
  unicode-display_width (>= 1.4.0, < 3.0)
45
- rubocop-ast (1.4.1)
46
- parser (>= 2.7.1.5)
55
+ rubocop-ast (1.15.1)
56
+ parser (>= 3.0.1.1)
57
+ rubocop-performance (1.13.2)
58
+ rubocop (>= 1.7.0, < 2.0)
59
+ rubocop-ast (>= 0.4.0)
47
60
  ruby-progressbar (1.11.0)
61
+ standard (1.7.0)
62
+ rubocop (= 1.25.0)
63
+ rubocop-performance (= 1.13.2)
48
64
  tzinfo (2.0.4)
49
65
  concurrent-ruby (~> 1.0)
50
- unicode-display_width (2.0.0)
66
+ unicode-display_width (2.1.0)
51
67
  with_advisory_lock (4.6.0)
52
68
  activerecord (>= 4.2)
53
- zeitwerk (2.5.1)
54
69
 
55
70
  PLATFORMS
56
71
  x86_64-darwin-19
@@ -59,7 +74,7 @@ DEPENDENCIES
59
74
  headmin!
60
75
  minitest (~> 5.0)
61
76
  rake (~> 13.0)
62
- rubocop (~> 1.7)
77
+ standard (~> 1.7)
63
78
 
64
79
  BUNDLED WITH
65
- 2.2.14
80
+ 2.3.3
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Headmin
2
+
2
3
  A complete library of commonly used components to build an admin interface in your Ruby on Rails project.
3
4
 
4
5
  [![Gem Version](https://badge.fury.io/rb/headmin.svg)](https://rubygems.org/gems/headmin)
@@ -6,77 +7,98 @@ A complete library of commonly used components to build an admin interface in yo
6
7
 
7
8
  ## Installation
8
9
 
9
- Add this line to your application's Gemfile:
10
+ To install Headmin into your current Rails application use bundler:
10
11
 
11
- ```ruby
12
- gem 'headmin'
12
+ ```shell
13
+ $ bundle add 'headmin'
13
14
  ```
14
15
 
15
- And then execute:
16
+ ## Usage
17
+ All assets are available via the asset pipeline and can be called as if it was available in your application.
16
18
 
17
- ```shell
18
- $ bundle install
19
+ ### Stylesheets
20
+ Import all SCSS stylesheets like this:
21
+
22
+ ```scss
23
+ @import "headmin";
24
+ ```
25
+
26
+ - Asset Pipeline: `Sprockets` & `sassc-rails` will pickup the correct file automatically
27
+ - Node: Use a build tool like `ESBuild`, `Webpack` or `Rollup` to find the right file via Headmins' package.json
28
+
29
+ ### Javascript
30
+ Import the `Headmin` class into your script and initialize it. This will append its Stimulus controllers to
31
+ the `window.Stimulus object` if it's available.
32
+
33
+ ```js
34
+ import {Headmin} from 'headmin'
35
+ Headmin.start()
19
36
  ```
20
37
 
21
- Add headmin to list of node modules
38
+ ### Node or not to Node
39
+ With the introduction of importmap in Rails 7, you're no longer required to use node for your frontend assets.
40
+ By default all assets are available via the asset pipeline and added to the default importmap.rb.
41
+
42
+ If you want to use node because you're tied to a specific build tool, you can add Headmin as a dependency to your package.json.
22
43
 
23
44
  ```shell
24
45
  $ yarn add headmin
25
46
  ```
26
- ## Usage
27
- Add the Headmin helpers to the Admin helper file
47
+
48
+ ## Helpers
49
+
50
+ Add the Headmin helpers to your helper file. We recommend using namespaces.
51
+
28
52
  ```ruby
53
+ # In a, preferably namespaced, view helper
29
54
  module AdminHelper
30
55
  include Headmin::AdminHelper
31
56
  end
32
57
  ```
33
58
 
34
- Import the Headmin class into your script.
35
- ```js
36
- import {Headmin} from 'headmin'
37
-
38
- document.addEventListener("DOMContentLoaded", function () {
39
- Headmin.start()
40
- })
41
- ```
42
-
43
- Finally import Headmin in your stylesheet.
44
- ```scss
45
- @import '~headmin/src/scss/headmin.scss';
46
- ```
47
-
48
- ### Integrations
49
- - [Blocks](docs/blocks.md)
50
- - [Fields](docs/fields.md)
51
- - [Blocks + Fields = Magic](docs/blocks-and-fields.md)
52
- - [Devise](docs/devise.md)
53
-
54
59
  ## Development
60
+
55
61
  For development purposes it's helpful to have both the test project and Headmin located in the same directory.
56
62
 
57
63
  In Gemfile
64
+
58
65
  ```ruby
59
66
  gem "headmin", path: "../headmin"
60
67
  ```
61
68
 
62
69
  In package.json
70
+
63
71
  ```json
64
72
  {
65
73
  "dependencies": {
66
- "bar": "file:../headmin"
74
+ "headmin": "link:../headmin"
67
75
  }
68
76
  }
69
77
  ```
70
78
 
79
+ To see frontend changes update live in development run
80
+ ```shell
81
+ # Watches changes and builds them on-the-fly
82
+ yarn dev
83
+ ```
84
+
85
+ ### Javascript
86
+
87
+ When adding new dependencies, make sure you add them to the `package.json` file as well as the `importmap.rb` file.
88
+
71
89
  ## Testing
72
- If you want to test a specific feature in a staging environment without releasing the gem, you can refer to the remote repo in your Gemfile and package.json.
90
+
91
+ If you want to test a specific feature in a staging environment without releasing the gem, you can refer to the remote
92
+ repo in your Gemfile and package.json.
73
93
 
74
94
  In Gemfile
95
+
75
96
  ```ruby
76
97
  gem 'headmin', git: 'git@github.com:insiting/headmin.git', branch: 'feature/test'
77
98
  ```
78
99
 
79
100
  In package.json
101
+
80
102
  ```json
81
103
  {
82
104
  "dependencies": {
@@ -87,50 +109,35 @@ In package.json
87
109
  ```
88
110
 
89
111
  ## Releasing
90
- After integration a new feature of fixing a bug, first commit and push your changes.
91
112
 
92
- Build the assets for production
93
- ```shell
94
- $ nvm use
95
- $ yarn build
96
- ```
113
+ After integration a new feature of fixing a bug, first commit and push your changes.
97
114
 
98
- Update the version number of the gem
115
+ Update the gem
99
116
 
100
117
  ```shell
101
118
  # First bundle if new runtime dependencies were added
102
119
  $ bundle
103
- $ git push
104
120
 
105
- # Update the version number and tag the release
121
+ # Update the version number, push commits and tag the release
106
122
  $ gem bump -v {patch,minor,major,...} --push --tag
107
123
 
108
124
  # Release to Rubygems
109
125
  $ gem release
110
126
  ```
111
127
 
112
- Update the node module
113
- ```
114
- # Manually update the version number in package.json
115
- $ npm publish
116
- ```
128
+ Update the node package
117
129
 
118
- ## Deployment
119
- Update the Headmin gem to the latest version
120
130
  ```shell
121
- $ bundle update headmin
122
- ```
123
-
124
- Update the Headmin node module ot the latest version
125
- ```shell
126
- $ yarn upgrade headmin
131
+ # Manually update the version number in package.json
132
+ $ yarn build
133
+ $ npm publish
127
134
  ```
128
135
 
129
- Deploy your app as usual
130
-
131
136
  ## Contributing
132
137
 
133
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/headmin. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/headmin/blob/master/CODE_OF_CONDUCT.md).
138
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/headmin. This project is intended
139
+ to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
140
+ the [code of conduct](https://github.com/[USERNAME]/headmin/blob/master/CODE_OF_CONDUCT.md).
134
141
 
135
142
  ## License
136
143
 
@@ -138,4 +145,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
138
145
 
139
146
  ## Code of Conduct
140
147
 
141
- Everyone interacting in the Headmin project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/headmin/blob/master/CODE_OF_CONDUCT.md).
148
+ Everyone interacting in the Headmin project's codebases, issue trackers, chat rooms and mailing lists is expected to
149
+ follow the [code of conduct](https://github.com/[USERNAME]/headmin/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,2 @@
1
+ //= link_tree ../images
2
+ //= link_tree ../javascripts
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ export default class {
2
+ static get locale() {
3
+ if (window.I18n === undefined) {
4
+ const locale = document.querySelector('html').getAttribute('lang')
5
+ window.I18n = {
6
+ locale: locale || 'en'
7
+ }
8
+ }
9
+ return window.I18n.locale
10
+ }
11
+ }
@@ -1,6 +1,5 @@
1
1
  import {Controller} from "@hotwired/stimulus"
2
2
  import Sortable from "sortablejs";
3
- import { createPopper } from '@popperjs/core';
4
3
 
5
4
  export default class extends Controller {
6
5
  static get targets() {
@@ -1,6 +1,4 @@
1
1
  import {Controller} from "@hotwired/stimulus"
2
- import Sortable from "sortablejs";
3
- import { createPopper } from '@popperjs/core';
4
2
 
5
3
  export default class extends Controller {
6
4
  static get targets() {
@@ -0,0 +1,33 @@
1
+ import {Controller} from "@hotwired/stimulus"
2
+
3
+ // References:
4
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API
5
+
6
+ export default class extends Controller {
7
+ static get targets() {
8
+ return ["input"]
9
+ }
10
+
11
+ connect() {
12
+ this.element.classList.add('h-dropzone')
13
+
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
+ }
33
+ }
@@ -0,0 +1,244 @@
1
+ import {Controller} from "@hotwired/stimulus"
2
+
3
+ // References:
4
+ // https://developer.mozilla.org/en-US/docs/Web/API/FileReader
5
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file
6
+
7
+ export default class extends Controller {
8
+ static get targets() {
9
+ return ["thumbnails", "template", "input", "placeholder", "thumbnail", "thumbnailDestroy"]
10
+ }
11
+
12
+ connect() {
13
+ this.thumbnailWidth = this.firstThumbnailWidth()
14
+ this.thumbnailHeight = this.firstThumbnailHeight()
15
+ }
16
+
17
+ preview() {
18
+ this.removeThumbnails()
19
+ this.addThumbnails()
20
+ this.togglePlaceholder()
21
+ }
22
+
23
+ togglePlaceholder() {
24
+ if (this.hasFilesSelected()) {
25
+ this.hidePlaceholder()
26
+ } else {
27
+ this.showPlaceholder()
28
+ }
29
+ }
30
+
31
+ hasFilesSelected() {
32
+ return this.hasInputFiles() || this.hasVisibleAttachments()
33
+ }
34
+
35
+ hasVisibleAttachments() {
36
+ return this.visibleAttachments().length > 0
37
+ }
38
+
39
+ hasAttachments() {
40
+ return this.attachments().length > 0
41
+ }
42
+
43
+ hasInputFiles() {
44
+ return this.inputFiles().length > 0
45
+ }
46
+
47
+ attachments() {
48
+ return this.thumbnailTargets.filter((thumbnail) => {
49
+ return this.isAttachment(thumbnail)
50
+ })
51
+ }
52
+
53
+ visibleAttachments() {
54
+ return this.attachments().filter((thumbnail) => {
55
+ return !thumbnail.classList.contains('d-none')
56
+ })
57
+ }
58
+
59
+ inputFiles() {
60
+ return Array.from(this.inputTarget.files)
61
+ }
62
+
63
+ writeInputFiles(files) {
64
+ const dataTransfer = new DataTransfer();
65
+ files.forEach((file) => {
66
+ dataTransfer.items.add(file);
67
+ })
68
+ this.inputTarget.files = dataTransfer.files;
69
+ }
70
+
71
+ remove(event) {
72
+ const thumbnail = event.target.closest('[data-file-preview-target="thumbnail"]')
73
+ this.removeThumbnail(thumbnail, event.params.name)
74
+ this.togglePlaceholder()
75
+ }
76
+
77
+ isAttachment(thumbnail) {
78
+ return thumbnail.querySelector('[data-file-preview-target="thumbnailDestroy"]')
79
+ }
80
+
81
+ removeInputFile(thumbnail, fileName) {
82
+ let files = this.inputFiles()
83
+ files = files.filter((file) => {
84
+ return file.name !== fileName
85
+ })
86
+ thumbnail.remove()
87
+ this.writeInputFiles(files)
88
+ }
89
+
90
+ removeAttachment(thumbnail) {
91
+ const destroyInput = thumbnail.querySelector('[data-file-preview-target="thumbnailDestroy"]')
92
+ destroyInput.value = '1';
93
+ thumbnail.classList.add('d-none')
94
+ }
95
+
96
+ showPlaceholder() {
97
+ this.placeholderTarget.classList.remove('d-none')
98
+ }
99
+
100
+ hidePlaceholder() {
101
+ this.placeholderTarget.classList.add('d-none')
102
+ }
103
+
104
+ removeThumbnails() {
105
+ this.thumbnailTargets.forEach((thumbnail) => {
106
+ this.removeThumbnail(thumbnail)
107
+ })
108
+ }
109
+
110
+ removeThumbnail(thumbnail, filename) {
111
+ if (this.isAttachment(thumbnail)) {
112
+ this.removeAttachment(thumbnail)
113
+ } else {
114
+ this.removeInputFile(thumbnail, filename)
115
+ }
116
+ }
117
+
118
+ addThumbnails() {
119
+ const files = this.inputFiles()
120
+ files.forEach((file) => {
121
+ let thumbnail = this.generateDummyThumbnail()
122
+ this.appendThumbnail(thumbnail)
123
+ this.updateThumbnail(this.lastThumbnail(), file)
124
+ })
125
+ }
126
+
127
+ generateDummyThumbnail() {
128
+ return this.templateTarget.content.cloneNode(true)
129
+ }
130
+
131
+ appendThumbnail(thumbnail) {
132
+ return this.thumbnailsTarget.appendChild(thumbnail)
133
+ }
134
+
135
+ updateThumbnail(thumbnail, file) {
136
+ this.updateThumbnailRemoveButton(thumbnail, file.name)
137
+
138
+ const title = this.titleForFile(file)
139
+ this.updateThumbnailTitle(thumbnail, title)
140
+
141
+ const icon = this.iconForMimeType(file.type)
142
+ this.updateThumbnailIcon(thumbnail, icon)
143
+
144
+ if (this.isImage(file)) {
145
+ this.updateThumbnailImage(thumbnail, file)
146
+ }
147
+
148
+ }
149
+
150
+ updateThumbnailImage(thumbnail, file) {
151
+ this.fileToBase64(file).then(base64 => {
152
+ this.updateThumbnailBackground(thumbnail, base64)
153
+ this.removeThumbnailIcon(thumbnail)
154
+ })
155
+ }
156
+
157
+ titleForFile(file) {
158
+ const byteSizeString = this.bytesToString(file.size)
159
+ return `${file.name} (${byteSizeString})`
160
+ }
161
+
162
+ bytesToString(bytes) {
163
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
164
+ return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
165
+ }
166
+
167
+ updateThumbnailRemoveButton(thumbnail, fileName) {
168
+ const removeButton = thumbnail.querySelector('.h-form-file-thumbnail-remove')
169
+ if(removeButton) {
170
+ removeButton.dataset.filePreviewNameParam = fileName
171
+ }
172
+ }
173
+
174
+ updateThumbnailTitle(thumbnail, title) {
175
+ thumbnail.title = title
176
+ }
177
+
178
+ updateThumbnailBackground(thumbnail, url) {
179
+ let thumbnailBackground = thumbnail.querySelector('.h-thumbnail-bg')
180
+ thumbnailBackground.style.backgroundImage = `url('${url}')`
181
+ }
182
+
183
+ removeThumbnailIcon(thumbnail) {
184
+ thumbnail.querySelector('.h-thumbnail-bg').innerHTML = ''
185
+ }
186
+
187
+ updateThumbnailIcon(thumbnail, icon) {
188
+ thumbnail.querySelector('.h-thumbnail-bg').innerHTML = icon
189
+ }
190
+
191
+ iconForMimeType(mimeType) {
192
+ const typeMap = {
193
+ image: ['image/bmp', 'image/gif', 'image/vnd.microsoft.icon', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/tiff', 'image/webp'],
194
+ play: ['video/mp4', 'video/mpeg', 'video/ogg', 'video/mp2t', 'video/webm', 'video/3gpp', 'video/3gpp2'],
195
+ music: ['audio/aac', 'audio/midi', 'audio/x-midi', 'audio/mpeg', 'audio/ogg', 'audio/opus', 'audio/wav', 'audio/webm', 'audio/3gpp', 'audio/3gpp2'],
196
+ word: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
197
+ ppt: ['application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
198
+ excel: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
199
+ slides: ['application/vnd.oasis.opendocument.presentation'],
200
+ spreadsheet: ['application/vnd.oasis.opendocument.spreadsheet'],
201
+ richtext: ['application/vnd.oasis.opendocument.text'],
202
+ zip: ['application/zip application/x-7z-compressed', 'application/x-bzip application/x-bzip2 application/gzip application/vnd.rar'],
203
+ pdf: ['application/pdf']
204
+ }
205
+
206
+ const icon_name = Object.keys(typeMap).find(key => typeMap[key].includes(mimeType));
207
+ const full_icon_name = ['bi', 'file', 'earmark', icon_name].filter(e => typeof e === 'string' && e !== '').join('-')
208
+
209
+ return `<i class="bi ${full_icon_name} h-thumbnail-icon"></i>`
210
+ }
211
+
212
+ isImage(file) {
213
+ return file.type.match(/^image/) !== null;
214
+ }
215
+
216
+ fileToBase64(file) {
217
+ return new Promise((resolve, reject) => {
218
+ const reader = new FileReader();
219
+ reader.readAsDataURL(file);
220
+ reader.onload = () => resolve(reader.result);
221
+ reader.onerror = error => reject(error);
222
+ });
223
+ }
224
+
225
+ thumbnails() {
226
+ return this.thumbnailsTarget.querySelectorAll('.img-thumbnail')
227
+ }
228
+
229
+ firstThumbnail() {
230
+ return this.thumbnailsTarget.firstElementChild
231
+ }
232
+
233
+ lastThumbnail() {
234
+ return this.thumbnailsTarget.lastElementChild
235
+ }
236
+
237
+ firstThumbnailWidth() {
238
+ return this.firstThumbnail().style.width;
239
+ }
240
+
241
+ firstThumbnailHeight() {
242
+ return this.firstThumbnail().style.height;
243
+ }
244
+ }