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
@@ -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
@@ -116,7 +116,7 @@ module Alchemy
116
116
  # If no languages are present, create a default language based
117
117
  # on the host app's Alchemy configuration.
118
118
  def create_default_language!
119
- default_language = Alchemy::Config.get(:default_language)
119
+ default_language = Alchemy.config.default_language
120
120
  if default_language
121
121
  Alchemy::Language.create!(
122
122
  name: default_language["name"],
@@ -134,7 +134,7 @@ module Alchemy
134
134
  end
135
135
 
136
136
  def create_default_site!
137
- default_site = Alchemy::Config.get(:default_site)
137
+ default_site = Alchemy.config.default_site
138
138
  if default_site
139
139
  Alchemy::Site.create!(name: default_site["name"], host: default_site["host"])
140
140
  else
@@ -11,8 +11,8 @@ module Alchemy
11
11
  .group(:name)
12
12
  .order("count DESC, name ASC")
13
13
  .map { |e| {"name" => e.name, "count" => e.count} }
14
- Alchemy::Element.definitions.reject { |definition| res.map { |e| e["name"] }.include? definition["name"] }.sort_by { |d| d["name"] }.each do |definition|
15
- res << {"name" => definition["name"], "count" => 0}
14
+ Alchemy::Element.definitions.reject { |definition| res.map { |e| e["name"] }.include?(definition.name) }.sort_by(&:name).each do |definition|
15
+ res << {"name" => definition.name, "count" => 0}
16
16
  end
17
17
  res
18
18
  end
@@ -23,8 +23,8 @@ module Alchemy
23
23
  .group(:page_layout)
24
24
  .order("count DESC, page_layout ASC")
25
25
  .map { |p| {"page_layout" => p.page_layout, "count" => p.count} }
26
- Alchemy::PageLayout.all.reject { |page_layout| res.map { |p| p["page_layout"] }.include? page_layout["name"] }.sort_by { |d| d["name"] }.each do |page_layout|
27
- res << {"page_layout" => page_layout["name"], "count" => 0}
26
+ Alchemy::PageDefinition.all.reject { |page_layout| res.map { |p| p["page_layout"] }.include?(page_layout.name) }.sort_by(&:name).each do |page_layout|
27
+ res << {"page_layout" => page_layout.name, "count" => 0}
28
28
  end
29
29
  res
30
30
  end
@@ -17,13 +17,7 @@ module Alchemy
17
17
  # @param value [Object] The value you want to return instead of the original one
18
18
  #
19
19
  def stub_alchemy_config(key, value)
20
- allow(Alchemy::Config).to receive(:get) do |arg|
21
- if arg == key
22
- value
23
- else
24
- Alchemy::Config.show[arg.to_s]
25
- end
26
- end
20
+ allow(Alchemy.config).to receive(key).and_return(value)
27
21
  end
28
22
  end
29
23
  end
@@ -2,9 +2,20 @@
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :alchemy_attachment, class: "Alchemy::Attachment" do
5
- file do
6
- File.new(Alchemy::Engine.root.join("lib", "alchemy", "test_support", "fixtures", "image.png"))
5
+ transient do
6
+ file do
7
+ Rack::Test::UploadedFile.new(
8
+ Alchemy::Engine.root.join("lib", "alchemy", "test_support", "fixtures", "image.png")
9
+ )
10
+ end
7
11
  end
12
+
13
+ after(:build) do |attachment, acc|
14
+ if acc.file
15
+ attachment.file = acc.file
16
+ end
17
+ end
18
+
8
19
  name { "image" }
9
20
  file_name { "image.png" }
10
21
  end
@@ -6,7 +6,7 @@ FactoryBot.define do
6
6
  code { ::I18n.available_locales.first.to_s }
7
7
  default { true }
8
8
  frontpage_name { "Intro" }
9
- page_layout { Alchemy::Config.get(:default_language)["page_layout"] }
9
+ page_layout { Alchemy.config.default_language.page_layout }
10
10
 
11
11
  public { true }
12
12
 
@@ -12,7 +12,7 @@ FactoryBot.define do
12
12
 
13
13
  parent do
14
14
  Alchemy::Page.find_by(language_root: true, language: language) ||
15
- FactoryBot.create(:alchemy_page, :language_root, language: language)
15
+ FactoryBot.create(:alchemy_page, :public, :language_root, language: language)
16
16
  end
17
17
 
18
18
  # This speeds up creating of pages dramatically.
@@ -23,7 +23,6 @@ FactoryBot.define do
23
23
  name { language&.frontpage_name || "Intro" }
24
24
  page_layout { language&.page_layout || "index" }
25
25
  language_root { true }
26
- public_on { Time.current }
27
26
  parent { nil }
28
27
  end
29
28
 
@@ -41,7 +40,7 @@ FactoryBot.define do
41
40
  end
42
41
  after(:create) do |page|
43
42
  if page.autogenerate_elements
44
- page.definition["autogenerate"].each do |name|
43
+ page.definition.autogenerate.each do |name|
45
44
  create(
46
45
  :alchemy_element,
47
46
  name: name,
@@ -2,9 +2,37 @@
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :alchemy_picture, class: "Alchemy::Picture" do
5
- image_file do
6
- File.new(Alchemy::Engine.root.join("lib", "alchemy", "test_support", "fixtures", "image.png"))
5
+ transient do
6
+ image_file do
7
+ Rack::Test::UploadedFile.new(
8
+ Alchemy::Engine.root.join("lib", "alchemy", "test_support", "fixtures", "image.png")
9
+ )
10
+ end
7
11
  end
12
+
13
+ after(:build) do |picture, acc|
14
+ if acc.image_file
15
+ case Alchemy.storage_adapter.name
16
+ when :active_storage
17
+ filename = acc.image_file.original_filename
18
+ content_type = Marcel::MimeType.for(extension: File.extname(filename))
19
+ picture.image_file.attach(
20
+ io: acc.image_file.open,
21
+ filename:,
22
+ content_type:,
23
+ identify: false,
24
+ metadata: {
25
+ width: 1,
26
+ height: 1
27
+ }
28
+ )
29
+ when :dragonfly
30
+ picture.image_file = acc.image_file
31
+ picture.image_file_size = acc.image_file.size
32
+ end
33
+ end
34
+ end
35
+
8
36
  name { "image" }
9
37
  upload_hash { Time.current.hash }
10
38
  end
@@ -8,8 +8,8 @@ FactoryBot.define do
8
8
  trait :default do
9
9
  public { true }
10
10
 
11
- name { Alchemy::Config.get(:default_site)["name"] }
12
- host { Alchemy::Config.get(:default_site)["host"] }
11
+ name { Alchemy.config.default_site.name }
12
+ host { Alchemy.config.default_site.host }
13
13
  end
14
14
 
15
15
  trait :public do
@@ -30,8 +30,8 @@ RSpec.shared_examples_for "having crop action" do |args|
30
30
  let(:settings) { {} }
31
31
 
32
32
  before do
33
- picture.image_file_width = 300
34
- picture.image_file_height = 250
33
+ allow(picture).to receive(:image_file_width) { 300 }
34
+ allow(picture).to receive(:image_file_height) { 250 }
35
35
  allow(croppable_resource).to receive(:settings) { settings }
36
36
  expect(Alchemy::Picture).to receive(:find_by) { picture }
37
37
  end