alchemy_cms 7.4.5 → 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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -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/picture_descriptions_controller.rb +5 -1
  28. data/app/controllers/alchemy/admin/pictures_controller.rb +10 -5
  29. data/app/controllers/alchemy/admin/resources_controller.rb +16 -106
  30. data/app/controllers/alchemy/attachments_controller.rb +43 -14
  31. data/app/controllers/alchemy/messages_controller.rb +1 -1
  32. data/app/controllers/alchemy/pages_controller.rb +7 -2
  33. data/app/controllers/concerns/alchemy/admin/picture_descriptions_form_helper.rb +16 -0
  34. data/app/controllers/concerns/alchemy/admin/resource_filter.rb +92 -0
  35. data/app/decorators/alchemy/element_editor.rb +5 -48
  36. data/app/decorators/alchemy/ingredient_editor.rb +3 -53
  37. data/app/helpers/alchemy/admin/base_helper.rb +14 -84
  38. data/app/helpers/alchemy/admin/elements_helper.rb +4 -4
  39. data/app/helpers/alchemy/admin/pages_helper.rb +1 -1
  40. data/app/helpers/alchemy/base_helper.rb +0 -30
  41. data/app/helpers/alchemy/elements_block_helper.rb +0 -14
  42. data/app/helpers/alchemy/pages_helper.rb +1 -1
  43. data/{lib → app/helpers}/alchemy/resources_helper.rb +5 -45
  44. data/app/javascript/alchemy_admin/components/action.js +4 -0
  45. data/app/javascript/alchemy_admin/components/alchemy_html_element.js +3 -3
  46. data/app/javascript/alchemy_admin/components/datepicker.js +10 -2
  47. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +7 -7
  48. data/app/javascript/alchemy_admin/components/element_editor.js +1 -1
  49. data/app/javascript/alchemy_admin/components/growl.js +1 -0
  50. data/app/javascript/alchemy_admin/components/index.js +1 -0
  51. data/app/javascript/alchemy_admin/components/remote_select.js +4 -1
  52. data/app/javascript/alchemy_admin/components/tags_autocomplete.js +5 -1
  53. data/app/javascript/alchemy_admin/components/tinymce.js +4 -2
  54. data/app/javascript/alchemy_admin/components/update_check.js +42 -0
  55. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +15 -8
  56. data/app/javascript/alchemy_admin/components/uploader/progress.js +12 -6
  57. data/app/javascript/alchemy_admin/components/uploader.js +4 -2
  58. data/app/javascript/alchemy_admin/confirm_dialog.js +27 -57
  59. data/app/javascript/alchemy_admin/dirty.js +3 -2
  60. data/app/javascript/alchemy_admin/i18n.js +15 -16
  61. data/app/javascript/alchemy_admin/initializer.js +1 -49
  62. data/app/javascript/alchemy_admin/utils/ajax.js +51 -44
  63. data/app/javascript/alchemy_admin.js +3 -8
  64. data/app/models/alchemy/admin/filters/base.rb +38 -0
  65. data/app/models/alchemy/admin/filters/checkbox.rb +24 -0
  66. data/app/models/alchemy/admin/filters/datepicker.rb +53 -0
  67. data/app/models/alchemy/admin/filters/select.rb +70 -0
  68. data/app/models/alchemy/admin/resource_name.rb +27 -0
  69. data/app/models/alchemy/attachment.rb +51 -34
  70. data/app/models/alchemy/base_record.rb +2 -0
  71. data/app/models/alchemy/element/definitions.rb +1 -1
  72. data/app/models/alchemy/element/element_ingredients.rb +6 -6
  73. data/app/models/alchemy/element/presenters.rb +3 -12
  74. data/app/models/alchemy/element.rb +9 -27
  75. data/app/models/alchemy/element_definition.rb +160 -0
  76. data/app/models/alchemy/ingredient.rb +10 -43
  77. data/app/models/alchemy/ingredient_definition.rb +134 -0
  78. data/app/models/alchemy/ingredient_validator.rb +7 -3
  79. data/app/models/alchemy/ingredients/number.rb +19 -0
  80. data/app/models/alchemy/language.rb +0 -14
  81. data/app/models/alchemy/message.rb +3 -7
  82. data/app/models/alchemy/node.rb +1 -1
  83. data/app/models/alchemy/page/{page_layouts.rb → definitions.rb} +12 -19
  84. data/app/models/alchemy/page/fixed_attributes.rb +1 -1
  85. data/app/models/alchemy/page/page_elements.rb +13 -14
  86. data/app/models/alchemy/page/page_natures.rb +7 -7
  87. data/app/models/alchemy/page/page_scopes.rb +1 -1
  88. data/app/models/alchemy/page.rb +11 -33
  89. data/app/models/alchemy/page_definition.rb +115 -0
  90. data/app/models/alchemy/picture.rb +69 -79
  91. data/app/models/alchemy/picture_variant.rb +115 -5
  92. data/{lib → app/models}/alchemy/resource.rb +4 -18
  93. data/{lib → app/models}/alchemy/searchable_resource.rb +15 -0
  94. data/app/models/alchemy/site/layout.rb +5 -5
  95. data/app/models/alchemy/site.rb +0 -15
  96. data/app/models/alchemy/storage_adapter/active_storage/attachment_url.rb +41 -0
  97. data/app/models/alchemy/storage_adapter/active_storage/picture_url.rb +55 -0
  98. data/app/models/alchemy/storage_adapter/active_storage/preprocessor.rb +40 -0
  99. data/app/models/alchemy/storage_adapter/active_storage.rb +173 -0
  100. data/app/models/alchemy/{attachment/url.rb → storage_adapter/dragonfly/attachment_url.rb} +12 -12
  101. data/app/models/alchemy/{picture/url.rb → storage_adapter/dragonfly/picture_url.rb} +28 -12
  102. data/app/models/alchemy/{picture → storage_adapter/dragonfly}/preprocessor.rb +4 -4
  103. data/app/models/alchemy/storage_adapter/dragonfly.rb +183 -0
  104. data/app/models/alchemy/storage_adapter.rb +74 -0
  105. data/app/models/concerns/alchemy/picture_thumbnails.rb +19 -6
  106. data/app/serializers/alchemy/element_serializer.rb +0 -1
  107. data/app/services/alchemy/dragonfly_to_image_processing.rb +100 -0
  108. data/app/stylesheets/alchemy/_defaults.scss +3 -0
  109. data/app/stylesheets/alchemy/_extends.scss +69 -0
  110. data/app/{assets/stylesheets → stylesheets}/alchemy/_mixins.scss +36 -49
  111. data/app/stylesheets/alchemy/_variables.scss +5 -0
  112. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/archive.scss +20 -37
  113. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/base.scss +16 -14
  114. data/app/stylesheets/alchemy/admin/buttons.scss +160 -0
  115. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/clipboard.scss +2 -2
  116. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dashboard.scss +13 -16
  117. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dialogs.scss +23 -16
  118. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/elements.scss +150 -105
  119. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/errors.scss +5 -5
  120. data/app/stylesheets/alchemy/admin/filters.scss +58 -0
  121. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flatpickr.scss +53 -60
  122. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/form_fields.scss +21 -7
  123. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/forms.scss +31 -19
  124. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/frame.scss +20 -16
  125. data/app/stylesheets/alchemy/admin/hints.scss +5 -0
  126. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/icons.scss +10 -1
  127. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/image_library.scss +10 -8
  128. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/images.scss +1 -1
  129. data/app/stylesheets/alchemy/admin/labels.scss +5 -0
  130. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/lists.scss +3 -3
  131. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/navigation.scss +61 -55
  132. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/nodes.scss +21 -18
  133. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/notices.scss +18 -18
  134. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/page-select.scss +2 -2
  135. data/app/stylesheets/alchemy/admin/pagination.scss +144 -0
  136. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/preview_window.scss +8 -6
  137. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/print.scss +1 -1
  138. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/resource_info.scss +8 -5
  139. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/search.scss +9 -6
  140. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/selects.scss +49 -37
  141. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/shoelace.scss +5 -6
  142. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/sitemap.scss +38 -33
  143. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tables.scss +6 -4
  144. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tags.scss +6 -4
  145. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/toolbar.scss +12 -6
  146. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/typography.scss +2 -2
  147. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/upload.scss +7 -5
  148. data/app/stylesheets/alchemy/admin.scss +44 -0
  149. data/app/stylesheets/alchemy/custom-properties.css +244 -0
  150. data/app/stylesheets/alchemy/welcome.scss +75 -0
  151. data/app/{assets/stylesheets → stylesheets}/tinymce/skins/content/alchemy/content.scss +8 -9
  152. data/app/stylesheets/tinymce/skins/ui/alchemy/content.scss +1 -0
  153. data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/skin.scss +133 -136
  154. data/app/views/alchemy/admin/attachments/_files_list.html.erb +2 -2
  155. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
  156. data/app/views/alchemy/admin/{elements/_clipboard_button.html.erb → clipboard/_button.html.erb} +3 -5
  157. data/app/views/alchemy/admin/clipboard/_update_nested_element_button.turbo_stream.erb +11 -0
  158. data/app/views/alchemy/admin/clipboard/clear.turbo_stream.erb +4 -0
  159. data/app/views/alchemy/admin/clipboard/index.html.erb +15 -13
  160. data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +18 -0
  161. data/app/views/alchemy/admin/clipboard/remove.turbo_stream.erb +9 -0
  162. data/app/views/alchemy/admin/dashboard/info.html.erb +17 -31
  163. data/app/views/alchemy/admin/elements/_element.html.erb +4 -8
  164. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  165. data/app/views/alchemy/admin/elements/_header.html.erb +1 -0
  166. data/app/views/alchemy/admin/elements/_toolbar.html.erb +4 -6
  167. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +2 -1
  168. data/app/views/alchemy/admin/elements/index.html.erb +2 -2
  169. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +3 -16
  170. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +0 -9
  171. data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
  172. data/app/views/alchemy/admin/languages/_table.html.erb +1 -1
  173. data/app/views/alchemy/admin/languages/index.html.erb +5 -2
  174. data/app/views/alchemy/admin/layoutpages/index.html.erb +1 -12
  175. data/app/views/alchemy/admin/pages/_form.html.erb +2 -2
  176. data/app/views/alchemy/admin/pages/_page.html.erb +2 -3
  177. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -15
  178. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  179. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +9 -12
  180. data/app/views/alchemy/admin/partials/_search_form.html.erb +4 -9
  181. data/app/views/alchemy/admin/picture_descriptions/_form.html.erb +5 -7
  182. data/app/views/alchemy/admin/picture_descriptions/edit.html.erb +2 -2
  183. data/app/views/alchemy/admin/pictures/_archive.html.erb +4 -7
  184. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +2 -1
  185. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -1
  186. data/app/views/alchemy/admin/pictures/_form.html.erb +2 -2
  187. data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +21 -13
  188. data/app/views/alchemy/admin/pictures/index.html.erb +2 -7
  189. data/app/views/alchemy/admin/resources/_applied_filters.html.erb +8 -0
  190. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +11 -21
  191. data/app/views/alchemy/admin/resources/_pagination.html.erb +6 -0
  192. data/app/views/alchemy/admin/resources/_per_page_select.html.erb +4 -2
  193. data/app/views/alchemy/admin/resources/_resource_table.html.erb +1 -1
  194. data/app/views/alchemy/admin/resources/_table_header.html.erb +1 -15
  195. data/app/views/alchemy/admin/sites/index.html.erb +5 -1
  196. data/app/views/alchemy/admin/styleguide/index.html.erb +8 -0
  197. data/app/views/alchemy/admin/tags/index.html.erb +1 -1
  198. data/app/views/alchemy/admin/tinymce/_setup.html.erb +7 -7
  199. data/app/{javascript/alchemy_admin/locales/en.js → views/alchemy/admin/translations/_en.js} +5 -2
  200. data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
  201. data/app/views/alchemy/admin/uploader/_setup.html.erb +4 -4
  202. data/app/views/alchemy/base/500.turbo_stream.erb +3 -0
  203. data/app/views/alchemy/base/redirect.js.erb +1 -1
  204. data/app/views/alchemy/ingredients/_number_editor.html.erb +24 -0
  205. data/app/views/alchemy/no_index.html.erb +31 -0
  206. data/app/views/alchemy/welcome.html.erb +12 -10
  207. data/app/views/kaminari/alchemy/_first_page.html.erb +5 -3
  208. data/app/views/kaminari/alchemy/_last_page.html.erb +5 -3
  209. data/app/views/kaminari/alchemy/_next_page.html.erb +5 -3
  210. data/app/views/kaminari/alchemy/_paginator.html.erb +18 -13
  211. data/app/views/kaminari/alchemy/_prev_page.html.erb +5 -3
  212. data/app/views/layouts/alchemy/admin.html.erb +5 -9
  213. data/bun.lockb +0 -0
  214. data/bundles/remixicon.mjs +153 -0
  215. data/config/alchemy/config.yml +3 -2
  216. data/config/initializers/dragonfly.rb +0 -1
  217. data/config/initializers/mime_types.rb +1 -0
  218. data/config/locales/alchemy.en.yml +32 -14
  219. data/config/routes.rb +0 -2
  220. data/db/migrate/20250626160259_add_unique_index_to_picture_descriptions.rb +7 -0
  221. data/eslint.config.js +2 -1
  222. data/lib/alchemy/admin/preview_url.rb +4 -5
  223. data/lib/alchemy/cache_digests/template_tracker.rb +6 -9
  224. data/lib/alchemy/config_missing.rb +14 -0
  225. data/lib/alchemy/configuration/base_option.rb +24 -0
  226. data/lib/alchemy/configuration/boolean_option.rb +16 -0
  227. data/lib/alchemy/configuration/class_option.rb +15 -0
  228. data/lib/alchemy/configuration/class_set_option.rb +46 -0
  229. data/lib/alchemy/configuration/integer_list_option.rb +13 -0
  230. data/lib/alchemy/configuration/integer_option.rb +12 -0
  231. data/lib/alchemy/configuration/list_option.rb +22 -0
  232. data/lib/alchemy/configuration/regexp_option.rb +11 -0
  233. data/lib/alchemy/configuration/string_list_option.rb +13 -0
  234. data/lib/alchemy/configuration/string_option.rb +11 -0
  235. data/lib/alchemy/configuration.rb +115 -0
  236. data/lib/alchemy/configuration_methods.rb +3 -1
  237. data/lib/alchemy/configurations/default_language.rb +12 -0
  238. data/lib/alchemy/configurations/default_site.rb +10 -0
  239. data/lib/alchemy/configurations/format_matchers.rb +11 -0
  240. data/lib/alchemy/configurations/mailer.rb +16 -0
  241. data/lib/alchemy/configurations/main.rb +216 -0
  242. data/lib/alchemy/configurations/preview.rb +32 -0
  243. data/lib/alchemy/configurations/sitemap.rb +10 -0
  244. data/lib/alchemy/configurations/uploader.rb +34 -0
  245. data/lib/alchemy/engine.rb +65 -17
  246. data/lib/alchemy/hints.rb +3 -7
  247. data/lib/alchemy/on_page_layout.rb +2 -2
  248. data/lib/alchemy/propshaft/tinymce_asset.rb +15 -0
  249. data/lib/alchemy/seeder.rb +2 -2
  250. data/lib/alchemy/tasks/usage.rb +4 -4
  251. data/lib/alchemy/test_support/config_stubbing.rb +1 -7
  252. data/lib/alchemy/test_support/factories/attachment_factory.rb +13 -2
  253. data/lib/alchemy/test_support/factories/language_factory.rb +1 -1
  254. data/lib/alchemy/test_support/factories/page_factory.rb +2 -3
  255. data/lib/alchemy/test_support/factories/picture_factory.rb +30 -2
  256. data/lib/alchemy/test_support/factories/site_factory.rb +2 -2
  257. data/lib/alchemy/test_support/having_crop_action_examples.rb +2 -2
  258. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +80 -26
  259. data/lib/alchemy/test_support/shared_ingredient_examples.rb +5 -5
  260. data/lib/alchemy/upgrader/.keep +0 -0
  261. data/lib/alchemy/upgrader/eight_zero.rb +14 -0
  262. data/lib/alchemy/upgrader.rb +33 -20
  263. data/lib/alchemy/version.rb +1 -1
  264. data/lib/alchemy.rb +192 -170
  265. data/lib/alchemy_cms.rb +1 -7
  266. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +0 -3
  267. data/lib/generators/alchemy/install/files/_article.html.erb +6 -4
  268. data/lib/generators/alchemy/install/files/alchemy.en.yml +22 -3
  269. data/lib/generators/alchemy/install/files/application.html.erb +5 -0
  270. data/lib/generators/alchemy/install/install_generator.rb +5 -14
  271. data/lib/generators/alchemy/install/templates/alchemy.rb.tt +196 -0
  272. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +0 -1
  273. data/lib/generators/alchemy/install/templates/elements.yml.tt +3 -1
  274. data/lib/generators/alchemy/install/templates/menus.yml.tt +1 -1
  275. data/lib/generators/alchemy/install/templates/page_layouts.yml.tt +2 -2
  276. data/lib/generators/alchemy/page_layouts/page_layouts_generator.rb +2 -2
  277. data/lib/tasks/alchemy/assets.rake +14 -0
  278. data/lib/tasks/alchemy/upgrade.rake +12 -47
  279. data/vendor/javascript/tinymce.min.js +1 -1
  280. data/vitest.config.js +21 -0
  281. metadata +184 -180
  282. data/app/assets/builds/alchemy/admin/page-select.css.map +0 -1
  283. data/app/assets/builds/alchemy/admin/print.css.map +0 -1
  284. data/app/assets/builds/alchemy/admin.css.map +0 -1
  285. data/app/assets/builds/alchemy/custom-properties.css.map +0 -1
  286. data/app/assets/builds/alchemy/welcome.css.map +0 -1
  287. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +0 -1
  288. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css.map +0 -1
  289. data/app/assets/javascripts/alchemy/admin.js +0 -10
  290. data/app/assets/stylesheets/alchemy/_defaults.scss +0 -3
  291. data/app/assets/stylesheets/alchemy/_deprecated_variables.scss +0 -45
  292. data/app/assets/stylesheets/alchemy/_deprecation.scss +0 -17
  293. data/app/assets/stylesheets/alchemy/_extends.scss +0 -62
  294. data/app/assets/stylesheets/alchemy/_variables.scss +0 -201
  295. data/app/assets/stylesheets/alchemy/admin/buttons.scss +0 -124
  296. data/app/assets/stylesheets/alchemy/admin/hints.scss +0 -5
  297. data/app/assets/stylesheets/alchemy/admin/labels.scss +0 -3
  298. data/app/assets/stylesheets/alchemy/admin/pagination.scss +0 -92
  299. data/app/assets/stylesheets/alchemy/admin.scss +0 -42
  300. data/app/assets/stylesheets/alchemy/custom-properties.css +0 -98
  301. data/app/assets/stylesheets/alchemy/welcome.scss +0 -57
  302. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.css +0 -711
  303. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.css +0 -705
  304. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.min.css +0 -7
  305. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.min.css +0 -7
  306. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.css +0 -29
  307. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.min.css +0 -7
  308. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.css +0 -677
  309. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.min.css +0 -7
  310. data/app/controllers/alchemy/elements_controller.rb +0 -32
  311. data/app/models/alchemy/element/dom_id.rb +0 -31
  312. data/app/models/alchemy/picture/calculations.rb +0 -49
  313. data/app/models/alchemy/picture/transformations.rb +0 -115
  314. data/app/views/alchemy/admin/attachments/destroy.js.erb +0 -1
  315. data/app/views/alchemy/admin/clipboard/clear.js.erb +0 -3
  316. data/app/views/alchemy/admin/clipboard/insert.js.erb +0 -29
  317. data/app/views/alchemy/admin/clipboard/remove.js.erb +0 -10
  318. data/app/views/alchemy/admin/resources/_filter.html.erb +0 -12
  319. data/app/views/alchemy/admin/resources/_resource.html.erb +0 -34
  320. data/app/views/alchemy/admin/resources/_table.html.erb +0 -29
  321. data/app/views/alchemy/elements/show.html.erb +0 -1
  322. data/app/views/alchemy/elements/show.js.erb +0 -1
  323. data/app/views/alchemy/ingredients/_audio_view.html.erb +0 -1
  324. data/app/views/alchemy/ingredients/_boolean_view.html.erb +0 -1
  325. data/app/views/alchemy/ingredients/_datetime_view.html.erb +0 -3
  326. data/app/views/alchemy/ingredients/_file_view.html.erb +0 -4
  327. data/app/views/alchemy/ingredients/_headline_view.html.erb +0 -4
  328. data/app/views/alchemy/ingredients/_html_view.html.erb +0 -1
  329. data/app/views/alchemy/ingredients/_link_view.html.erb +0 -4
  330. data/app/views/alchemy/ingredients/_node_view.html.erb +0 -1
  331. data/app/views/alchemy/ingredients/_page_view.html.erb +0 -1
  332. data/app/views/alchemy/ingredients/_picture_view.html.erb +0 -4
  333. data/app/views/alchemy/ingredients/_richtext_view.html.erb +0 -3
  334. data/app/views/alchemy/ingredients/_select_view.html.erb +0 -1
  335. data/app/views/alchemy/ingredients/_text_view.html.erb +0 -4
  336. data/app/views/alchemy/ingredients/_video_view.html.erb +0 -3
  337. data/babel.config.js +0 -12
  338. data/config/initializers/assets.rb +0 -4
  339. data/lib/alchemy/config.rb +0 -114
  340. data/lib/alchemy/element_definition.rb +0 -73
  341. data/lib/alchemy/page_layout.rb +0 -73
  342. data/lib/alchemy/resource_filter.rb +0 -40
  343. data/lib/alchemy/upgrader/seven_point_four.rb +0 -26
  344. data/lib/alchemy/upgrader/seven_point_three.rb +0 -52
  345. data/lib/generators/alchemy/ingredient/templates/view.html.erb +0 -1
  346. data/lib/generators/alchemy/install/files/alchemy_admin.js +0 -1
  347. data/lib/generators/alchemy/install/files/all.js +0 -11
  348. data/lib/generators/alchemy/install/files/article.css +0 -25
  349. data/vendor/assets/images/remixicon.symbol.svg +0 -11
  350. /data/app/{assets/stylesheets → stylesheets}/alchemy/_fonts.scss +0 -0
  351. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachment-select.scss +0 -0
  352. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachments.scss +0 -0
  353. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flash.scss +0 -0
  354. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/list_filter.scss +0 -0
  355. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/node-select.scss +0 -0
  356. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/spinner.scss +0 -0
  357. /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/skintool.json +0 -0
  358. /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/fonts/tinymce-mobile.woff +0 -0
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext/string"
5
+
6
+ require "alchemy/configuration/boolean_option"
7
+ require "alchemy/configuration/class_option"
8
+ require "alchemy/configuration/class_set_option"
9
+ require "alchemy/configuration/integer_option"
10
+ require "alchemy/configuration/integer_list_option"
11
+ require "alchemy/configuration/regexp_option"
12
+ require "alchemy/configuration/string_list_option"
13
+ require "alchemy/configuration/string_option"
14
+
15
+ module Alchemy
16
+ class Configuration
17
+ def initialize(configuration_hash = {})
18
+ set(configuration_hash)
19
+ end
20
+
21
+ def set(configuration_hash)
22
+ configuration_hash.each do |key, value|
23
+ send(:"#{key}=", value)
24
+ end
25
+ end
26
+
27
+ alias_method :get, :send
28
+ alias_method :[], :get
29
+
30
+ def show = self
31
+
32
+ def fetch(key, default = nil)
33
+ get(key) || default
34
+ end
35
+
36
+ def set_from_yaml(file)
37
+ set(
38
+ YAML.safe_load(
39
+ ERB.new(File.read(file)).result,
40
+ permitted_classes: YAML_PERMITTED_CLASSES,
41
+ aliases: true
42
+ ) || {}
43
+ )
44
+ end
45
+
46
+ def to_h
47
+ self.class.defined_options.map do |option|
48
+ [option, send(option)]
49
+ end.concat(
50
+ self.class.defined_configurations.map do |configuration|
51
+ [configuration, send(configuration).to_h]
52
+ end
53
+ ).to_h
54
+ end
55
+
56
+ class << self
57
+ def defined_configurations = []
58
+
59
+ def defined_options = []
60
+
61
+ def configuration(name, configuration_class)
62
+ # The defined configurations on a class are all those defined directly on
63
+ # that class as well as those defined on ancestors.
64
+ # We store these as a class instance variable on each class which has a
65
+ # configuration. super() collects configurations defined on ancestors.
66
+ singleton_configurations = (@defined_singleton_configurations ||= [])
67
+ singleton_configurations << name.to_sym
68
+
69
+ define_singleton_method :defined_configurations do
70
+ super() + singleton_configurations
71
+ end
72
+
73
+ define_method(name) do
74
+ unless instance_variable_get(:"@#{name}")
75
+ send(:"#{name}=", configuration_class.new)
76
+ end
77
+ instance_variable_get(:"@#{name}")
78
+ end
79
+
80
+ define_method(:"#{name}=") do |value|
81
+ if value.is_a?(configuration_class)
82
+ instance_variable_set(:"@#{name}", value)
83
+ else
84
+ send(name).set(value)
85
+ end
86
+ end
87
+ end
88
+
89
+ def option(name, type, default: nil, **args)
90
+ klass = "Alchemy::Configuration::#{type.to_s.camelize}Option".constantize
91
+ # The defined options on a class are all those defined directly on
92
+ # that class as well as those defined on ancestors.
93
+ # We store these as a class instance variable on each class which has a
94
+ # option. super() collects options defined on ancestors.
95
+ singleton_options = (@defined_singleton_options ||= [])
96
+ singleton_options << name.to_sym
97
+
98
+ define_singleton_method :defined_options do
99
+ super() + singleton_options
100
+ end
101
+
102
+ define_method(name) do
103
+ unless instance_variable_defined?(:"@#{name}")
104
+ send(:"#{name}=", default)
105
+ end
106
+ instance_variable_get(:"@#{name}").value
107
+ end
108
+
109
+ define_method(:"#{name}=") do |value|
110
+ instance_variable_set(:"@#{name}", klass.new(value:, name:, **args))
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -12,9 +12,11 @@ module Alchemy
12
12
  #
13
13
  # Config file is in +config/alchemy/config.yml+
14
14
  #
15
+ # @deprecated - Use Alchemy.config.get instead
15
16
  def configuration(name)
16
- Config.get(name)
17
+ Alchemy.config.get(name)
17
18
  end
19
+ deprecate configuration: "Alchemy.config.get", deprecator: Alchemy::Deprecation
18
20
 
19
21
  # Returns true if more than one language is published on current site.
20
22
  #
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class DefaultLanguage < Alchemy::Configuration
6
+ option :name, :string, default: "English"
7
+ option :code, :string, default: "en"
8
+ option :page_layout, :string, default: "index"
9
+ option :frontpage_name, :string, default: "Index"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class DefaultSite < Alchemy::Configuration
6
+ option :name, :string, default: "Default Site"
7
+ option :host, :string, default: "*"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class FormatMatchers < Alchemy::Configuration
6
+ option :email, :regexp, default: /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
7
+ option :url, :regexp, default: /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
8
+ option :link_url, :regexp, default: /^(tel:|mailto:|\/|[a-z]+:\/\/)/
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class Mailer < Alchemy::Configuration
6
+ option :page_layout_name, :string, default: "contact"
7
+ option :forward_to_page, :boolean, default: false
8
+ option :mail_success_page, :string, default: "thanks"
9
+ option :mail_from, :string, default: "your.mail@your-domain.com"
10
+ option :mail_to, :string, default: "your.mail@your-domain.com"
11
+ option :subject, :string, default: "A new contact form message"
12
+ option :fields, :string_list, default: %w[salutation firstname lastname address zip city phone email message]
13
+ option :validate_fields, :string_list, default: %w[lastname email]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration"
4
+ require "alchemy/configurations/default_language"
5
+ require "alchemy/configurations/default_site"
6
+ require "alchemy/configurations/format_matchers"
7
+ require "alchemy/configurations/mailer"
8
+ require "alchemy/configurations/preview"
9
+ require "alchemy/configurations/sitemap"
10
+ require "alchemy/configurations/uploader"
11
+ require "alchemy/deprecation"
12
+
13
+ module Alchemy
14
+ module Configurations
15
+ class Main < Alchemy::Configuration
16
+ # == This is the global Alchemy configuration class
17
+
18
+ # === Auto Log Out Time
19
+ #
20
+ # The amount of time of inactivity in minutes after which the user is kicked out of his current session.
21
+ #
22
+ # NOTE: This is only active in production environments
23
+ #
24
+ option :auto_logout_time, :integer, default: 30
25
+
26
+ # === Page caching
27
+ #
28
+ # Enable/Disable page caching globally.
29
+ #
30
+ # NOTE: You can enable/disable page caching for single Alchemy::Definitions in the page_layout.yml file.
31
+ #
32
+ option :cache_pages, :boolean, default: true
33
+
34
+ # === Sitemap
35
+ #
36
+ # Alchemy creates a XML, Google compatible, sitemap for you.
37
+ #
38
+ # The url is: http://your-domain.tld/sitemap.xml
39
+ #
40
+ # ==== Config Options:
41
+ #
42
+ # show_root [Boolean] # Show language root page in sitemap?
43
+ # show_flag [Boolean] # Enables the Checkbox in Page#update overlay. So your customer can set the visibility of pages in the sitemap.
44
+ configuration :sitemap, Sitemap
45
+
46
+ # === Default items per page in admin views
47
+ #
48
+ # In Alchemy's Admin, change how many items you would get shown per page by Kaminari
49
+ option :items_per_page, :integer, default: 15
50
+
51
+ # === Preview window URL configuration
52
+ #
53
+ # By default Alchemy uses its internal page preview renderer,
54
+ # but you can configure it to be any URL instead.
55
+ #
56
+ # Basic Auth is supported.
57
+ #
58
+ # preview:
59
+ # host: https://www.my-static-site.com
60
+ # auth:
61
+ # username: <%= ENV["BASIC_AUTH_USERNAME"] %>
62
+ # password: <%= ENV["BASIC_AUTH_PASSWORD"] %>
63
+ #
64
+ # Preview config per site is supported as well.
65
+ #
66
+ # preview:
67
+ # My site name:
68
+ # host: https://www.my-static-site.com
69
+ # auth:
70
+ # username: <%= ENV["BASIC_AUTH_USERNAME"] %>
71
+ # password: <%= ENV["BASIC_AUTH_PASSWORD"] %>
72
+ #
73
+ configuration :preview, Preview
74
+
75
+ # === Picture rendering settings
76
+ #
77
+ # Alchemy uses Dragonfly to render images. Settings for image rendering are specific to elements and are defined in elements.yml
78
+ #
79
+ # Example:
80
+ # - name: some_element
81
+ # ingredients:
82
+ # - role: some_picture
83
+ # type: Picture
84
+ # settings:
85
+ # hint: true
86
+ # crop: true # turns on image cropping
87
+ # size: '500x500' # image will be cropped to this size
88
+ #
89
+ # See http://markevans.github.com/dragonfly for further info.
90
+ #
91
+ # ==== Global Options:
92
+ #
93
+ # output_image_quality [Integer] # If image gets rendered as JPG or WebP this is the quality setting for it. (Default 85)
94
+ # preprocess_image_resize [String] # Use this option to resize images to the given size when they are uploaded to the image library. Downsizing example: '1000x1000>' (Default nil)
95
+ # image_output_format [String] # The global image output format setting. (Default +original+)
96
+ #
97
+ # NOTE: You can always override the output format in the settings of your ingredients in elements.yml, I.E. {format: 'gif'}
98
+ #
99
+ option :output_image_quality, :integer, default: 85
100
+ alias_method :output_image_jpg_quality, :output_image_quality
101
+ deprecate output_image_jpg_quality: :output_image_quality, deprecator: Alchemy::Deprecation
102
+ alias_method :output_image_jpg_quality=, :output_image_quality=
103
+ deprecate "output_image_jpg_quality=": :output_image_quality=, deprecator: Alchemy::Deprecation
104
+ option :preprocess_image_resize, :string
105
+ option :image_output_format, :string, default: "original"
106
+ option :sharpen_images, :boolean, default: false
107
+
108
+ # This is used by the seeder to create the default site.
109
+ configuration :default_site, DefaultSite
110
+
111
+ # This is the default language when seeding.
112
+ configuration :default_language, DefaultLanguage
113
+
114
+ # === Mailer Settings:
115
+ #
116
+ # To send emails via contact forms, you can create your form fields here and set which fields are to be validated.
117
+ #
118
+ # === Validating fields:
119
+ #
120
+ # Pass the field name as a symbol and a message_id (will be translated) to :validate_fields:
121
+ #
122
+ # ==== Options:
123
+ #
124
+ # page_layout_name: [String] # A +Alchemy::PageDefinition+ name. Used to render the contactform on a page with this layout.
125
+ # fields: [Array] # An Array of fieldnames.
126
+ # validate_fields: [Array] # An Array of fieldnames to be validated on presence.
127
+ #
128
+ # ==== Translating validation messages:
129
+ #
130
+ # The validation messages are passed through ::I18n.t so you can translate it in your language yml file.
131
+ #
132
+ # ==== Example:
133
+ #
134
+ # de:
135
+ # activemodel:
136
+ # attributes:
137
+ # alchemy/message:
138
+ # firstname: Vorname
139
+ #
140
+ configuration :mailer, Mailer
141
+
142
+ # === User roles
143
+ #
144
+ # You can add own user roles.
145
+ #
146
+ # Further documentation for the auth system used please visit:
147
+ #
148
+ # https://github.com/ryanb/cancan/wiki
149
+ #
150
+ # ==== Translating User roles
151
+ #
152
+ # Userroles can be translated inside your the language yml file under:
153
+ #
154
+ # alchemy:
155
+ # user_roles:
156
+ # rolename: Name of the role
157
+ #
158
+ option :user_roles, :string_list, default: %w[member author editor admin]
159
+
160
+ # === Uploader Settings
161
+ #
162
+ # upload_limit [Integer] # Set an amount of files upload limit of files which can be uploaded at once. Set 0 for unlimited.
163
+ # file_size_limit* [Integer] # Set a file size limit in mega bytes for a per file limit.
164
+ #
165
+ # *) Allow filetypes to upload. Pass * to allow all kind of files.
166
+ #
167
+ configuration :uploader, Uploader
168
+
169
+ # === Link Target Options
170
+ #
171
+ # Values for the link target selectbox inside the page link overlay.
172
+ # The value gets attached as a data-link-target attribute to the link.
173
+ #
174
+ # == Example:
175
+ #
176
+ # Open all links set to overlay inside an jQuery UI Dialog Window.
177
+ #
178
+ # jQuery(a[data-link-target="overlay"]).dialog();
179
+ #
180
+ option :link_target_options, :string_list, default: %w[blank]
181
+
182
+ # === Format matchers
183
+ #
184
+ # Named aliases for regular expressions that can be used in various places.
185
+ # The most common use case is the format validation of ingredients, or attribute validations of your individual models.
186
+ #
187
+ # == Example:
188
+ #
189
+ # validates_format_of :url, with: Alchemy.config.format_matchers.url
190
+ #
191
+ configuration :format_matchers, FormatMatchers
192
+
193
+ # The layout used for rendering the +alchemy/admin/pages#show+ action.
194
+ option :admin_page_preview_layout, :string, default: "application"
195
+
196
+ # The sizes for the preview size select in the page editor.
197
+ option :page_preview_sizes, :integer_list, default: [360, 640, 768, 1024, 1280, 1440]
198
+
199
+ # Enable full text search configuration
200
+ #
201
+ # It enables a searchable checkbox in the page form to toggle
202
+ # the searchable field. These information can used in a search
203
+ # plugin (e.g. https://github.com/AlchemyCMS/alchemy-pg_search).
204
+ #
205
+ # == Example
206
+ #
207
+ # # config/initializers/alchemy.rb
208
+ # Alchemy.config.page_searchable_checkbox = true
209
+ option :show_page_searchable_checkbox, :boolean, default: false
210
+
211
+ # The storage adapter for Pictures and Attachments
212
+ #
213
+ option :storage_adapter, :string, default: "dragonfly"
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class Preview < Alchemy::Configuration
6
+ class PreviewAuth < Alchemy::Configuration
7
+ option :username, :string
8
+ option :password, :string
9
+ end
10
+
11
+ attr_reader :per_site_configs
12
+
13
+ def initialize(configuration = {})
14
+ @per_site_configs = []
15
+ configuration = configuration.with_indifferent_access
16
+ configuration.except(:host, :site_name, :auth).keys.each do |site_name|
17
+ @per_site_configs << Preview.new(configuration[site_name].merge(site_name: site_name))
18
+ end
19
+ super(configuration.slice(:host, :site_name, :auth))
20
+ end
21
+
22
+ option :site_name, :string, default: "*"
23
+ option :host, :string
24
+
25
+ configuration :auth, PreviewAuth
26
+
27
+ def for_site(site)
28
+ per_site_configs.detect { _1.site_name == site.name } || self
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class Sitemap < Alchemy::Configuration
6
+ option :show_root, :boolean, default: true
7
+ option :show_flag, :boolean, default: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Configurations
5
+ class Uploader < Alchemy::Configuration
6
+ class AllowedFileTypes < Alchemy::Configuration
7
+ option :alchemy_attachments, :string_list, default: ["*"]
8
+ option :alchemy_pictures, :string_list, default: %w[jpg jpeg gif png svg webp]
9
+
10
+ def set(configuration_hash)
11
+ super(configuration_hash.transform_keys { transform_key(_1) })
12
+ end
13
+
14
+ def get(key)
15
+ super(transform_key(key))
16
+ end
17
+ alias_method :[], :get
18
+
19
+ private
20
+
21
+ def transform_key(key)
22
+ key.to_s.tr("/", "_")
23
+ end
24
+ end
25
+
26
+ # Number of files that can be uploaded at once
27
+ option :upload_limit, :integer, default: 50
28
+ # Megabytes
29
+ option :file_size_limit, :integer, default: 100
30
+
31
+ configuration :allowed_filetypes, AllowedFileTypes
32
+ end
33
+ end
34
+ end
@@ -16,13 +16,29 @@ module Alchemy
16
16
  end
17
17
  end
18
18
 
19
- initializer "alchemy.non_digest_assets" do
20
- NonStupidDigestAssets.whitelist += [/^tinymce\//]
19
+ initializer "alchemy.assets" do |app|
20
+ if defined?(Sprockets)
21
+ require_relative "../non_stupid_digest_assets"
22
+ NonStupidDigestAssets.whitelist += [/^tinymce\//]
23
+ app.config.assets.precompile << "alchemy_manifest.js"
24
+ end
21
25
  end
22
26
 
23
27
  initializer "alchemy.admin_stylesheets" do |app|
24
- Alchemy.admin_stylesheets.each do |stylesheet|
25
- app.config.assets.precompile << stylesheet
28
+ if defined?(Sprockets)
29
+ Alchemy.admin_stylesheets.each do |stylesheet|
30
+ app.config.assets.precompile << stylesheet
31
+ end
32
+ end
33
+ end
34
+
35
+ initializer "alchemy.propshaft" do |app|
36
+ if defined?(Propshaft)
37
+ if app.config.assets.server
38
+ # Monkey-patch Propshaft::Asset to enable access
39
+ # of TinyMCE assets without a hash digest.
40
+ require_relative "propshaft/tinymce_asset"
41
+ end
26
42
  end
27
43
  end
28
44
 
@@ -46,18 +62,18 @@ module Alchemy
46
62
  end
47
63
  end
48
64
 
49
- initializer "alchemy.watch_definition_changes" do |app|
50
- elements_reloader = app.config.file_watcher.new([ElementDefinition.definitions_file_path]) do
65
+ config.to_prepare do
66
+ elements_reloader = Rails.application.config.file_watcher.new([ElementDefinition.definitions_file_path]) do
51
67
  Rails.logger.info "[#{engine_name}] Reloading Element Definitions."
52
68
  ElementDefinition.reset!
53
69
  end
54
- page_layouts_reloader = app.config.file_watcher.new([PageLayout.layouts_file_path]) do
70
+ page_layouts_reloader = Rails.application.config.file_watcher.new([PageDefinition.layouts_file_path]) do
55
71
  Rails.logger.info "[#{engine_name}] Reloading Page Layouts."
56
- PageLayout.reset!
72
+ PageDefinition.reset!
57
73
  end
58
74
  [elements_reloader, page_layouts_reloader].each do |reloader|
59
- app.reloaders << reloader
60
- app.reloader.to_run do
75
+ Rails.application.reloaders << reloader
76
+ Rails.application.reloader.to_run do
61
77
  reloader.execute_if_updated
62
78
  end
63
79
  end
@@ -79,13 +95,36 @@ module Alchemy
79
95
  down_arrow: '<alchemy-icon name="arrow-down" size="1x"></alchemy-icon>'
80
96
  }
81
97
  end
98
+
99
+ ActiveSupport.on_load(:active_storage_blob) do
100
+ ActiveStorage::Blob.define_singleton_method(:ransackable_attributes) do |_auth_object|
101
+ %w[filename]
102
+ end
103
+ end
104
+ end
105
+
106
+ # Load Alchemy configuration from YAML files
107
+ # in config/alchemy/config.yml and config/alchemy/#{Rails.env}.config.yml
108
+ # if they exist.
109
+ # This has to be done before any app initializers are loaded, so that
110
+ # the configuration is available in all initializers.
111
+ initializer "alchemy.config_yml", before: :load_config_initializers do |app|
112
+ config_directory = Rails.root.join("config", "alchemy")
113
+ main_config = config_directory.join("config.yml")
114
+ env_specific_config = config_directory.join("#{Rails.env}.config.yml")
115
+ if File.exist?(main_config)
116
+ Alchemy.config.set_from_yaml(main_config)
117
+ end
118
+ if File.exist?(env_specific_config)
119
+ Alchemy.config.set_from_yaml(env_specific_config)
120
+ end
82
121
  end
83
122
 
84
123
  config.after_initialize do
85
124
  if Alchemy.user_class
86
125
  ActiveSupport.on_load(:active_record) do
87
126
  Alchemy.user_class.model_stamper
88
- Alchemy.user_class.stampable(stamper_class_name: Alchemy.user_class.name)
127
+ Alchemy.user_class.stampable(stamper_class_name: Alchemy.user_class_name)
89
128
  end
90
129
  end
91
130
 
@@ -96,14 +135,23 @@ module Alchemy
96
135
  end
97
136
  end
98
137
 
99
- initializer "alchemy.webp-mime_type" do
100
- # Rails does not know anything about webp even in 2022
101
- unless Mime::Type.lookup_by_extension(:webp)
102
- Mime::Type.register("image/webp", :webp)
103
- end
138
+ initializer "alchemy.webp-mime_type" do |app|
139
+ webp = "image/webp"
140
+
104
141
  # Dragonfly uses Rack to read the mime type and guess what
142
+ # Rack 3.0 has this included, but Rails 8 still allows Rack 2.2
105
143
  unless Rack::Mime::MIME_TYPES[".webp"]
106
- Rack::Mime::MIME_TYPES[".webp"] = "image/webp"
144
+ Rack::Mime::MIME_TYPES[".webp"] = webp
145
+ end
146
+
147
+ # ActiveStorage 7.2 adds support for webp, but we still support Rails 7.1
148
+ if app.config.active_storage
149
+ unless app.config.active_storage.web_image_content_types.include? webp
150
+ app.config.active_storage.web_image_content_types += [webp]
151
+ end
152
+ unless app.config.active_storage.content_types_allowed_inline.include? webp
153
+ app.config.active_storage.content_types_allowed_inline += [webp]
154
+ end
107
155
  end
108
156
  end
109
157
  end
data/lib/alchemy/hints.rb CHANGED
@@ -35,7 +35,7 @@ module Alchemy
35
35
  # @return String
36
36
  #
37
37
  def hint
38
- hint = definition[:hint]
38
+ hint = attributes[:hint]
39
39
  if hint == true
40
40
  Alchemy.t(hint_translation_attribute, scope: hint_translation_scope)
41
41
  else
@@ -43,9 +43,9 @@ module Alchemy
43
43
  end
44
44
  end
45
45
 
46
- # Returns true if the element has a hint defined
46
+ # Returns true if the definition has a hint defined
47
47
  def has_hint?
48
- !!definition[:hint]
48
+ !!attributes[:hint]
49
49
  end
50
50
 
51
51
  private
@@ -53,9 +53,5 @@ module Alchemy
53
53
  def hint_translation_attribute
54
54
  name
55
55
  end
56
-
57
- def hint_translation_scope
58
- "#{self.class.model_name.to_s.demodulize.downcase}_hints"
59
- end
60
56
  end
61
57
  end
@@ -9,7 +9,7 @@ module Alchemy
9
9
  # Pass a block or method name in which you have the +@page+ object available and can do
10
10
  # everything as if you were in a normal controller action.
11
11
  #
12
- # You can pass a +Alchemy::PageLayout+ name, an array of names, or +:all+ to
12
+ # You can pass a +Alchemy::PageDefinition+ name, an array of names, or +:all+ to
13
13
  # evaluate the callback on either some specific or all the pages.
14
14
  #
15
15
  # == Example:
@@ -56,7 +56,7 @@ module Alchemy
56
56
  # Pass a block or method name in which you have the +@page+ object available and can do
57
57
  # everything as if you were in a normal controller action.
58
58
  #
59
- # Pass a +Alchemy::PageLayout+ name, an array of names, or +:all+ to
59
+ # Pass a +Alchemy::PageDefinition+ name, an array of names, or +:all+ to
60
60
  # evaluate the callback on either some specific or all the pages.
61
61
  #
62
62
  def on_page_layout(page_layouts, callback = nil, &block)
@@ -0,0 +1,15 @@
1
+ require "propshaft/asset"
2
+
3
+ module Alchemy
4
+ module Propshaft
5
+ module TinymceAsset
6
+ # Allow TinyMCE assets to be accessed (in development mode) without a digest
7
+ def fresh?(digest)
8
+ super ||
9
+ (digest.blank? && logical_path.to_s.starts_with?("tinymce/"))
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ Propshaft::Asset.prepend Alchemy::Propshaft::TinymceAsset