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
@@ -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
@@ -86,8 +86,8 @@ RSpec.shared_examples_for "having picture thumbnails" do
86
86
  allow(record).to receive(:settings) { {} }
87
87
  end
88
88
 
89
- it "adds them to the url" do
90
- expect(picture_url).to match(/\?foo=baz/)
89
+ it "does not add them to the url" do
90
+ expect(picture_url).to_not match(/\?foo=baz/)
91
91
  end
92
92
  end
93
93
  end
@@ -112,7 +112,7 @@ RSpec.shared_examples_for "having picture thumbnails" do
112
112
  describe "#picture_url_options" do
113
113
  subject(:picture_url_options) { record.picture_url_options }
114
114
 
115
- let(:picture) { build_stubbed(:alchemy_picture) }
115
+ let(:picture) { build(:alchemy_picture) }
116
116
 
117
117
  it { is_expected.to be_a(HashWithIndifferentAccess) }
118
118
 
@@ -418,7 +418,7 @@ RSpec.shared_examples_for "having picture thumbnails" do
418
418
  end
419
419
 
420
420
  context "with picture assigned" do
421
- let(:picture) { build_stubbed(:alchemy_picture) }
421
+ let(:picture) { build(:alchemy_picture) }
422
422
 
423
423
  let(:default_mask) do
424
424
  [
@@ -432,8 +432,8 @@ RSpec.shared_examples_for "having picture thumbnails" do
432
432
  let(:settings) { {} }
433
433
 
434
434
  before do
435
- picture.image_file_width = 300
436
- picture.image_file_height = 250
435
+ allow(picture).to receive(:image_file_width) { 300 }
436
+ allow(picture).to receive(:image_file_height) { 250 }
437
437
  allow(record).to receive(:settings) { settings }
438
438
  end
439
439
 
@@ -555,8 +555,8 @@ RSpec.shared_examples_for "having picture thumbnails" do
555
555
  let(:settings) { {crop: true, size: size} }
556
556
 
557
557
  before do
558
- picture.image_file_width = 200
559
- picture.image_file_height = 100
558
+ allow(picture).to receive(:image_file_width) { 200 }
559
+ allow(picture).to receive(:image_file_height) { 100 }
560
560
  end
561
561
 
562
562
  context "size 200x50" do
@@ -619,45 +619,99 @@ RSpec.shared_examples_for "having picture thumbnails" do
619
619
  end
620
620
 
621
621
  describe "#allow_image_cropping?" do
622
- let(:picture) do
623
- stub_model(Alchemy::Picture, image_file_width: 400, image_file_height: 300)
622
+ let(:picture) { Alchemy::Picture.new }
623
+ let(:image_file_width) { 400 }
624
+ let(:image_file_height) { 300 }
625
+ let(:crop) { false }
626
+ let(:size) { "400x300" }
627
+ let(:upsample) { false }
628
+
629
+ before do
630
+ allow(picture).to receive(:image_file_width) { image_file_width }
631
+ allow(picture).to receive(:image_file_height) { image_file_height }
632
+ allow(record).to receive(:settings) { {crop:, size:, upsample:} }
624
633
  end
625
634
 
626
635
  subject { record.allow_image_cropping? }
627
636
 
628
- it { is_expected.to be_falsy }
637
+ shared_context "with image file" do
638
+ before do
639
+ if Alchemy.storage_adapter.dragonfly?
640
+ expect(picture).to receive(:image_file) { fixture_file_upload("image.png") }
641
+ elsif Alchemy.storage_adapter.active_storage?
642
+ expect(picture.image_file).to receive(:attached?) { true }
643
+ end
644
+ end
645
+ end
629
646
 
630
- context "with picture assigned" do
647
+ shared_context "without image file" do
631
648
  before do
632
- allow(record).to receive(:picture) { picture }
649
+ if Alchemy.storage_adapter.dragonfly?
650
+ expect(picture).to receive(:image_file) { nil }
651
+ elsif Alchemy.storage_adapter.active_storage?
652
+ expect(picture.image_file).to receive(:attached?) { false }
653
+ end
633
654
  end
655
+ end
656
+
657
+ context "with crop set to false" do
658
+ let(:crop) { false }
634
659
 
635
660
  it { is_expected.to be_falsy }
661
+ end
662
+
663
+ context "with crop set to true" do
664
+ let(:crop) { true }
636
665
 
637
- context "and with image larger than crop size" do
666
+ context "with picture assigned" do
638
667
  before do
639
- allow(picture).to receive(:can_be_cropped_to?) { true }
668
+ allow(record).to receive(:picture) { picture }
640
669
  end
641
670
 
642
- it { is_expected.to be_falsy }
671
+ context "and image smaller or equal to crop size" do
672
+ context "if picture.image_file is nil" do
673
+ include_context "without image file"
643
674
 
644
- context "with crop set to true" do
645
- before do
646
- allow(record).to receive(:settings) { {crop: true} }
675
+ it { is_expected.to be_falsy }
647
676
  end
648
677
 
649
- context "if picture.image_file is nil" do
650
- before do
651
- expect(picture).to receive(:image_file) { nil }
652
- end
678
+ context "if picture.image_file is present" do
679
+ include_context "with image file"
653
680
 
654
681
  it { is_expected.to be_falsy }
682
+
683
+ context "but with upsample set to true" do
684
+ let(:upsample) { true }
685
+
686
+ it { is_expected.to be(true) }
687
+ end
655
688
  end
689
+ end
656
690
 
657
- context "if picture.image_file is present" do
658
- let(:picture) { build_stubbed(:alchemy_picture) }
691
+ context "and with image larger than crop size" do
692
+ let(:image_file_width) { 1201 }
693
+ let(:image_file_height) { 481 }
694
+
695
+ it { is_expected.to be_falsy }
659
696
 
660
- it { is_expected.to be(true) }
697
+ context "with crop set to true" do
698
+ context "if picture.image_file is nil" do
699
+ include_context "without image file"
700
+
701
+ it { is_expected.to be_falsy }
702
+ end
703
+
704
+ context "if picture.image_file is present" do
705
+ include_context "with image file"
706
+
707
+ it { is_expected.to be(true) }
708
+
709
+ context "with size setting being nil" do
710
+ let(:size) { nil }
711
+
712
+ it { is_expected.to be_falsey }
713
+ end
714
+ end
661
715
  end
662
716
  end
663
717
  end
@@ -29,11 +29,11 @@ RSpec.shared_examples_for "an alchemy ingredient" do
29
29
  context "with element" do
30
30
  before do
31
31
  expect(element).to receive(:ingredient_definition_for).at_least(:once) do
32
- {
32
+ Alchemy::IngredientDefinition.new(
33
33
  settings: {
34
34
  linkable: true
35
35
  }
36
- }.with_indifferent_access
36
+ )
37
37
  end
38
38
  end
39
39
 
@@ -47,19 +47,19 @@ RSpec.shared_examples_for "an alchemy ingredient" do
47
47
  context "without element" do
48
48
  let(:element) { nil }
49
49
 
50
- it { is_expected.to eq({}) }
50
+ it { is_expected.to be_a(Alchemy::IngredientDefinition) }
51
51
  end
52
52
 
53
53
  context "with element" do
54
54
  let(:definition) do
55
- {
55
+ Alchemy::IngredientDefinition.new(
56
56
  role: "headline",
57
57
  type: "Text",
58
58
  default: "Hello World",
59
59
  settings: {
60
60
  linkable: true
61
61
  }
62
- }.with_indifferent_access
62
+ )
63
63
  end
64
64
 
65
65
  before do
File without changes
@@ -0,0 +1,14 @@
1
+ module Alchemy
2
+ class Upgrader
3
+ module EightZero
4
+ def mention_alchemy_config_initializer
5
+ todo <<~TEXT, "Configuration has changed to initializer"
6
+ Check the new configuration file `./config/initializers/alchemy.rb` and
7
+ update values from your `config/alchemy/config.yml` file.
8
+
9
+ Then you can safely remove the `config/alchemy/config.yml` file.
10
+ TEXT
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,29 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "alchemy/shell"
4
+ require "thor"
4
5
 
5
6
  module Alchemy
6
7
  class Upgrader
7
- extend Alchemy::Shell
8
-
9
- Dir["#{File.dirname(__FILE__)}/upgrader/*.rb"].sort.each { |f| require f }
10
-
11
- class << self
12
- def copy_new_config_file
13
- desc "Copy configuration file."
14
- config_file = Rails.root.join("config/alchemy/config.yml")
15
- default_config = File.join(File.dirname(__FILE__), "../../config/alchemy/config.yml")
16
- if !File.exist? config_file
17
- log "No configuration file found. Creating it."
18
- FileUtils.cp default_config, Rails.root.join("config/alchemy/config.yml")
19
- elsif FileUtils.identical? default_config, config_file
20
- log "Configuration file already present.", :skip
21
- else
22
- log "Custom configuration file found."
23
- FileUtils.cp default_config, Rails.root.join("config/alchemy/config.yml.defaults")
24
- log "Copied new default configuration file."
25
- todo "Check the default configuration file (./config/alchemy/config.yml.defaults) for new configuration options and insert them into your config file.", "Configuration has changed"
26
- end
8
+ include Alchemy::Shell
9
+ include Thor::Base
10
+ include Thor::Actions
11
+
12
+ Dir["#{File.dirname(__FILE__)}/upgrader/*.rb"].sort.each { require(_1) }
13
+
14
+ VERSION_MODULE_MAP = {
15
+ "8.0" => "Alchemy::Upgrader::EightZero"
16
+ }
17
+
18
+ source_root Alchemy::Engine.root.join("lib/generators/alchemy/install")
19
+
20
+ def initialize(version)
21
+ super()
22
+ self.class.include VERSION_MODULE_MAP[version.to_s].constantize
23
+ end
24
+
25
+ def update_config
26
+ desc "Copy configuration file."
27
+ @default_config = Alchemy::Configurations::Main.new
28
+ template("templates/alchemy.rb.tt", "config/initializers/alchemy.rb")
29
+ end
30
+
31
+ def run_migrations
32
+ ActiveRecord::Migration.check_all_pending!
33
+ rescue ActiveRecord::PendingMigrationError
34
+ desc "Pending Database migrations."
35
+ if yes?("Run database migrations now? (y/N)")
36
+ log "Migrating Database..."
37
+ Rake::Task["db:migrate"].invoke
38
+ else
39
+ log "Don't forget to run database migrations later with rake `db:migrate`.", :skip
27
40
  end
28
41
  end
29
42
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "7.4.5"
4
+ VERSION = "8.0.0.a"
5
5
 
6
6
  def self.version
7
7
  VERSION