alchemy_cms 7.1.13 → 7.2.0.b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +132 -39
  3. data/Gemfile +2 -11
  4. data/LICENSE +1 -1
  5. data/README.md +5 -6
  6. data/SECURITY.md +1 -1
  7. data/alchemy_cms.gemspec +3 -4
  8. data/app/assets/javascripts/alchemy/admin.js +0 -9
  9. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +5 -15
  10. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +5 -4
  11. data/app/assets/javascripts/alchemy/templates/index.js +0 -1
  12. data/app/assets/javascripts/alchemy/templates/node_folder.hbs +1 -1
  13. data/app/assets/javascripts/alchemy/templates/page_folder.hbs +1 -1
  14. data/app/assets/javascripts/tinymce/plugins/alchemy_link/plugin.min.js +20 -7
  15. data/app/assets/stylesheets/alchemy/_custom-properties.scss +12 -0
  16. data/app/assets/stylesheets/alchemy/_mixins.scss +10 -6
  17. data/app/assets/stylesheets/alchemy/_variables.scss +3 -0
  18. data/app/assets/stylesheets/alchemy/admin.scss +2 -2
  19. data/app/assets/stylesheets/alchemy/archive.scss +4 -3
  20. data/app/assets/stylesheets/alchemy/attachment-select.scss +19 -0
  21. data/app/assets/stylesheets/alchemy/base.scss +31 -18
  22. data/app/assets/stylesheets/alchemy/buttons.scss +3 -4
  23. data/app/assets/stylesheets/alchemy/dashboard.scss +1 -1
  24. data/app/assets/stylesheets/alchemy/dialogs.scss +2 -5
  25. data/app/assets/stylesheets/alchemy/elements.scss +74 -42
  26. data/app/assets/stylesheets/alchemy/flash.scss +20 -70
  27. data/app/assets/stylesheets/alchemy/forms.scss +41 -36
  28. data/app/assets/stylesheets/alchemy/frame.scss +12 -3
  29. data/app/assets/stylesheets/alchemy/icons.scss +34 -2
  30. data/app/assets/stylesheets/alchemy/image_library.scss +18 -9
  31. data/app/assets/stylesheets/alchemy/{filter_field.scss → list_filter.scss} +8 -7
  32. data/app/assets/stylesheets/alchemy/lists.scss +1 -1
  33. data/app/assets/stylesheets/alchemy/navigation.scss +9 -12
  34. data/app/assets/stylesheets/alchemy/node-select.scss +1 -1
  35. data/app/assets/stylesheets/alchemy/nodes.scss +15 -13
  36. data/app/assets/stylesheets/alchemy/notices.scss +56 -39
  37. data/app/assets/stylesheets/alchemy/page-select.scss +1 -4
  38. data/app/assets/stylesheets/alchemy/pagination.scss +11 -1
  39. data/app/assets/stylesheets/alchemy/preview_window.scss +3 -3
  40. data/app/assets/stylesheets/alchemy/search.scss +4 -4
  41. data/app/assets/stylesheets/alchemy/selects.scss +13 -7
  42. data/app/assets/stylesheets/alchemy/shoelace.scss +33 -2
  43. data/app/assets/stylesheets/alchemy/sitemap.scss +155 -159
  44. data/app/assets/stylesheets/alchemy/tables.scss +49 -12
  45. data/app/assets/stylesheets/alchemy/tags.scss +17 -11
  46. data/app/assets/stylesheets/alchemy/toolbar.scss +2 -2
  47. data/app/assets/stylesheets/alchemy/typography.scss +41 -22
  48. data/app/assets/stylesheets/alchemy/upload.scss +5 -4
  49. data/app/components/alchemy/admin/attachment_select.rb +39 -0
  50. data/app/components/alchemy/admin/icon.rb +72 -0
  51. data/app/components/alchemy/admin/link_dialog/anchor_tab.rb +41 -0
  52. data/app/components/alchemy/admin/link_dialog/base_tab.rb +75 -0
  53. data/app/components/alchemy/admin/link_dialog/external_tab.rb +42 -0
  54. data/app/components/alchemy/admin/link_dialog/file_tab.rb +45 -0
  55. data/app/components/alchemy/admin/link_dialog/internal_tab.rb +66 -0
  56. data/app/components/alchemy/admin/link_dialog/tabs.rb +33 -0
  57. data/app/components/alchemy/admin/list_filter.rb +42 -0
  58. data/app/components/alchemy/admin/message.rb +19 -0
  59. data/app/components/alchemy/admin/tags_autocomplete.rb +25 -0
  60. data/app/components/alchemy/admin/toolbar_button.rb +111 -0
  61. data/app/components/alchemy/ingredients/datetime_view.rb +2 -3
  62. data/app/components/alchemy/ingredients/link_view.rb +1 -7
  63. data/app/components/alchemy/ingredients/picture_view.rb +2 -2
  64. data/app/components/alchemy/ingredients/text_view.rb +1 -2
  65. data/app/controllers/alchemy/admin/base_controller.rb +3 -27
  66. data/app/controllers/alchemy/admin/elements_controller.rb +4 -2
  67. data/app/controllers/alchemy/admin/ingredients_controller.rb +2 -0
  68. data/app/controllers/alchemy/admin/languages_controller.rb +2 -2
  69. data/app/controllers/alchemy/admin/layoutpages_controller.rb +0 -19
  70. data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +12 -4
  71. data/app/controllers/alchemy/admin/nodes_controller.rb +26 -0
  72. data/app/controllers/alchemy/admin/pages_controller.rb +16 -79
  73. data/app/controllers/alchemy/admin/picture_descriptions_controller.rb +15 -0
  74. data/app/controllers/alchemy/admin/pictures_controller.rb +18 -1
  75. data/app/controllers/alchemy/admin/resources_controller.rb +16 -11
  76. data/app/controllers/alchemy/api/attachments_controller.rb +44 -0
  77. data/app/controllers/alchemy/api/pages_controller.rb +10 -6
  78. data/app/controllers/alchemy/base_controller.rb +2 -2
  79. data/app/controllers/alchemy/messages_controller.rb +3 -3
  80. data/app/controllers/alchemy/pages_controller.rb +8 -6
  81. data/app/controllers/concerns/alchemy/admin/current_language.rb +1 -11
  82. data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +1 -1
  83. data/app/decorators/alchemy/element_editor.rb +2 -2
  84. data/app/helpers/alchemy/admin/base_helper.rb +8 -60
  85. data/app/helpers/alchemy/admin/elements_helper.rb +1 -1
  86. data/app/helpers/alchemy/admin/ingredients_helper.rb +1 -1
  87. data/app/helpers/alchemy/base_helper.rb +9 -91
  88. data/app/helpers/alchemy/elements_helper.rb +3 -3
  89. data/app/helpers/alchemy/pages_helper.rb +16 -9
  90. data/app/javascript/alchemy_admin/components/attachment_select.js +24 -0
  91. data/app/javascript/alchemy_admin/components/button.js +3 -0
  92. data/app/javascript/alchemy_admin/components/clipboard_button.js +3 -2
  93. data/app/javascript/alchemy_admin/components/dialog_link.js +10 -7
  94. data/app/javascript/alchemy_admin/components/dom_id_select.js +69 -0
  95. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +42 -0
  96. data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +4 -2
  97. data/app/javascript/alchemy_admin/components/element_editor.js +21 -13
  98. data/app/javascript/alchemy_admin/components/elements_window.js +87 -0
  99. data/app/javascript/alchemy_admin/components/growl.js +13 -0
  100. data/app/javascript/alchemy_admin/components/icon.js +51 -0
  101. data/app/javascript/alchemy_admin/components/index.js +24 -0
  102. data/app/javascript/alchemy_admin/components/ingredient_group.js +6 -0
  103. data/app/javascript/alchemy_admin/components/link_buttons/link_button.js +21 -11
  104. data/app/javascript/alchemy_admin/components/link_buttons/unlink_button.js +2 -1
  105. data/app/javascript/alchemy_admin/components/link_buttons.js +1 -0
  106. data/app/javascript/alchemy_admin/components/list_filter.js +68 -0
  107. data/app/javascript/alchemy_admin/components/message.js +69 -0
  108. data/app/javascript/alchemy_admin/components/node_select.js +1 -1
  109. data/app/javascript/alchemy_admin/components/overlay.js +6 -6
  110. data/app/javascript/alchemy_admin/components/page_select.js +3 -7
  111. data/app/javascript/alchemy_admin/components/preview_window.js +121 -0
  112. data/app/javascript/alchemy_admin/components/remote_select.js +4 -1
  113. data/app/javascript/alchemy_admin/components/select.js +37 -1
  114. data/app/javascript/alchemy_admin/components/tags_autocomplete.js +57 -0
  115. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +4 -3
  116. data/app/javascript/alchemy_admin/components/uploader/progress.js +1 -1
  117. data/app/javascript/alchemy_admin/confirm_dialog.js +133 -0
  118. data/app/javascript/alchemy_admin/dirty.js +19 -14
  119. data/app/javascript/alchemy_admin/fixed_elements.js +24 -0
  120. data/app/javascript/alchemy_admin/growler.js +15 -0
  121. data/app/javascript/alchemy_admin/gui.js +2 -4
  122. data/app/javascript/alchemy_admin/hotkeys.js +60 -0
  123. data/app/javascript/alchemy_admin/image_loader.js +2 -2
  124. data/app/javascript/alchemy_admin/ingredient_anchor_link.js +2 -3
  125. data/app/javascript/alchemy_admin/initializer.js +1 -8
  126. data/app/javascript/alchemy_admin/link_dialog.js +131 -0
  127. data/app/javascript/alchemy_admin/locales/en.js +3 -0
  128. data/app/javascript/alchemy_admin/node_tree.js +4 -3
  129. data/app/javascript/alchemy_admin/page_sorter.js +23 -14
  130. data/app/javascript/alchemy_admin/picture_editors.js +6 -5
  131. data/app/javascript/alchemy_admin/shoelace_theme.js +60 -0
  132. data/app/javascript/alchemy_admin/sitemap.js +9 -3
  133. data/app/javascript/alchemy_admin/sortable_elements.js +4 -6
  134. data/app/javascript/alchemy_admin.js +18 -42
  135. data/app/models/alchemy/current.rb +26 -0
  136. data/app/models/alchemy/element.rb +1 -1
  137. data/app/models/alchemy/ingredients/audio.rb +0 -11
  138. data/app/models/alchemy/ingredients/datetime.rb +1 -1
  139. data/app/models/alchemy/ingredients/headline.rb +8 -1
  140. data/app/models/alchemy/ingredients/picture.rb +6 -0
  141. data/app/models/alchemy/ingredients/video.rb +0 -12
  142. data/app/models/alchemy/language.rb +8 -6
  143. data/app/models/alchemy/node.rb +2 -2
  144. data/app/models/alchemy/page/page_elements.rb +8 -8
  145. data/app/models/alchemy/page/page_layouts.rb +3 -3
  146. data/app/models/alchemy/page/page_natures.rb +13 -9
  147. data/app/models/alchemy/page/page_scopes.rb +2 -2
  148. data/app/models/alchemy/page/publisher.rb +1 -0
  149. data/app/models/alchemy/page.rb +16 -31
  150. data/app/models/alchemy/picture.rb +8 -0
  151. data/app/models/alchemy/picture_description.rb +8 -0
  152. data/app/models/alchemy/picture_variant.rb +1 -1
  153. data/app/models/alchemy/site.rb +10 -7
  154. data/app/models/concerns/alchemy/picture_thumbnails.rb +5 -4
  155. data/app/serializers/alchemy/attachment_serializer.rb +8 -0
  156. data/app/serializers/alchemy/page_node_serializer.rb +9 -0
  157. data/app/views/alchemy/_menubar.html.erb +1 -1
  158. data/app/views/alchemy/_preview_mode_code.html.erb +1 -1
  159. data/app/views/alchemy/admin/attachments/_tag_list.html.erb +2 -2
  160. data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +0 -1
  161. data/app/views/alchemy/admin/attachments/edit.html.erb +3 -4
  162. data/app/views/alchemy/admin/clipboard/clear.js.erb +1 -1
  163. data/app/views/alchemy/admin/clipboard/index.html.erb +1 -1
  164. data/app/views/alchemy/admin/clipboard/insert.js.erb +1 -1
  165. data/app/views/alchemy/admin/clipboard/remove.js.erb +1 -1
  166. data/app/views/alchemy/admin/dashboard/_locked_pages.html.erb +1 -1
  167. data/app/views/alchemy/admin/dashboard/_sites.html.erb +1 -1
  168. data/app/views/alchemy/admin/dashboard/help.html.erb +48 -12
  169. data/app/views/alchemy/admin/dashboard/index.html.erb +1 -1
  170. data/app/views/alchemy/admin/dashboard/info.html.erb +5 -8
  171. data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +1 -1
  172. data/app/views/alchemy/admin/elements/_element.html.erb +5 -5
  173. data/app/views/alchemy/admin/elements/_footer.html.erb +1 -1
  174. data/app/views/alchemy/admin/elements/_header.html.erb +6 -2
  175. data/app/views/alchemy/admin/elements/_toolbar.html.erb +8 -6
  176. data/app/views/alchemy/admin/elements/create.js.erb +0 -5
  177. data/app/views/alchemy/admin/elements/index.html.erb +70 -34
  178. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +1 -2
  179. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +3 -5
  180. data/app/views/alchemy/admin/languages/_language.html.erb +1 -1
  181. data/app/views/alchemy/admin/languages/index.html.erb +2 -2
  182. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +18 -18
  183. data/app/views/alchemy/admin/layoutpages/edit.html.erb +4 -5
  184. data/app/views/alchemy/admin/layoutpages/index.html.erb +2 -2
  185. data/app/views/alchemy/admin/legacy_page_urls/_legacy_page_url.html.erb +10 -11
  186. data/app/views/alchemy/admin/legacy_page_urls/_new.html.erb +15 -17
  187. data/app/views/alchemy/admin/legacy_page_urls/_table.html.erb +16 -0
  188. data/app/views/alchemy/admin/legacy_page_urls/_update.turbo_stream.erb +12 -0
  189. data/app/views/alchemy/admin/legacy_page_urls/create.turbo_stream.erb +8 -0
  190. data/app/views/alchemy/admin/legacy_page_urls/destroy.turbo_stream.erb +1 -0
  191. data/app/views/alchemy/admin/legacy_page_urls/edit.html.erb +27 -0
  192. data/app/views/alchemy/admin/legacy_page_urls/show.html.erb +1 -0
  193. data/app/views/alchemy/admin/legacy_page_urls/update.turbo_stream.erb +1 -0
  194. data/app/views/alchemy/admin/nodes/_form.html.erb +12 -11
  195. data/app/views/alchemy/admin/nodes/_label.html.erb +1 -0
  196. data/app/views/alchemy/admin/nodes/_node.html.erb +19 -19
  197. data/app/views/alchemy/admin/nodes/_page_nodes.html.erb +48 -0
  198. data/app/views/alchemy/admin/nodes/_update.turbo_stream.erb +9 -0
  199. data/app/views/alchemy/admin/nodes/create.turbo_stream.erb +1 -0
  200. data/app/views/alchemy/admin/nodes/destroy.turbo_stream.erb +1 -0
  201. data/app/views/alchemy/admin/nodes/index.html.erb +3 -3
  202. data/app/views/alchemy/admin/pages/_form.html.erb +3 -4
  203. data/app/views/alchemy/admin/pages/_legacy_urls.html.erb +4 -15
  204. data/app/views/alchemy/admin/pages/_page.html.erb +39 -39
  205. data/app/views/alchemy/admin/pages/_table_row.html.erb +3 -3
  206. data/app/views/alchemy/admin/pages/_toolbar.html.erb +2 -2
  207. data/app/views/alchemy/admin/pages/configure.html.erb +6 -0
  208. data/app/views/alchemy/admin/pages/edit.html.erb +15 -62
  209. data/app/views/alchemy/admin/pages/unlock.js.erb +3 -3
  210. data/app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb +3 -1
  211. data/app/views/alchemy/admin/partials/_flash_notices.html.erb +4 -2
  212. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  213. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +5 -2
  214. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +2 -2
  215. data/app/views/alchemy/admin/partials/_search_form.html.erb +2 -2
  216. data/app/views/alchemy/admin/partials/_site_select.html.erb +1 -1
  217. data/app/views/alchemy/admin/picture_descriptions/_form.html.erb +11 -0
  218. data/app/views/alchemy/admin/picture_descriptions/edit.html.erb +6 -0
  219. data/app/views/alchemy/admin/pictures/_form.html.erb +4 -3
  220. data/app/views/alchemy/admin/pictures/_infos.html.erb +1 -1
  221. data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +29 -0
  222. data/app/views/alchemy/admin/pictures/_tag_list.html.erb +2 -2
  223. data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +0 -2
  224. data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +3 -3
  225. data/app/views/alchemy/admin/pictures/show.html.erb +3 -3
  226. data/app/views/alchemy/admin/resources/_form.html.erb +3 -4
  227. data/app/views/alchemy/admin/resources/_per_page_select.html.erb +1 -1
  228. data/app/views/alchemy/admin/resources/_tag_list.html.erb +2 -2
  229. data/app/views/alchemy/admin/resources/index.html.erb +2 -2
  230. data/app/views/alchemy/admin/sites/index.html.erb +1 -1
  231. data/app/views/alchemy/admin/styleguide/index.html.erb +29 -24
  232. data/app/views/alchemy/admin/tags/_tag.html.erb +1 -1
  233. data/app/views/alchemy/admin/tags/edit.html.erb +1 -1
  234. data/app/views/alchemy/admin/tags/index.html.erb +1 -1
  235. data/app/views/alchemy/base/500.html.erb +7 -18
  236. data/app/views/alchemy/base/error_notice.html.erb +3 -1
  237. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +1 -1
  238. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +2 -3
  239. data/app/views/alchemy/ingredients/_headline_editor.html.erb +13 -8
  240. data/app/views/alchemy/ingredients/_picture_editor.html.erb +1 -1
  241. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +1 -1
  242. data/app/views/alchemy/language_links/_language.html.erb +1 -1
  243. data/app/views/kaminari/alchemy/_first_page.html.erb +2 -2
  244. data/app/views/kaminari/alchemy/_gap.html.erb +1 -1
  245. data/app/views/kaminari/alchemy/_last_page.html.erb +2 -2
  246. data/app/views/kaminari/alchemy/_next_page.html.erb +2 -2
  247. data/app/views/kaminari/alchemy/_prev_page.html.erb +2 -2
  248. data/app/views/layouts/alchemy/admin.html.erb +2 -1
  249. data/bundles/shoelace.js +3 -1
  250. data/config/locales/alchemy.en.yml +16 -3
  251. data/config/routes.rb +4 -2
  252. data/db/migrate/20240314105244_create_alchemy_picture_descriptions.rb +11 -0
  253. data/lib/alchemy/configuration_methods.rb +1 -1
  254. data/lib/alchemy/controller_actions.rb +3 -3
  255. data/lib/alchemy/element_definition.rb +10 -6
  256. data/lib/alchemy/engine.rb +19 -2
  257. data/lib/alchemy/page_layout.rb +10 -6
  258. data/lib/alchemy/permissions.rb +4 -3
  259. data/lib/alchemy/resource.rb +4 -14
  260. data/lib/alchemy/routing_constraints.rb +1 -1
  261. data/lib/alchemy/seeder.rb +2 -2
  262. data/lib/alchemy/test_support/capybara_helpers.rb +4 -0
  263. data/lib/alchemy/test_support/factories/language_factory.rb +1 -1
  264. data/lib/alchemy/test_support/shared_contexts.rb +8 -0
  265. data/lib/alchemy/tinymce.rb +2 -1
  266. data/lib/alchemy/version.rb +1 -1
  267. data/lib/alchemy.rb +36 -0
  268. data/lib/alchemy_cms.rb +0 -1
  269. data/lib/generators/alchemy/menus/templates/node.html.erb +2 -2
  270. data/lib/generators/alchemy/menus/templates/node.html.haml +2 -2
  271. data/lib/generators/alchemy/menus/templates/node.html.slim +2 -2
  272. data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
  273. data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
  274. data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
  275. data/lib/tasks/alchemy/sitemap.rake +97 -0
  276. data/lib/tasks/alchemy/tidy.rake +1 -0
  277. data/package.json +8 -8
  278. data/vendor/assets/fonts/remixicon.symbol.svg +11 -0
  279. data/vendor/javascript/shoelace.min.js +333 -118
  280. data/vendor/javascript/sortable.min.js +1 -1
  281. data/vendor/javascript/tinymce.min.js +1 -1
  282. data/vendor/javascript/ungap-custom-elements.min.js +1 -1
  283. metadata +63 -55
  284. data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +0 -85
  285. data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +0 -107
  286. data/app/assets/javascripts/alchemy/alchemy.file_progress.js.coffee +0 -66
  287. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +0 -45
  288. data/app/assets/javascripts/alchemy/alchemy.growler.js.coffee +0 -24
  289. data/app/assets/javascripts/alchemy/alchemy.hotkeys.js.coffee +0 -49
  290. data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +0 -0
  291. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +0 -230
  292. data/app/assets/javascripts/alchemy/alchemy.list_filter.js.coffee +0 -49
  293. data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +0 -82
  294. data/app/assets/javascripts/alchemy/alchemy.string_extension.js.coffee +0 -11
  295. data/app/assets/javascripts/alchemy/templates/page.hbs +0 -19
  296. data/app/javascript/alchemy_admin/tags_autocomplete.js +0 -46
  297. data/app/models/alchemy/tree_node.rb +0 -7
  298. data/app/views/alchemy/admin/elements/destroy.js.erb +0 -8
  299. data/app/views/alchemy/admin/legacy_page_urls/_form.html.erb +0 -5
  300. data/app/views/alchemy/admin/legacy_page_urls/create.js.erb +0 -9
  301. data/app/views/alchemy/admin/legacy_page_urls/destroy.js.erb +0 -6
  302. data/app/views/alchemy/admin/legacy_page_urls/update.js.erb +0 -2
  303. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +0 -22
  304. data/app/views/alchemy/admin/pages/_external_link.html.erb +0 -31
  305. data/app/views/alchemy/admin/pages/_file_link.html.erb +0 -31
  306. data/app/views/alchemy/admin/pages/_internal_link.html.erb +0 -35
  307. data/app/views/alchemy/admin/pages/link.html.erb +0 -26
  308. data/app/views/alchemy/admin/partials/_flash.html.erb +0 -4
  309. data/app/views/alchemy/admin/partials/_toolbar_button.html.erb +0 -29
  310. data/lib/alchemy/test_support/current_language_shared_examples.rb +0 -33
  311. data/vendor/assets/fonts/remixicon.eot +0 -0
  312. data/vendor/assets/fonts/remixicon.svg +0 -7816
  313. data/vendor/assets/fonts/remixicon.ttf +0 -0
  314. data/vendor/assets/fonts/remixicon.woff +0 -0
  315. data/vendor/assets/fonts/remixicon.woff2 +0 -0
  316. data/vendor/assets/stylesheets/remixicon.scss +0 -10480
@@ -42,7 +42,7 @@ module Alchemy
42
42
  end
43
43
 
44
44
  can :read, Alchemy::Page, Alchemy::Page.published.not_restricted.from_current_site do |p|
45
- p.public? && !p.restricted? && p.site == Alchemy::Site.current
45
+ p.public? && !p.restricted? && p.site == Alchemy::Current.site
46
46
  end
47
47
  end
48
48
  end
@@ -65,7 +65,7 @@ module Alchemy
65
65
  end
66
66
 
67
67
  can :read, Alchemy::Page, Alchemy::Page.published.from_current_site do |p|
68
- p.public? && p.site == Alchemy::Site.current
68
+ p.public? && p.site == Alchemy::Current.site
69
69
  end
70
70
  end
71
71
  end
@@ -96,7 +96,7 @@ module Alchemy
96
96
  can :leave, :alchemy_admin
97
97
  can [:info, :help], :alchemy_admin_dashboard
98
98
  can :manage, :alchemy_admin_clipboard
99
- can :update, :alchemy_admin_layoutpages
99
+ can :edit, :alchemy_admin_layoutpages
100
100
  can :tree, :alchemy_admin_pages
101
101
 
102
102
  # Resources
@@ -157,6 +157,7 @@ module Alchemy
157
157
  end
158
158
 
159
159
  can :manage, Alchemy::Picture
160
+ can :manage, Alchemy::PictureDescription
160
161
  can :manage, Alchemy::Attachment
161
162
  can :manage, Alchemy::Tag
162
163
  can :index, Alchemy::Language
@@ -188,21 +188,11 @@ module Alchemy
188
188
  end
189
189
  end
190
190
 
191
- # Returns a sorted array of attributes.
192
- #
193
- # Attribute called "name" comes first.
194
- # Attribute called "updated_at" comes last.
195
- # Boolean type attributes come after non-boolean attributes but before "updated_at".
196
- #
197
191
  def sorted_attributes
198
- @_sorted_attributes ||= attributes.sort_by! do |attr|
199
- [
200
- (attr[:name] == "name") ? 0 : 1,
201
- (attr[:name] == "updated_at") ? 3 : 2,
202
- (attr[:type] == :boolean) ? 2 : 1,
203
- attr[:name]
204
- ]
205
- end
192
+ @_sorted_attributes ||= attributes
193
+ .sort_by { |attr| (attr[:name] == "name") ? 0 : 1 }
194
+ .sort_by! { |attr| (attr[:type] == :boolean) ? 1 : 0 }
195
+ .sort_by! { |attr| (attr[:name] == "updated_at") ? 1 : 0 }
206
196
  end
207
197
 
208
198
  def editable_attributes
@@ -27,7 +27,7 @@ module Alchemy
27
27
  # because it could be a legacy route that needs to be redirected.
28
28
  #
29
29
  def handable_format?
30
- @request.format.symbol.nil? || @request.format.html?
30
+ @request.format.symbol.nil? || (@request.format.symbol == :html)
31
31
  end
32
32
 
33
33
  # We don't want to handle the Rails info routes.
@@ -31,7 +31,7 @@ module Alchemy
31
31
  log "There are already pages present in your database. " \
32
32
  "Please use `rake db:reset' if you want to rebuild your database.", :skip
33
33
  else
34
- create_default_site! unless Alchemy::Site.default
34
+ create_default_site! unless Alchemy::Site.first
35
35
  create_default_language! unless Alchemy::Language.default
36
36
  seed_pages if contentpages.present?
37
37
  seed_layoutpages if layoutpages.present?
@@ -126,7 +126,7 @@ module Alchemy
126
126
  page_layout: default_language["page_layout"],
127
127
  public: true,
128
128
  default: true,
129
- site: Alchemy::Site.default
129
+ site: Alchemy::Site.first
130
130
  )
131
131
  else
132
132
  raise DefaultLanguageNotFoundError
@@ -54,6 +54,10 @@ module Alchemy
54
54
  find(%([content="#{content}"] > a)).click
55
55
  end
56
56
 
57
+ def click_icon(name)
58
+ find(%(alchemy-icon[name="#{name}"])).click
59
+ end
60
+
57
61
  private
58
62
 
59
63
  def within_entire_page(&block)
@@ -10,7 +10,7 @@ FactoryBot.define do
10
10
 
11
11
  public { true }
12
12
 
13
- site { Alchemy::Site.default || create(:alchemy_site, :default) }
13
+ site { Alchemy::Site.first || create(:alchemy_site, :default) }
14
14
 
15
15
  trait :klingon do
16
16
  name { "Klingon" }
@@ -14,3 +14,11 @@ RSpec.shared_context "with invalid file" do
14
14
  end
15
15
  end
16
16
  end
17
+
18
+ RSpec.shared_context "in preview mode" do
19
+ around do |example|
20
+ Alchemy::Current.preview_page = page
21
+ example.run
22
+ Alchemy::Current.preview_page = nil
23
+ end
24
+ end
@@ -33,7 +33,8 @@ module Alchemy
33
33
  entity_encoding: "raw",
34
34
  paste_as_text: true,
35
35
  element_format: "html",
36
- branding: false
36
+ branding: false,
37
+ license_key: "gpl"
37
38
  }
38
39
 
39
40
  class << self
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "7.1.13"
4
+ VERSION = "7.2.0.b"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/lib/alchemy.rb CHANGED
@@ -102,4 +102,40 @@ module Alchemy
102
102
  # JS Importmap instance
103
103
  singleton_class.attr_accessor :importmap
104
104
  self.importmap = Importmap::Map.new
105
+
106
+ # Configure tabs in the link dialog
107
+ #
108
+ # With this configuration that tabs in the link dialog can be extended
109
+ # without overwriting or defacing the Admin Interface.
110
+ #
111
+ # == Example
112
+ #
113
+ # # components/acme/link_tab.rb
114
+ # module Acme
115
+ # class LinkTab < ::Alchemy::Admin::LinkDialog::BaseTab
116
+ # def title
117
+ # "Awesome Tab Title"
118
+ # end
119
+ #
120
+ # def name
121
+ # :unique_name
122
+ # end
123
+ #
124
+ # def fields
125
+ # [ title_input, target_select ]
126
+ # end
127
+ # end
128
+ # end
129
+ #
130
+ # # config/initializers/alchemy.rb
131
+ # Alchemy.link_dialog_tabs << Acme::LinkTab
132
+ #
133
+ def self.link_dialog_tabs
134
+ @_link_dialog_tabs ||= Set.new([
135
+ Alchemy::Admin::LinkDialog::InternalTab,
136
+ Alchemy::Admin::LinkDialog::AnchorTab,
137
+ Alchemy::Admin::LinkDialog::ExternalTab,
138
+ Alchemy::Admin::LinkDialog::FileTab
139
+ ])
140
+ end
105
141
  end
data/lib/alchemy_cms.rb CHANGED
@@ -17,7 +17,6 @@ require "jquery-rails"
17
17
  require "kaminari"
18
18
  require "non_stupid_digest_assets"
19
19
  require "ransack"
20
- require "request_store"
21
20
  require "responders"
22
21
  require "sassc-rails"
23
22
  require "simple_form"
@@ -1,8 +1,8 @@
1
- <%% cache [node, @page, @preview_mode] do %>
1
+ <%% cache [node, @page, Alchemy::Current.preview_page?] do %>
2
2
  <%%= content_tag :li, class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do %>
3
3
  <%%= link_to_if node.url,
4
4
  node.name,
5
- @preview_mode ? 'javascript: void(0)' : node.url,
5
+ Alchemy::Current.preview_page? ? 'javascript: void(0)' : node.url,
6
6
  class: ['nav-link', current_page?(node.url) ? 'active' : nil].compact,
7
7
  title: node.title,
8
8
  target: node.external? ? '_blank' : nil,
@@ -1,9 +1,9 @@
1
- - cache [node, @page, @preview_mode] do
1
+ - cache [node, @page, Alchemy::Current.preview_page?] do
2
2
  = content_tag :li,
3
3
  class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do
4
4
  = link_to_if node.url,
5
5
  node.name,
6
- @preview_mode ? 'javascript: void(0)' : node.url,
6
+ Alchemy::Current.preview_page? ? 'javascript: void(0)' : node.url,
7
7
  class: ['nav-link', current_page?(node.url) ? 'active' : nil].compact,
8
8
  title: node.title,
9
9
  target: node.external? ? '_blank' : nil,
@@ -1,9 +1,9 @@
1
- - cache [node, @page, @preview_mode] do
1
+ - cache [node, @page, Alchemy::Current.preview_page?] do
2
2
  = content_tag :li,
3
3
  class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do
4
4
  = link_to_if node.url,
5
5
  node.name,
6
- @preview_mode ? 'javascript: void(0)' : node.url,
6
+ Alchemy::Current.preview_page? ? 'javascript: void(0)' : node.url,
7
7
  class: ['nav-link', current_page?(node.url) ? 'active' : nil].compact,
8
8
  title: node.title,
9
9
  target: node.external? ? '_blank' : nil,
@@ -1,4 +1,4 @@
1
- <%% cache [menu, @page, @preview_mode] do %>
1
+ <%% cache [menu, @page, Alchemy::Current.preview_page?] do %>
2
2
  <ul class="nav">
3
3
  <%%= render partial: menu.to_partial_path,
4
4
  collection: menu.children.includes(:page, :children),
@@ -1,4 +1,4 @@
1
- - cache [menu, @page, @preview_mode] do
1
+ - cache [menu, @page, Alchemy::Current.preview_page?] do
2
2
  %ul.nav
3
3
  = render partial: menu.to_partial_path,
4
4
  collection: menu.children.includes(:page, :children),
@@ -1,4 +1,4 @@
1
- - cache [menu, @page, @preview_mode] do
1
+ - cache [menu, @page, Alchemy::Current.preview_page?] do
2
2
  ul.nav
3
3
  = render partial: menu.to_partial_path,
4
4
  collection: menu.children.includes(:page, :children),
@@ -0,0 +1,97 @@
1
+ class SiteMapIssueFinder
2
+ attr_reader :save
3
+ attr_accessor :depth_issue_page_ids, :lft_rgt_issue_page_ids
4
+
5
+ def initialize(save: false)
6
+ @save = save
7
+ @depth_issue_page_ids = Set.new
8
+ @lft_rgt_issue_page_ids = Set.new
9
+ end
10
+
11
+ def depth_issues
12
+ puts "\nFind Page Depth Issues"
13
+ puts "======================\n"
14
+
15
+ Alchemy::Page.each_with_level(Alchemy::Page.root.self_and_descendants) do |page, level|
16
+ not_the_same_level = level != page.depth
17
+ print not_the_same_level ? "F" : "."
18
+ if not_the_same_level
19
+ depth_issue_page_ids << page.id
20
+ page.update_column(:depth, level) if save
21
+ end
22
+ end
23
+
24
+ print_conclusion(depth_issue_page_ids, "depth")
25
+ end
26
+
27
+ def lft_rgt_issues
28
+ puts "\nFind Page Left/Right Value Issues"
29
+ puts "=================================\n"
30
+
31
+ Alchemy::Page.roots.each do |root_page|
32
+ traverse_children(root_page, root_page.lft)
33
+ end
34
+
35
+ print_conclusion(lft_rgt_issue_page_ids, "left/right value")
36
+ end
37
+
38
+ private
39
+
40
+ def print_conclusion(page_ids, field_description)
41
+ puts "\n\n"
42
+ if page_ids.length > 0
43
+ if save
44
+ puts "Found and corrected #{field_description} for #{page_ids.length} page(s)!"
45
+ else
46
+ puts "Following Pages have an incorrect #{field_description}: #{page_ids.join(", ")}"
47
+ end
48
+ else
49
+ puts "All pages have the correct #{field_description}!\n"
50
+ end
51
+ puts "\n"
52
+ end
53
+
54
+ def fix_page_field(page, field, counter)
55
+ wrong_counter = page[field] != counter
56
+ print wrong_counter ? "F" : "."
57
+ if wrong_counter
58
+ lft_rgt_issue_page_ids << page.id
59
+ page.update_column(field, counter) if save
60
+ end
61
+ end
62
+
63
+ ##
64
+ # @param [Alchemy::Page] page
65
+ # @param [Integer] counter
66
+ # @return [Integer]
67
+ def traverse_children(page, counter)
68
+ page.children.order(lft: :asc).each do |child_page|
69
+ counter += 1
70
+ fix_page_field(child_page, :lft, counter)
71
+ counter = traverse_children(child_page, counter) unless child_page.leaf?
72
+
73
+ counter += 1
74
+ fix_page_field(child_page, :rgt, counter)
75
+ end
76
+
77
+ counter
78
+ end
79
+ end
80
+
81
+ namespace :alchemy do
82
+ namespace :sitemap do
83
+ desc "Get an overview over all sitemap issues"
84
+ task anomalies: [:environment] do
85
+ finder = SiteMapIssueFinder.new
86
+ finder.lft_rgt_issues
87
+ finder.depth_issues
88
+ end
89
+
90
+ desc "Fix nested set sitemap issues"
91
+ task fix: [:environment] do
92
+ finder = SiteMapIssueFinder.new(save: true)
93
+ finder.lft_rgt_issues
94
+ finder.depth_issues
95
+ end
96
+ end
97
+ end
@@ -7,6 +7,7 @@ namespace :alchemy do
7
7
  desc "Tidy up Alchemy database."
8
8
  task :up do
9
9
  Rake::Task["alchemy:tidy:element_positions"].invoke
10
+ Rake::Task["alchemy:tidy:content_positions"].invoke
10
11
  Rake::Task["alchemy:tidy:remove_orphaned_records"].invoke
11
12
  Rake::Task["alchemy:tidy:remove_trashed_elements"].invoke
12
13
  Rake::Task["alchemy:tidy:remove_duplicate_legacy_urls"].invoke
data/package.json CHANGED
@@ -11,28 +11,28 @@
11
11
  "license": "BSD-3-Clause",
12
12
  "dependencies": {
13
13
  "@rails/ujs": "^7.1.3",
14
- "@shoelace-style/shoelace": "^2.13.1",
14
+ "@shoelace-style/shoelace": "^2.14.0",
15
15
  "@ungap/custom-elements": "^1.3.0",
16
16
  "clipboard": "^2.0.11",
17
17
  "flatpickr": "^4.6.13",
18
18
  "keymaster": "^1.6.2",
19
19
  "sortablejs": "^1.15.2",
20
- "tinymce": "^6.8.3"
20
+ "tinymce": "^7.1.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@babel/core": "^7.23.7",
24
- "@babel/preset-env": "^7.23.7",
23
+ "@babel/core": "^7.24.5",
24
+ "@babel/preset-env": "^7.24.5",
25
25
  "@rollup/plugin-commonjs": "^25.0.7",
26
26
  "@rollup/plugin-node-resolve": "^15.2.3",
27
27
  "@rollup/plugin-terser": "^0.4.4",
28
28
  "babel-jest": "^29.6.4",
29
- "eslint": "^8.56.0",
29
+ "eslint": "^8.57.0",
30
30
  "jest": "^29.6.4",
31
31
  "jest-environment-jsdom": "^29.6.4",
32
32
  "jquery": "^3.7.1",
33
- "jsdom-testing-mocks": "^1.11.0",
34
- "prettier": "^3.2.4",
35
- "rollup": "^4.9.5",
33
+ "jsdom-testing-mocks": "^1.13.0",
34
+ "prettier": "^3.2.5",
35
+ "rollup": "^4.17.2",
36
36
  "xhr-mock": "^2.5.1"
37
37
  },
38
38
  "jest": {