alchemy_cms 7.4.6 → 8.0.0.a

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

Files changed (349) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/Gemfile +13 -6
  4. data/README.md +13 -5
  5. data/alchemy_cms.gemspec +14 -5
  6. data/app/assets/builds/alchemy/admin/page-select.css +1 -1
  7. data/app/assets/builds/alchemy/admin/print.css +1 -1
  8. data/app/assets/builds/alchemy/admin.css +2 -2
  9. data/app/assets/builds/alchemy/custom-properties.css +1 -1
  10. data/app/assets/builds/alchemy/welcome.css +1 -1
  11. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
  12. data/app/assets/builds/tinymce/skins/ui/alchemy/content.min.css +1 -0
  13. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
  14. data/app/assets/config/alchemy_manifest.js +0 -2
  15. data/app/assets/images/alchemy/icons-sprite.svg +1 -0
  16. data/app/components/alchemy/admin/resource/applied_filter.rb +29 -0
  17. data/app/components/alchemy/admin/resource/checkbox_filter.rb +36 -0
  18. data/app/components/alchemy/admin/resource/datepicker_filter.rb +42 -0
  19. data/app/components/alchemy/admin/resource/select_filter.rb +43 -0
  20. data/app/components/alchemy/admin/toolbar_button.rb +5 -2
  21. data/app/components/alchemy/ingredients/number_view.rb +18 -0
  22. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -15
  23. data/app/controllers/alchemy/admin/clipboard_controller.rb +2 -6
  24. data/app/controllers/alchemy/admin/elements_controller.rb +1 -1
  25. data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
  26. data/app/controllers/alchemy/admin/pages_controller.rb +15 -15
  27. data/app/controllers/alchemy/admin/pictures_controller.rb +9 -5
  28. data/app/controllers/alchemy/admin/resources_controller.rb +16 -106
  29. data/app/controllers/alchemy/attachments_controller.rb +43 -14
  30. data/app/controllers/alchemy/messages_controller.rb +1 -1
  31. data/app/controllers/alchemy/pages_controller.rb +7 -2
  32. data/app/controllers/concerns/alchemy/admin/resource_filter.rb +92 -0
  33. data/app/decorators/alchemy/element_editor.rb +5 -48
  34. data/app/decorators/alchemy/ingredient_editor.rb +3 -53
  35. data/app/helpers/alchemy/admin/base_helper.rb +14 -84
  36. data/app/helpers/alchemy/admin/elements_helper.rb +4 -4
  37. data/app/helpers/alchemy/admin/pages_helper.rb +1 -1
  38. data/app/helpers/alchemy/base_helper.rb +0 -30
  39. data/app/helpers/alchemy/elements_block_helper.rb +0 -14
  40. data/app/helpers/alchemy/pages_helper.rb +1 -1
  41. data/{lib → app/helpers}/alchemy/resources_helper.rb +5 -45
  42. data/app/javascript/alchemy_admin/components/action.js +2 -0
  43. data/app/javascript/alchemy_admin/components/alchemy_html_element.js +3 -3
  44. data/app/javascript/alchemy_admin/components/datepicker.js +10 -2
  45. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +7 -7
  46. data/app/javascript/alchemy_admin/components/element_editor.js +1 -1
  47. data/app/javascript/alchemy_admin/components/index.js +1 -0
  48. data/app/javascript/alchemy_admin/components/remote_select.js +4 -1
  49. data/app/javascript/alchemy_admin/components/tags_autocomplete.js +5 -1
  50. data/app/javascript/alchemy_admin/components/tinymce.js +4 -2
  51. data/app/javascript/alchemy_admin/components/update_check.js +42 -0
  52. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +15 -8
  53. data/app/javascript/alchemy_admin/components/uploader/progress.js +12 -6
  54. data/app/javascript/alchemy_admin/components/uploader.js +4 -2
  55. data/app/javascript/alchemy_admin/confirm_dialog.js +27 -57
  56. data/app/javascript/alchemy_admin/dirty.js +3 -2
  57. data/app/javascript/alchemy_admin/i18n.js +15 -16
  58. data/app/javascript/alchemy_admin/initializer.js +1 -49
  59. data/app/javascript/alchemy_admin/utils/ajax.js +51 -44
  60. data/app/javascript/alchemy_admin.js +3 -8
  61. data/app/models/alchemy/admin/filters/base.rb +38 -0
  62. data/app/models/alchemy/admin/filters/checkbox.rb +24 -0
  63. data/app/models/alchemy/admin/filters/datepicker.rb +53 -0
  64. data/app/models/alchemy/admin/filters/select.rb +70 -0
  65. data/app/models/alchemy/admin/resource_name.rb +27 -0
  66. data/app/models/alchemy/attachment.rb +51 -34
  67. data/app/models/alchemy/base_record.rb +2 -0
  68. data/app/models/alchemy/element/definitions.rb +1 -1
  69. data/app/models/alchemy/element/element_ingredients.rb +6 -6
  70. data/app/models/alchemy/element/presenters.rb +3 -12
  71. data/app/models/alchemy/element.rb +9 -27
  72. data/app/models/alchemy/element_definition.rb +160 -0
  73. data/app/models/alchemy/ingredient.rb +10 -43
  74. data/app/models/alchemy/ingredient_definition.rb +134 -0
  75. data/app/models/alchemy/ingredient_validator.rb +7 -3
  76. data/app/models/alchemy/ingredients/number.rb +19 -0
  77. data/app/models/alchemy/language.rb +0 -14
  78. data/app/models/alchemy/message.rb +3 -7
  79. data/app/models/alchemy/node.rb +1 -1
  80. data/app/models/alchemy/page/{page_layouts.rb → definitions.rb} +12 -19
  81. data/app/models/alchemy/page/fixed_attributes.rb +1 -1
  82. data/app/models/alchemy/page/page_elements.rb +13 -14
  83. data/app/models/alchemy/page/page_natures.rb +7 -7
  84. data/app/models/alchemy/page/page_scopes.rb +1 -1
  85. data/app/models/alchemy/page.rb +11 -33
  86. data/app/models/alchemy/page_definition.rb +115 -0
  87. data/app/models/alchemy/picture.rb +69 -79
  88. data/app/models/alchemy/picture_variant.rb +115 -5
  89. data/{lib → app/models}/alchemy/resource.rb +4 -18
  90. data/{lib → app/models}/alchemy/searchable_resource.rb +15 -0
  91. data/app/models/alchemy/site/layout.rb +5 -5
  92. data/app/models/alchemy/site.rb +0 -15
  93. data/app/models/alchemy/storage_adapter/active_storage/attachment_url.rb +41 -0
  94. data/app/models/alchemy/storage_adapter/active_storage/picture_url.rb +55 -0
  95. data/app/models/alchemy/storage_adapter/active_storage/preprocessor.rb +40 -0
  96. data/app/models/alchemy/storage_adapter/active_storage.rb +173 -0
  97. data/app/models/alchemy/{attachment/url.rb → storage_adapter/dragonfly/attachment_url.rb} +12 -12
  98. data/app/models/alchemy/{picture/url.rb → storage_adapter/dragonfly/picture_url.rb} +28 -12
  99. data/app/models/alchemy/{picture → storage_adapter/dragonfly}/preprocessor.rb +4 -4
  100. data/app/models/alchemy/storage_adapter/dragonfly.rb +183 -0
  101. data/app/models/alchemy/storage_adapter.rb +74 -0
  102. data/app/models/concerns/alchemy/picture_thumbnails.rb +19 -6
  103. data/app/serializers/alchemy/element_serializer.rb +0 -1
  104. data/app/services/alchemy/dragonfly_to_image_processing.rb +100 -0
  105. data/app/stylesheets/alchemy/_defaults.scss +3 -0
  106. data/app/stylesheets/alchemy/_extends.scss +69 -0
  107. data/app/{assets/stylesheets → stylesheets}/alchemy/_mixins.scss +36 -49
  108. data/app/stylesheets/alchemy/_variables.scss +5 -0
  109. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/archive.scss +20 -37
  110. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/base.scss +16 -14
  111. data/app/stylesheets/alchemy/admin/buttons.scss +160 -0
  112. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/clipboard.scss +2 -2
  113. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dashboard.scss +13 -16
  114. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dialogs.scss +23 -16
  115. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/elements.scss +150 -105
  116. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/errors.scss +5 -5
  117. data/app/stylesheets/alchemy/admin/filters.scss +58 -0
  118. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flatpickr.scss +53 -60
  119. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/form_fields.scss +21 -7
  120. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/forms.scss +31 -19
  121. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/frame.scss +20 -16
  122. data/app/stylesheets/alchemy/admin/hints.scss +5 -0
  123. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/icons.scss +10 -1
  124. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/image_library.scss +10 -8
  125. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/images.scss +1 -1
  126. data/app/stylesheets/alchemy/admin/labels.scss +5 -0
  127. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/lists.scss +3 -3
  128. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/navigation.scss +61 -55
  129. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/nodes.scss +21 -18
  130. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/notices.scss +18 -18
  131. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/page-select.scss +2 -2
  132. data/app/stylesheets/alchemy/admin/pagination.scss +144 -0
  133. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/preview_window.scss +8 -6
  134. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/print.scss +1 -1
  135. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/resource_info.scss +8 -5
  136. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/search.scss +9 -6
  137. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/selects.scss +49 -37
  138. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/shoelace.scss +5 -6
  139. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/sitemap.scss +38 -33
  140. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tables.scss +6 -4
  141. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tags.scss +6 -4
  142. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/toolbar.scss +12 -6
  143. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/typography.scss +2 -2
  144. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/upload.scss +7 -5
  145. data/app/stylesheets/alchemy/admin.scss +44 -0
  146. data/app/stylesheets/alchemy/custom-properties.css +244 -0
  147. data/app/stylesheets/alchemy/welcome.scss +75 -0
  148. data/app/{assets/stylesheets → stylesheets}/tinymce/skins/content/alchemy/content.scss +8 -9
  149. data/app/stylesheets/tinymce/skins/ui/alchemy/content.scss +1 -0
  150. data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/skin.scss +133 -136
  151. data/app/views/alchemy/admin/attachments/_files_list.html.erb +2 -2
  152. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
  153. data/app/views/alchemy/admin/{elements/_clipboard_button.html.erb → clipboard/_button.html.erb} +3 -5
  154. data/app/views/alchemy/admin/clipboard/_update_nested_element_button.turbo_stream.erb +11 -0
  155. data/app/views/alchemy/admin/clipboard/clear.turbo_stream.erb +4 -0
  156. data/app/views/alchemy/admin/clipboard/index.html.erb +15 -13
  157. data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +18 -0
  158. data/app/views/alchemy/admin/clipboard/remove.turbo_stream.erb +9 -0
  159. data/app/views/alchemy/admin/dashboard/info.html.erb +17 -31
  160. data/app/views/alchemy/admin/elements/_element.html.erb +4 -8
  161. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  162. data/app/views/alchemy/admin/elements/_header.html.erb +1 -0
  163. data/app/views/alchemy/admin/elements/_toolbar.html.erb +4 -6
  164. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +2 -1
  165. data/app/views/alchemy/admin/elements/index.html.erb +2 -2
  166. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +3 -16
  167. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +0 -9
  168. data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
  169. data/app/views/alchemy/admin/languages/_table.html.erb +1 -1
  170. data/app/views/alchemy/admin/languages/index.html.erb +5 -2
  171. data/app/views/alchemy/admin/layoutpages/index.html.erb +1 -12
  172. data/app/views/alchemy/admin/pages/_form.html.erb +2 -2
  173. data/app/views/alchemy/admin/pages/_page.html.erb +2 -3
  174. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -15
  175. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  176. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +9 -12
  177. data/app/views/alchemy/admin/partials/_search_form.html.erb +4 -9
  178. data/app/views/alchemy/admin/pictures/_archive.html.erb +4 -7
  179. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +2 -1
  180. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -1
  181. data/app/views/alchemy/admin/pictures/index.html.erb +2 -7
  182. data/app/views/alchemy/admin/resources/_applied_filters.html.erb +8 -0
  183. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +11 -21
  184. data/app/views/alchemy/admin/resources/_pagination.html.erb +6 -0
  185. data/app/views/alchemy/admin/resources/_per_page_select.html.erb +4 -2
  186. data/app/views/alchemy/admin/resources/_resource_table.html.erb +1 -1
  187. data/app/views/alchemy/admin/resources/_table_header.html.erb +1 -15
  188. data/app/views/alchemy/admin/sites/index.html.erb +5 -1
  189. data/app/views/alchemy/admin/styleguide/index.html.erb +8 -0
  190. data/app/views/alchemy/admin/tags/index.html.erb +1 -1
  191. data/app/views/alchemy/admin/tinymce/_setup.html.erb +7 -7
  192. data/app/{javascript/alchemy_admin/locales/en.js → views/alchemy/admin/translations/_en.js} +5 -2
  193. data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
  194. data/app/views/alchemy/admin/uploader/_setup.html.erb +4 -4
  195. data/app/views/alchemy/base/redirect.js.erb +1 -1
  196. data/app/views/alchemy/ingredients/_number_editor.html.erb +24 -0
  197. data/app/views/alchemy/no_index.html.erb +31 -0
  198. data/app/views/alchemy/welcome.html.erb +12 -10
  199. data/app/views/kaminari/alchemy/_first_page.html.erb +5 -3
  200. data/app/views/kaminari/alchemy/_last_page.html.erb +5 -3
  201. data/app/views/kaminari/alchemy/_next_page.html.erb +5 -3
  202. data/app/views/kaminari/alchemy/_paginator.html.erb +18 -13
  203. data/app/views/kaminari/alchemy/_prev_page.html.erb +5 -3
  204. data/app/views/layouts/alchemy/admin.html.erb +5 -9
  205. data/bun.lockb +0 -0
  206. data/bundles/remixicon.mjs +153 -0
  207. data/config/alchemy/config.yml +3 -2
  208. data/config/initializers/dragonfly.rb +0 -1
  209. data/config/initializers/mime_types.rb +1 -0
  210. data/config/locales/alchemy.en.yml +32 -14
  211. data/config/routes.rb +0 -2
  212. data/eslint.config.js +2 -1
  213. data/lib/alchemy/admin/preview_url.rb +4 -5
  214. data/lib/alchemy/cache_digests/template_tracker.rb +6 -9
  215. data/lib/alchemy/config_missing.rb +14 -0
  216. data/lib/alchemy/configuration/base_option.rb +24 -0
  217. data/lib/alchemy/configuration/boolean_option.rb +16 -0
  218. data/lib/alchemy/configuration/class_option.rb +15 -0
  219. data/lib/alchemy/configuration/class_set_option.rb +46 -0
  220. data/lib/alchemy/configuration/integer_list_option.rb +13 -0
  221. data/lib/alchemy/configuration/integer_option.rb +12 -0
  222. data/lib/alchemy/configuration/list_option.rb +22 -0
  223. data/lib/alchemy/configuration/regexp_option.rb +11 -0
  224. data/lib/alchemy/configuration/string_list_option.rb +13 -0
  225. data/lib/alchemy/configuration/string_option.rb +11 -0
  226. data/lib/alchemy/configuration.rb +115 -0
  227. data/lib/alchemy/configuration_methods.rb +3 -1
  228. data/lib/alchemy/configurations/default_language.rb +12 -0
  229. data/lib/alchemy/configurations/default_site.rb +10 -0
  230. data/lib/alchemy/configurations/format_matchers.rb +11 -0
  231. data/lib/alchemy/configurations/mailer.rb +16 -0
  232. data/lib/alchemy/configurations/main.rb +216 -0
  233. data/lib/alchemy/configurations/preview.rb +32 -0
  234. data/lib/alchemy/configurations/sitemap.rb +10 -0
  235. data/lib/alchemy/configurations/uploader.rb +34 -0
  236. data/lib/alchemy/engine.rb +65 -17
  237. data/lib/alchemy/hints.rb +3 -7
  238. data/lib/alchemy/on_page_layout.rb +2 -2
  239. data/lib/alchemy/propshaft/tinymce_asset.rb +15 -0
  240. data/lib/alchemy/seeder.rb +2 -2
  241. data/lib/alchemy/tasks/usage.rb +4 -4
  242. data/lib/alchemy/test_support/config_stubbing.rb +1 -7
  243. data/lib/alchemy/test_support/factories/attachment_factory.rb +13 -2
  244. data/lib/alchemy/test_support/factories/language_factory.rb +1 -1
  245. data/lib/alchemy/test_support/factories/page_factory.rb +2 -3
  246. data/lib/alchemy/test_support/factories/picture_factory.rb +30 -2
  247. data/lib/alchemy/test_support/factories/site_factory.rb +2 -2
  248. data/lib/alchemy/test_support/having_crop_action_examples.rb +2 -2
  249. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +80 -26
  250. data/lib/alchemy/test_support/shared_ingredient_examples.rb +5 -5
  251. data/lib/alchemy/upgrader/.keep +0 -0
  252. data/lib/alchemy/upgrader/eight_zero.rb +14 -0
  253. data/lib/alchemy/upgrader.rb +33 -20
  254. data/lib/alchemy/version.rb +1 -1
  255. data/lib/alchemy.rb +192 -170
  256. data/lib/alchemy_cms.rb +1 -7
  257. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +0 -3
  258. data/lib/generators/alchemy/install/files/_article.html.erb +6 -4
  259. data/lib/generators/alchemy/install/files/alchemy.en.yml +22 -3
  260. data/lib/generators/alchemy/install/files/application.html.erb +5 -0
  261. data/lib/generators/alchemy/install/install_generator.rb +5 -14
  262. data/lib/generators/alchemy/install/templates/alchemy.rb.tt +196 -0
  263. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +0 -1
  264. data/lib/generators/alchemy/install/templates/elements.yml.tt +3 -1
  265. data/lib/generators/alchemy/install/templates/menus.yml.tt +1 -1
  266. data/lib/generators/alchemy/install/templates/page_layouts.yml.tt +2 -2
  267. data/lib/generators/alchemy/page_layouts/page_layouts_generator.rb +2 -2
  268. data/lib/tasks/alchemy/assets.rake +14 -0
  269. data/lib/tasks/alchemy/upgrade.rake +12 -47
  270. data/vendor/javascript/tinymce.min.js +1 -1
  271. data/vitest.config.js +21 -0
  272. metadata +181 -180
  273. data/app/assets/builds/alchemy/admin/page-select.css.map +0 -1
  274. data/app/assets/builds/alchemy/admin/print.css.map +0 -1
  275. data/app/assets/builds/alchemy/admin.css.map +0 -1
  276. data/app/assets/builds/alchemy/custom-properties.css.map +0 -1
  277. data/app/assets/builds/alchemy/welcome.css.map +0 -1
  278. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +0 -1
  279. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css.map +0 -1
  280. data/app/assets/javascripts/alchemy/admin.js +0 -10
  281. data/app/assets/stylesheets/alchemy/_defaults.scss +0 -3
  282. data/app/assets/stylesheets/alchemy/_deprecated_variables.scss +0 -45
  283. data/app/assets/stylesheets/alchemy/_deprecation.scss +0 -17
  284. data/app/assets/stylesheets/alchemy/_extends.scss +0 -62
  285. data/app/assets/stylesheets/alchemy/_variables.scss +0 -201
  286. data/app/assets/stylesheets/alchemy/admin/buttons.scss +0 -124
  287. data/app/assets/stylesheets/alchemy/admin/hints.scss +0 -5
  288. data/app/assets/stylesheets/alchemy/admin/labels.scss +0 -3
  289. data/app/assets/stylesheets/alchemy/admin/pagination.scss +0 -92
  290. data/app/assets/stylesheets/alchemy/admin.scss +0 -42
  291. data/app/assets/stylesheets/alchemy/custom-properties.css +0 -98
  292. data/app/assets/stylesheets/alchemy/welcome.scss +0 -57
  293. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.css +0 -711
  294. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.css +0 -705
  295. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.min.css +0 -7
  296. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.min.css +0 -7
  297. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.css +0 -29
  298. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.min.css +0 -7
  299. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.css +0 -677
  300. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.min.css +0 -7
  301. data/app/controllers/alchemy/elements_controller.rb +0 -32
  302. data/app/models/alchemy/element/dom_id.rb +0 -31
  303. data/app/models/alchemy/picture/calculations.rb +0 -49
  304. data/app/models/alchemy/picture/transformations.rb +0 -115
  305. data/app/views/alchemy/admin/attachments/destroy.js.erb +0 -1
  306. data/app/views/alchemy/admin/clipboard/clear.js.erb +0 -3
  307. data/app/views/alchemy/admin/clipboard/insert.js.erb +0 -29
  308. data/app/views/alchemy/admin/clipboard/remove.js.erb +0 -10
  309. data/app/views/alchemy/admin/resources/_filter.html.erb +0 -12
  310. data/app/views/alchemy/admin/resources/_resource.html.erb +0 -34
  311. data/app/views/alchemy/admin/resources/_table.html.erb +0 -29
  312. data/app/views/alchemy/elements/show.html.erb +0 -1
  313. data/app/views/alchemy/elements/show.js.erb +0 -1
  314. data/app/views/alchemy/ingredients/_audio_view.html.erb +0 -1
  315. data/app/views/alchemy/ingredients/_boolean_view.html.erb +0 -1
  316. data/app/views/alchemy/ingredients/_datetime_view.html.erb +0 -3
  317. data/app/views/alchemy/ingredients/_file_view.html.erb +0 -4
  318. data/app/views/alchemy/ingredients/_headline_view.html.erb +0 -4
  319. data/app/views/alchemy/ingredients/_html_view.html.erb +0 -1
  320. data/app/views/alchemy/ingredients/_link_view.html.erb +0 -4
  321. data/app/views/alchemy/ingredients/_node_view.html.erb +0 -1
  322. data/app/views/alchemy/ingredients/_page_view.html.erb +0 -1
  323. data/app/views/alchemy/ingredients/_picture_view.html.erb +0 -4
  324. data/app/views/alchemy/ingredients/_richtext_view.html.erb +0 -3
  325. data/app/views/alchemy/ingredients/_select_view.html.erb +0 -1
  326. data/app/views/alchemy/ingredients/_text_view.html.erb +0 -4
  327. data/app/views/alchemy/ingredients/_video_view.html.erb +0 -3
  328. data/babel.config.js +0 -12
  329. data/config/initializers/assets.rb +0 -4
  330. data/lib/alchemy/config.rb +0 -114
  331. data/lib/alchemy/element_definition.rb +0 -73
  332. data/lib/alchemy/page_layout.rb +0 -73
  333. data/lib/alchemy/resource_filter.rb +0 -40
  334. data/lib/alchemy/upgrader/seven_point_four.rb +0 -26
  335. data/lib/alchemy/upgrader/seven_point_three.rb +0 -52
  336. data/lib/generators/alchemy/ingredient/templates/view.html.erb +0 -1
  337. data/lib/generators/alchemy/install/files/alchemy_admin.js +0 -1
  338. data/lib/generators/alchemy/install/files/all.js +0 -11
  339. data/lib/generators/alchemy/install/files/article.css +0 -25
  340. data/vendor/assets/images/remixicon.symbol.svg +0 -11
  341. /data/app/{assets/stylesheets → stylesheets}/alchemy/_fonts.scss +0 -0
  342. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachment-select.scss +0 -0
  343. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachments.scss +0 -0
  344. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flash.scss +0 -0
  345. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/list_filter.scss +0 -0
  346. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/node-select.scss +0 -0
  347. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/spinner.scss +0 -0
  348. /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/skintool.json +0 -0
  349. /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/fonts/tinymce-mobile.woff +0 -0
@@ -14,7 +14,7 @@ module Alchemy
14
14
  #
15
15
  # @return Array<Alchemy::IngredientEditor>
16
16
  def ingredients
17
- element.definition.fetch(:ingredients, []).map do |ingredient|
17
+ ingredient_definitions.map do |ingredient|
18
18
  Alchemy::IngredientEditor.new(find_or_create_ingredient(ingredient))
19
19
  end
20
20
  end
@@ -22,7 +22,7 @@ module Alchemy
22
22
  # Are any ingredients defined?
23
23
  # @return [Boolean]
24
24
  def has_ingredients_defined?
25
- element.definition.fetch(:ingredients, []).any?
25
+ ingredient_definitions.any?
26
26
  end
27
27
 
28
28
  # Returns the translated ingredient group for displaying in admin editor group headings
@@ -77,56 +77,13 @@ module Alchemy
77
77
  super
78
78
  end
79
79
 
80
- # Returns a deprecation notice for elements marked deprecated
81
- #
82
- # You can either use localizations or pass a String as notice
83
- # in the element definition.
84
- #
85
- # == Custom deprecation notices
86
- #
87
- # Use general element deprecation notice
88
- #
89
- # - name: old_element
90
- # deprecated: true
91
- #
92
- # Add a translation to your locale file for a per element notice.
93
- #
94
- # en:
95
- # alchemy:
96
- # element_deprecation_notices:
97
- # old_element: Foo baz widget is deprecated
98
- #
99
- # or use the global translation that apply to all deprecated elements.
100
- #
101
- # en:
102
- # alchemy:
103
- # element_deprecation_notice: Foo baz widget is deprecated
104
- #
105
- # or pass string as deprecation notice.
106
- #
107
- # - name: old_element
108
- # deprecated: This element will be removed soon.
109
- #
110
- def deprecation_notice
111
- case definition["deprecated"]
112
- when String
113
- definition["deprecated"]
114
- when TrueClass
115
- Alchemy.t(
116
- name,
117
- scope: :element_deprecation_notices,
118
- default: Alchemy.t(:element_deprecated)
119
- )
120
- end
121
- end
122
-
123
80
  private
124
81
 
125
82
  def find_or_create_ingredient(definition)
126
- element.ingredients.detect { |i| i.role == definition[:role] } ||
83
+ element.ingredients.detect { _1.role == definition.role } ||
127
84
  element.ingredients.create!(
128
- role: definition[:role],
129
- type: Alchemy::Ingredient.normalize_type(definition[:type])
85
+ role: definition.role,
86
+ type: Alchemy::Ingredient.normalize_type(definition.type)
130
87
  )
131
88
  end
132
89
  end
@@ -99,62 +99,12 @@ module Alchemy
99
99
  Logger.warn("ingredient #{role} is missing its definition", caller(1..1))
100
100
  Alchemy.t(:ingredient_definition_missing)
101
101
  else
102
- deprecation_notice
103
- end
104
- end
105
-
106
- # Returns a deprecation notice for ingredients marked deprecated
107
- #
108
- # You can either use localizations or pass a String as notice
109
- # in the ingredient definition.
110
- #
111
- # == Custom deprecation notices
112
- #
113
- # Use general ingredient deprecation notice
114
- #
115
- # - name: element_name
116
- # ingredients:
117
- # - role: old_ingredient
118
- # type: Text
119
- # deprecated: true
120
- #
121
- # Add a translation to your locale file for a per ingredient notice.
122
- #
123
- # en:
124
- # alchemy:
125
- # ingredient_deprecation_notices:
126
- # element_name:
127
- # old_ingredient: Foo baz widget is deprecated
128
- #
129
- # or use the global translation that apply to all deprecated ingredients.
130
- #
131
- # en:
132
- # alchemy:
133
- # ingredient_deprecation_notice: Foo baz widget is deprecated
134
- #
135
- # or pass string as deprecation notice.
136
- #
137
- # - name: element_name
138
- # ingredients:
139
- # - role: old_ingredient
140
- # type: Text
141
- # deprecated: This ingredient will be removed soon.
142
- #
143
- def deprecation_notice
144
- case definition[:deprecated]
145
- when String
146
- definition[:deprecated]
147
- when TrueClass
148
- Alchemy.t(
149
- role,
150
- scope: [:ingredient_deprecation_notices, element.name],
151
- default: Alchemy.t(:ingredient_deprecated)
152
- )
102
+ definition.deprecation_notice(element_name: element&.name)
153
103
  end
154
104
  end
155
105
 
156
106
  def validations
157
- definition.fetch(:validate, [])
107
+ definition.validate
158
108
  end
159
109
 
160
110
  def format_validation
@@ -173,7 +123,7 @@ module Alchemy
173
123
  private
174
124
 
175
125
  def form_field_counter
176
- element.definition.fetch(:ingredients, []).index { |i| i[:role] == role }
126
+ element.ingredient_definitions.index { _1.role == role }
177
127
  end
178
128
  end
179
129
  end
@@ -73,6 +73,13 @@ module Alchemy
73
73
  end
74
74
  end
75
75
 
76
+ def alchemy_admin_js_translations(locale = ::I18n.locale)
77
+ render partial: "alchemy/admin/translations/#{locale}", formats: [:js]
78
+ rescue ActionView::MissingTemplate
79
+ # Fallback to default translations
80
+ render partial: "alchemy/admin/translations/en", formats: [:js]
81
+ end
82
+
76
83
  # Used for site selector in Alchemy cockpit.
77
84
  def sites_for_select
78
85
  Alchemy::Site.all.map do |site|
@@ -80,36 +87,6 @@ module Alchemy
80
87
  end
81
88
  end
82
89
 
83
- # Returns a javascript driven live filter for lists.
84
- #
85
- # The items must have a html +name+ attribute that holds the filterable value.
86
- #
87
- # == Example
88
- #
89
- # Given a list of items:
90
- #
91
- # <%= js_filter_field('#products .product') %>
92
- #
93
- # <ul id="products">
94
- # <li class="product" name="kat litter">Kat Litter</li>
95
- # <li class="product" name="milk">Milk</li>
96
- # </ul>
97
- #
98
- # @param [String] items
99
- # A jquery compatible selector string that represents the items to filter
100
- # @param [Hash] options
101
- # HTML options passed to the input field
102
- #
103
- # @option options [String] :class ('js_filter_field')
104
- # The css class of the <input> tag
105
- # @option options [String or Hash] :data ({'alchemy-list-filter' => items})
106
- # A HTML data attribute that holds the jQuery selector that represents the list to be filtered
107
- # @deprecated render Alchemy::Admin::ListFilter.new(items) instead
108
- def js_filter_field(items, _options = {})
109
- render Alchemy::Admin::ListFilter.new(items)
110
- end
111
- deprecate js_filter_field: "render Alchemy::Admin::ListFilter.new(items) instead", deprecator: Alchemy::Deprecation
112
-
113
90
  # Returns a link that opens a modal confirmation to delete window.
114
91
  #
115
92
  # === Example:
@@ -137,12 +114,10 @@ module Alchemy
137
114
  def link_to_confirm_dialog(link_string = "", message = "", url = "", html_options = {})
138
115
  link_to(link_string, url,
139
116
  html_options.merge(
140
- "data-alchemy-confirm-delete" => {
141
- title: Alchemy.t(:please_confirm),
142
- message: message,
143
- ok_label: Alchemy.t("Yes"),
144
- cancel_label: Alchemy.t("No")
145
- }.to_json
117
+ data: {
118
+ "turbo-method": :delete,
119
+ "turbo-confirm": message
120
+ }
146
121
  ))
147
122
  end
148
123
 
@@ -168,12 +143,10 @@ module Alchemy
168
143
  def button_with_confirm(value = "", url = "", options = {}, html_options = {})
169
144
  options = {
170
145
  message: Alchemy.t(:confirm_to_proceed),
171
- ok_label: Alchemy.t("Yes"),
172
- title: Alchemy.t(:please_confirm),
173
- cancel_label: Alchemy.t("No")
146
+ title: Alchemy.t(:please_confirm)
174
147
  }.merge(options)
175
148
  form_tag url, {method: html_options.delete(:method), class: "button-with-confirm"} do
176
- button_tag value, html_options.merge("data-alchemy-confirm" => options.to_json)
149
+ button_tag value, html_options.merge("data-turbo-confirm" => options[:message])
177
150
  end
178
151
  end
179
152
 
@@ -220,49 +193,6 @@ module Alchemy
220
193
  "Alchemy CMS - #{title}"
221
194
  end
222
195
 
223
- # Renders a toolbar button for the Alchemy toolbar
224
- #
225
- # == Example
226
- #
227
- # <%= toolbar_button(
228
- # icon: :plus,
229
- # label: 'Create',
230
- # url: new_resource_path,
231
- # title: 'Create Resource',
232
- # hotkey: 'alt+n',
233
- # dialog_options: {
234
- # title: 'Create Resource',
235
- # size: "430x400"
236
- # },
237
- # if_permitted_to: [:create, resource_model]
238
- # ) %>
239
- #
240
- # @option options [String] :icon
241
- # Icon class. See +app/assets/stylesheets/alchemy/icons.css.sccs+ for available icons, or make your own.
242
- # @option options [String] :label
243
- # Text for button label.
244
- # @option options [String] :url
245
- # Url for link.
246
- # @option options [String] :title
247
- # Text for title tag.
248
- # @option options [String] :hotkey
249
- # Keyboard shortcut for this button. I.E +alt-n+
250
- # @option options [Boolean] :dialog (true)
251
- # Open the link in a modal dialog.
252
- # @option options [Hash] :dialog_options
253
- # Overlay options. See link_to_dialog helper.
254
- # @option options [Array] :if_permitted_to ([:action, :controller])
255
- # Check permission for button. Exactly how you defined the permission in your +authorization_rules.rb+. Defaults to controller and action from button url.
256
- # @option options [Boolean] :skip_permission_check (false)
257
- # Skip the permission check. NOT RECOMMENDED!
258
- # @option options [Boolean] :loading_indicator (true)
259
- # Shows the please wait dialog while loading. Only for buttons not opening an dialog.
260
- # @deprecated render Alchemy::Admin::ToolbarButton.new instead
261
- def toolbar_button(options = {})
262
- render Alchemy::Admin::ToolbarButton.new(**options)
263
- end
264
- deprecate toolbar_button: "render Alchemy::Admin::ToolbarButton.new instead", deprecator: Alchemy::Deprecation
265
-
266
196
  # Renders a textfield ready to display a datepicker
267
197
  #
268
198
  # A Javascript observer converts this into a fancy Datepicker.
@@ -346,7 +276,7 @@ module Alchemy
346
276
 
347
277
  # Returns the regular expression used for external url validation in link dialog.
348
278
  def link_url_regexp
349
- Alchemy::Config.get(:format_matchers)["link_url"] || /^(mailto:|\/|[a-z]+:\/\/)/
279
+ Alchemy.config.format_matchers.link_url || /^(mailto:|\/|[a-z]+:\/\/)/
350
280
  end
351
281
 
352
282
  # Renders a hint with tooltip
@@ -13,12 +13,12 @@ module Alchemy
13
13
  def elements_for_select(elements)
14
14
  return [] if elements.nil?
15
15
 
16
- elements.collect do |e|
16
+ elements.map do |e|
17
17
  [
18
- Element.display_name_for(e["name"]),
19
- e["name"]
18
+ Element.display_name_for(e.name),
19
+ e.name
20
20
  ]
21
- end.sort
21
+ end.tap(&:sort!)
22
22
  end
23
23
  end
24
24
  end
@@ -10,7 +10,7 @@ module Alchemy
10
10
  # You can configure the screen sizes in your +config/alchemy/config.yml+.
11
11
  #
12
12
  def preview_sizes_for_select
13
- Alchemy::Config.get(:page_preview_sizes).map do |size|
13
+ Alchemy.config.page_preview_sizes.map do |size|
14
14
  [Alchemy.t(size, scope: "preview_sizes"), size]
15
15
  end
16
16
  end
@@ -2,14 +2,6 @@
2
2
 
3
3
  module Alchemy
4
4
  module BaseHelper
5
- # An alias for truncate.
6
- # Left here for downwards compatibilty.
7
- # @deprecated
8
- def shorten(text, length)
9
- text.truncate(length: length)
10
- end
11
- deprecate :shorten, deprecator: Alchemy::Deprecation
12
-
13
5
  # Logs a message in the Rails logger (warn level)
14
6
  # and optionally displays an error message to the user.
15
7
  def warning(message, text = nil)
@@ -45,27 +37,5 @@ module Alchemy
45
37
  def render_message(type = :info, msg = nil, &)
46
38
  render Alchemy::Admin::Message.new(msg || capture(&), type: type)
47
39
  end
48
-
49
- # Checks if the given argument is a String or a Page object.
50
- # If a String is given, it tries to find the page via page_layout
51
- # Logs a warning if no page is given.
52
- # @deprecated
53
- def page_or_find(page)
54
- unless Current.language
55
- warning("No default language set up")
56
- return nil
57
- end
58
-
59
- if page.is_a?(String)
60
- page = Current.language.pages.find_by(page_layout: page)
61
- end
62
- if page.blank?
63
- warning("No Page found for #{page.inspect}")
64
- nil
65
- else
66
- page
67
- end
68
- end
69
- deprecate :page_or_find, deprecator: Alchemy::Deprecation
70
40
  end
71
41
  end
@@ -100,22 +100,8 @@ module Alchemy
100
100
  # A lambda used for formatting the element's tags (see Alchemy::ElementsHelper::element_tags_attributes). Set to +false+ to not include tags in the wrapper element.
101
101
  #
102
102
  def element_view_for(element, options = {})
103
- if options[:id].nil?
104
- Alchemy::Deprecation.warn <<~WARN
105
- Relying on an implicit DOM id in `element_view_for` is deprecated. Please provide an explicit `id` if you actually want to render an `id` attribute on the #{element.name} element wrapper tag.
106
- WARN
107
- end
108
-
109
- if options[:class].nil?
110
- Alchemy::Deprecation.warn <<~WARN
111
- Relying on an implicit CSS class in `element_view_for` is deprecated. Please provide an explicit `class` for the #{element.name} element wrapper tag.
112
- WARN
113
- end
114
-
115
103
  options = {
116
104
  tag: :div,
117
- id: (!!options[:id]) ? options[:id] : element.dom_id,
118
- class: element.name,
119
105
  tags_formatter: ->(tags) { tags.join(" ") }
120
106
  }.merge(options)
121
107
 
@@ -46,7 +46,7 @@ module Alchemy
46
46
  def render_page_layout
47
47
  render @page, page: @page
48
48
  rescue ActionView::MissingTemplate
49
- warning("PageLayout: '#{@page.page_layout}' not found. Rendering standard page_layout.")
49
+ warning("[alchemy]: '#{@page.page_layout}' page layout not found. Rendering 'standard' page layout.")
50
50
  render "alchemy/page_layouts/standard", page: @page
51
51
  end
52
52
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Alchemy
4
4
  module ResourcesHelper
5
+ include Alchemy::Admin::ResourceName
6
+
5
7
  # = Alchemy::ResourceHelper
6
8
  #
7
9
  # Used to DRY up resource like structures in Alchemy's admin backend in combination with Alchemy::Resource
@@ -14,11 +16,11 @@ module Alchemy
14
16
  end
15
17
 
16
18
  def resource_instance_variable
17
- instance_variable_get(:"@#{resource_handler.resource_name}")
19
+ instance_variable_get(:"@#{resource_name}")
18
20
  end
19
21
 
20
22
  def resources_instance_variable
21
- instance_variable_get(:"@#{resource_handler.resources_name}")
23
+ instance_variable_get(:"@#{resources_name}")
22
24
  end
23
25
 
24
26
  def resource_url_proxy
@@ -46,14 +48,10 @@ module Alchemy
46
48
  end
47
49
 
48
50
  def edit_resource_path(resource = nil, options = {})
49
- path_segments = resource_scope + [resource] || resource_handler.resource_array
51
+ path_segments = resource_scope + [resource] || resource_array
50
52
  edit_polymorphic_path path_segments, options
51
53
  end
52
54
 
53
- def resource_name
54
- resource_handler.resource_name
55
- end
56
-
57
55
  def resource_model
58
56
  resource_handler.model
59
57
  end
@@ -127,44 +125,6 @@ module Alchemy
127
125
  resource_handler.resource_relations.collect { |_k, v| v[:name].to_sym }
128
126
  end
129
127
 
130
- # Returns the attribute's column for sorting
131
- #
132
- # If the attribute contains a resource_relation, then the table and column for related model will be returned.
133
- # @deprecated
134
- def sortable_resource_header_column(attribute)
135
- if (relation = attribute[:relation])
136
- "#{relation[:model_association].name}_#{relation[:attr_method]}"
137
- else
138
- attribute[:name]
139
- end
140
- end
141
- deprecate sortable_resource_header_column: "Please `render Alchemy::Admin::Resource::Table instead`", deprecator: Alchemy::Deprecation
142
-
143
- # Renders the row for a resource record in the resources table.
144
- #
145
- # This helper has a nice fallback. If you create a partial for your record then this partial will be rendered.
146
- #
147
- # Otherwise the default +app/views/alchemy/admin/resources/_resource.html.erb+ partial gets rendered.
148
- #
149
- # == Example
150
- #
151
- # For a resource named +Comment+ you can create a partial named +_comment.html.erb+
152
- #
153
- # # app/views/admin/comments/_comment.html.erb
154
- # <tr>
155
- # <td><%= comment.title %></td>
156
- # <td><%= comment.body %></td>
157
- # </tr>
158
- #
159
- # NOTE: Alchemy gives you a local variable named like your resource
160
- # @deprecated
161
- def render_resources(icon: nil)
162
- render partial: resource_name, collection: resources_instance_variable, locals: {icon: icon}
163
- rescue ActionView::MissingTemplate
164
- render partial: "resource", collection: resources_instance_variable, locals: {icon: icon}
165
- end
166
- deprecate render_resources: "Please `render Alchemy::Admin::Resource::Table instead`", deprecator: Alchemy::Deprecation
167
-
168
128
  def resource_has_tags
169
129
  resource_model.respond_to?(:tag_counts) && resource_model.tag_counts.any?
170
130
  end
@@ -1,4 +1,5 @@
1
1
  import { reloadPreview } from "alchemy_admin/components/preview_window"
2
+ import { removeTab } from "alchemy_admin/fixed_elements"
2
3
  import { closeCurrentDialog } from "alchemy_admin/dialog"
3
4
  import IngredientAnchorLink from "alchemy_admin/ingredient_anchor_link"
4
5
 
@@ -13,6 +14,7 @@ class Action extends HTMLElement {
13
14
  // we don't have to implicitly close the dialog
14
15
  closeCurrentDialog,
15
16
  reloadPreview,
17
+ removeFixedElement: removeTab,
16
18
  updateAnchorIcon: IngredientAnchorLink.updateIcon
17
19
  }
18
20
  }
@@ -26,7 +26,7 @@ export class AlchemyHTMLElement extends HTMLElement {
26
26
  * this is a default function
27
27
  * @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Components#reference
28
28
  */
29
- connectedCallback() {
29
+ async connectedCallback() {
30
30
  // parse the properties object and register property with the default values
31
31
  Object.keys(this.constructor.properties).forEach((name) => {
32
32
  // if the options was given via the constructor, they should be prefer (e.g. new <WebComponentName>({title: "Foo"}))
@@ -39,7 +39,7 @@ export class AlchemyHTMLElement extends HTMLElement {
39
39
 
40
40
  // render the component
41
41
  this._updateComponent()
42
- this.connected()
42
+ await this.connected()
43
43
  }
44
44
 
45
45
  /**
@@ -64,7 +64,7 @@ export class AlchemyHTMLElement extends HTMLElement {
64
64
  /**
65
65
  * a connected method to make it easier to overwrite the connection callback
66
66
  */
67
- connected() {}
67
+ async connected() {}
68
68
 
69
69
  /**
70
70
  * a disconnected method to make it easier to overwrite the disconnection callback
@@ -2,6 +2,8 @@ import { AlchemyHTMLElement } from "alchemy_admin/components/alchemy_html_elemen
2
2
  import { translate, currentLocale } from "alchemy_admin/i18n"
3
3
  import flatpickr from "flatpickr"
4
4
 
5
+ const locale = currentLocale()
6
+
5
7
  class Datepicker extends AlchemyHTMLElement {
6
8
  static properties = {
7
9
  inputType: { default: "date" }
@@ -12,7 +14,13 @@ class Datepicker extends AlchemyHTMLElement {
12
14
  this.flatpickr = undefined
13
15
  }
14
16
 
15
- afterRender() {
17
+ // Load the locales for flatpickr before setting it up.
18
+ async connected() {
19
+ // English is the default locale for flatpickr, so we don't need to load it
20
+ if (locale !== "en") {
21
+ await import(`flatpickr/${locale}.js`)
22
+ }
23
+
16
24
  this.flatpickr = flatpickr(
17
25
  this.getElementsByTagName("input")[0],
18
26
  this.flatpickrOptions
@@ -27,7 +35,7 @@ class Datepicker extends AlchemyHTMLElement {
27
35
  const enableTime = /time/.test(this.inputType)
28
36
  const options = {
29
37
  // alchemy_i18n supports `zh_CN` etc., but flatpickr only has two-letter codes (`zh`)
30
- locale: currentLocale().slice(0, 2),
38
+ locale: locale.slice(0, 2),
31
39
  altInput: true,
32
40
  altFormat: translate(`formats.${this.inputType}`),
33
41
  altInputClass: "flatpickr-input",
@@ -1,7 +1,7 @@
1
1
  import { removeTab } from "alchemy_admin/fixed_elements"
2
2
  import { growl } from "alchemy_admin/growler"
3
3
  import { reloadPreview } from "alchemy_admin/components/preview_window"
4
- import { confirmToDeleteDialog } from "alchemy_admin/confirm_dialog"
4
+ import { openConfirmDialog } from "alchemy_admin/confirm_dialog"
5
5
 
6
6
  export class DeleteElementButton extends HTMLElement {
7
7
  constructor() {
@@ -9,12 +9,12 @@ export class DeleteElementButton extends HTMLElement {
9
9
  this.addEventListener("click", this)
10
10
  }
11
11
 
12
- handleEvent() {
13
- confirmToDeleteDialog(this.url, { message: this.message }).then(
14
- (response) => {
15
- this.#removeElement(response)
16
- }
17
- )
12
+ async handleEvent() {
13
+ const confirmed = await openConfirmDialog(this.message)
14
+ if (confirmed) {
15
+ const response = await fetch(this.url, { method: "DELETE" })
16
+ this.#removeElement(await response.json())
17
+ }
18
18
  }
19
19
 
20
20
  #removeElement(response) {
@@ -231,7 +231,7 @@ export class ElementEditor extends HTMLElement {
231
231
  setDirty() {
232
232
  if (this.hasEditors) {
233
233
  this.dirty = true
234
- window.onbeforeunload = () => Alchemy.t("page_dirty_notice")
234
+ window.onbeforeunload = (event) => event.preventDefault()
235
235
  }
236
236
  }
237
237
 
@@ -24,6 +24,7 @@ import "alchemy_admin/components/select"
24
24
  import "alchemy_admin/components/spinner"
25
25
  import "alchemy_admin/components/tags_autocomplete"
26
26
  import "alchemy_admin/components/tinymce"
27
+ import "alchemy_admin/components/update_check"
27
28
 
28
29
  await Promise.race([
29
30
  // Load all global custom elements
@@ -1,4 +1,5 @@
1
1
  import { AlchemyHTMLElement } from "alchemy_admin/components/alchemy_html_element"
2
+ import { setupSelectLocale } from "alchemy_admin/i18n"
2
3
 
3
4
  export class RemoteSelect extends AlchemyHTMLElement {
4
5
  static properties = {
@@ -9,7 +10,9 @@ export class RemoteSelect extends AlchemyHTMLElement {
9
10
  url: { default: "" }
10
11
  }
11
12
 
12
- connected() {
13
+ async connected() {
14
+ await setupSelectLocale()
15
+
13
16
  this.input.classList.add("alchemy_selectbox")
14
17
 
15
18
  $(this.input)
@@ -1,5 +1,9 @@
1
+ import { setupSelectLocale } from "alchemy_admin/i18n"
2
+
1
3
  class TagsAutocomplete extends HTMLElement {
2
- connectedCallback() {
4
+ async connectedCallback() {
5
+ await setupSelectLocale()
6
+
3
7
  this.classList.add("autocomplete_tag_list")
4
8
  $(this.input).select2(this.select2Config)
5
9
  }
@@ -76,8 +76,10 @@ class Tinymce extends AlchemyHTMLElement {
76
76
  this.getElementsByTagName("alchemy-spinner")[0].remove()
77
77
 
78
78
  // event listener to mark the editor as dirty
79
- editor.on("dirty", () => this.elementEditor.setDirty())
80
- editor.on("click", () => this.elementEditor.onClickElement(false))
79
+ if (this.elementEditor) {
80
+ editor.on("dirty", () => this.elementEditor.setDirty())
81
+ editor.on("click", () => this.elementEditor.onClickElement(false))
82
+ }
81
83
  })
82
84
  })
83
85
  }