alchemy_cms 8.3.11 → 8.4.1

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 (368) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +58 -10
  4. data/app/assets/builds/alchemy/admin/page-select.css +1 -1
  5. data/app/assets/builds/alchemy/admin/print.css +1 -1
  6. data/app/assets/builds/alchemy/admin/remote-select.css +1 -0
  7. data/app/assets/builds/alchemy/admin/tags-autocomplete.css +1 -0
  8. data/app/assets/builds/alchemy/admin.css +4 -4
  9. data/app/assets/builds/alchemy/alchemy_admin.min.js +1 -1
  10. data/app/assets/builds/alchemy/alchemy_admin.min.js.map +1 -1
  11. data/app/assets/builds/alchemy/dark-theme.css +1 -1
  12. data/app/assets/builds/alchemy/light-theme.css +1 -1
  13. data/app/assets/builds/alchemy/preview.min.js +1 -1
  14. data/app/assets/builds/alchemy/theme.css +1 -1
  15. data/app/assets/builds/alchemy/welcome.css +1 -1
  16. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
  17. data/app/assets/builds/tinymce/skins/content/alchemy-dark/content.min.css +1 -1
  18. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
  19. data/app/assets/builds/tinymce/skins/ui/alchemy-dark/skin.min.css +1 -1
  20. data/app/assets/images/alchemy/icons-sprite.svg +1 -1
  21. data/app/components/alchemy/admin/dashboard/widgets/greeting.html.erb +1 -1
  22. data/app/components/alchemy/admin/dashboard/widgets/news_reader.html.erb +38 -0
  23. data/app/components/alchemy/admin/dashboard/widgets/news_reader.rb +54 -0
  24. data/app/components/alchemy/admin/dashboard/widgets/online_users.html.erb +1 -1
  25. data/app/components/alchemy/admin/dashboard/widgets/recent_pages.html.erb +1 -1
  26. data/app/components/alchemy/admin/dashboard/widgets/system_info.html.erb +11 -3
  27. data/app/components/alchemy/admin/dashboard/widgets/system_info.rb +6 -1
  28. data/app/components/alchemy/admin/element_editor.html.erb +1 -1
  29. data/app/components/alchemy/admin/element_select.rb +30 -20
  30. data/app/components/alchemy/admin/element_status_indicators.html.erb +16 -0
  31. data/app/components/alchemy/admin/element_status_indicators.rb +31 -0
  32. data/app/components/alchemy/admin/link_dialog/external_tab.rb +2 -1
  33. data/app/components/alchemy/admin/main_navigation/entry.rb +61 -0
  34. data/app/components/alchemy/admin/main_navigation/menu.rb +21 -0
  35. data/app/components/alchemy/admin/main_navigation/sub_navigation.rb +31 -0
  36. data/app/components/alchemy/admin/page_node.html.erb +1 -1
  37. data/app/components/alchemy/admin/page_permitted_roles_select.html.erb +11 -0
  38. data/app/components/alchemy/admin/page_permitted_roles_select.rb +35 -0
  39. data/app/components/alchemy/admin/page_select.rb +18 -8
  40. data/app/components/alchemy/admin/preview_time_select.rb +1 -1
  41. data/app/components/alchemy/admin/toolbar_button.rb +43 -20
  42. data/app/components/alchemy/admin/uploader_button.rb +66 -0
  43. data/app/components/alchemy/ingredients/base_editor.rb +10 -1
  44. data/app/components/alchemy/ingredients/boolean_editor.rb +1 -0
  45. data/app/components/alchemy/ingredients/color_editor.rb +6 -3
  46. data/app/components/alchemy/ingredients/datetime_view.rb +1 -1
  47. data/app/components/alchemy/ingredients/picture_view.rb +2 -4
  48. data/app/components/alchemy/menubar.html.erb +157 -0
  49. data/app/components/alchemy/menubar.rb +15 -0
  50. data/app/controllers/alchemy/admin/attachments_controller.rb +12 -9
  51. data/app/controllers/alchemy/admin/base_controller.rb +34 -21
  52. data/app/controllers/alchemy/admin/dashboard_controller.rb +4 -0
  53. data/app/controllers/alchemy/admin/elements_controller.rb +4 -23
  54. data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
  55. data/app/controllers/alchemy/admin/nodes_controller.rb +1 -1
  56. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  57. data/app/controllers/alchemy/admin/pictures_controller.rb +6 -3
  58. data/app/controllers/alchemy/admin/resources_controller.rb +5 -5
  59. data/app/controllers/alchemy/admin/sites_controller.rb +1 -1
  60. data/app/controllers/alchemy/base_controller.rb +24 -16
  61. data/app/controllers/alchemy/pages_controller.rb +29 -8
  62. data/app/controllers/alchemy/sitemap_controller.rb +58 -0
  63. data/app/controllers/concerns/alchemy/admin/csp_protection.rb +43 -0
  64. data/app/controllers/concerns/alchemy/admin/current_language.rb +1 -1
  65. data/app/controllers/concerns/alchemy/admin/resource_filter.rb +3 -1
  66. data/{lib → app/controllers/concerns}/alchemy/controller_actions.rb +13 -0
  67. data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +4 -4
  68. data/app/helpers/alchemy/admin/base_helper.rb +4 -1
  69. data/app/helpers/alchemy/admin/form_helper.rb +0 -2
  70. data/app/helpers/alchemy/admin/navigation_helper.rb +10 -181
  71. data/app/helpers/alchemy/elements_block_helper.rb +14 -0
  72. data/app/helpers/alchemy/resources_helper.rb +15 -1
  73. data/app/javascript/alchemy_admin/components/attachment_select.js +11 -20
  74. data/app/javascript/alchemy_admin/components/auto_submit.js +2 -4
  75. data/app/javascript/alchemy_admin/components/button.js +0 -6
  76. data/app/javascript/alchemy_admin/components/clear_schedule_button.js +21 -0
  77. data/app/javascript/alchemy_admin/components/color_select.js +50 -45
  78. data/app/javascript/alchemy_admin/components/conditional_field.js +50 -0
  79. data/app/javascript/alchemy_admin/components/dirty_guard.js +77 -0
  80. data/app/javascript/alchemy_admin/components/dom_id_select.js +17 -10
  81. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +7 -2
  82. data/app/javascript/alchemy_admin/components/element_editor.js +29 -56
  83. data/app/javascript/alchemy_admin/components/element_select.js +26 -66
  84. data/app/javascript/alchemy_admin/components/icon.js +9 -4
  85. data/app/javascript/alchemy_admin/{image_cropper.js → components/image_cropper.js} +39 -53
  86. data/app/javascript/alchemy_admin/components/image_overlay_link.js +14 -0
  87. data/app/javascript/alchemy_admin/components/index.js +12 -1
  88. data/app/javascript/alchemy_admin/components/main_navi_entry.js +75 -0
  89. data/app/javascript/alchemy_admin/components/menu_node.js +73 -0
  90. data/app/javascript/alchemy_admin/components/news_reader.js +109 -0
  91. data/app/javascript/alchemy_admin/components/node_folder.js +36 -0
  92. data/app/javascript/alchemy_admin/components/node_form.js +34 -0
  93. data/app/javascript/alchemy_admin/components/node_select.js +25 -30
  94. data/app/javascript/alchemy_admin/components/node_tree.js +56 -0
  95. data/app/javascript/alchemy_admin/components/page_node.js +2 -1
  96. data/app/javascript/alchemy_admin/components/page_select.js +16 -34
  97. data/app/javascript/alchemy_admin/components/picture_archive.js +92 -0
  98. data/app/javascript/alchemy_admin/components/picture_editor.js +2 -1
  99. data/app/javascript/alchemy_admin/components/preview_window.js +11 -3
  100. data/app/javascript/alchemy_admin/components/remote_select.js +461 -81
  101. data/app/javascript/alchemy_admin/components/select.js +26 -88
  102. data/app/javascript/alchemy_admin/components/sitemap.js +2 -1
  103. data/app/javascript/alchemy_admin/components/sortable_elements.js +2 -1
  104. data/app/javascript/alchemy_admin/components/tags_autocomplete.js +63 -48
  105. data/app/javascript/alchemy_admin/components/tinymce.js +2 -1
  106. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +3 -2
  107. data/app/javascript/alchemy_admin/components/uploader.js +19 -3
  108. data/app/javascript/alchemy_admin/confirm_dialog.js +7 -1
  109. data/app/javascript/alchemy_admin/dialog.js +182 -110
  110. data/app/javascript/alchemy_admin/hotkeys.js +0 -5
  111. data/app/javascript/alchemy_admin/i18n.js +3 -9
  112. data/app/javascript/alchemy_admin/image_overlay.js +58 -42
  113. data/app/javascript/alchemy_admin/initializer.js +2 -2
  114. data/app/javascript/alchemy_admin/link_dialog.js +15 -2
  115. data/app/javascript/alchemy_admin/routes.js +18 -0
  116. data/app/javascript/alchemy_admin/turbo_stream_actions.js +88 -0
  117. data/app/javascript/alchemy_admin/utils/ajax.js +14 -3
  118. data/app/javascript/alchemy_admin/utils/events.js +5 -0
  119. data/app/javascript/alchemy_admin/utils/json_script.js +12 -0
  120. data/app/javascript/alchemy_admin/utils/tom_select.js +171 -0
  121. data/app/javascript/alchemy_admin.js +2 -19
  122. data/app/javascript/preview.js +131 -113
  123. data/app/jobs/alchemy/invalidate_elements_cache_job.rb +1 -1
  124. data/app/models/alchemy/admin/content_security_policy.rb +143 -0
  125. data/app/models/alchemy/admin/filters/base.rb +7 -0
  126. data/app/models/alchemy/admin/filters/datepicker.rb +1 -1
  127. data/app/models/alchemy/admin/filters/select.rb +20 -7
  128. data/app/models/alchemy/attachment.rb +14 -7
  129. data/app/models/alchemy/cache_control.rb +104 -0
  130. data/app/models/alchemy/current.rb +1 -1
  131. data/app/models/alchemy/eager_loading.rb +0 -2
  132. data/app/models/alchemy/element.rb +23 -8
  133. data/app/models/alchemy/element_definition.rb +1 -0
  134. data/app/models/alchemy/elements_repository.rb +11 -0
  135. data/app/models/alchemy/folded_page.rb +5 -1
  136. data/app/models/alchemy/ingredient.rb +26 -0
  137. data/app/models/alchemy/ingredients/datetime.rb +1 -1
  138. data/app/models/alchemy/ingredients/link.rb +2 -0
  139. data/app/models/alchemy/ingredients/picture.rb +3 -0
  140. data/app/models/alchemy/ingredients/text.rb +2 -0
  141. data/app/models/alchemy/language.rb +19 -7
  142. data/app/models/alchemy/legacy_page_url.rb +6 -1
  143. data/app/models/alchemy/node.rb +51 -0
  144. data/app/models/alchemy/page/page_natures.rb +41 -8
  145. data/app/models/alchemy/page/page_scopes.rb +23 -0
  146. data/app/models/alchemy/page/sitemap_cache_key.rb +56 -0
  147. data/app/models/alchemy/page.rb +88 -32
  148. data/app/models/alchemy/page_definition.rb +1 -1
  149. data/app/models/alchemy/page_mutex.rb +16 -0
  150. data/app/models/alchemy/page_version.rb +24 -1
  151. data/app/models/alchemy/permissions.rb +6 -5
  152. data/app/models/alchemy/picture.rb +15 -7
  153. data/app/models/alchemy/picture_description.rb +22 -0
  154. data/app/models/alchemy/picture_thumb.rb +18 -0
  155. data/app/models/alchemy/publishable/timestamp_resolver.rb +70 -0
  156. data/app/models/alchemy/resource.rb +1 -1
  157. data/app/models/alchemy/safe_url_validator.rb +34 -0
  158. data/app/models/alchemy/site.rb +8 -3
  159. data/app/models/alchemy/storage_adapter/active_storage/preprocessor.rb +7 -3
  160. data/app/models/alchemy/storage_adapter/active_storage.rb +4 -1
  161. data/app/models/alchemy/tag.rb +10 -4
  162. data/{lib → app/models/concerns}/alchemy/filetypes.rb +5 -0
  163. data/app/models/concerns/alchemy/picture_thumbnails.rb +61 -6
  164. data/app/models/concerns/alchemy/publishable.rb +14 -27
  165. data/app/models/concerns/alchemy/taggable.rb +92 -0
  166. data/app/models/concerns/alchemy/user_methods.rb +95 -0
  167. data/app/services/alchemy/duplicate_element.rb +5 -2
  168. data/app/services/alchemy/element_preloader.rb +1 -2
  169. data/app/stylesheets/alchemy/_custom-properties.scss +1 -0
  170. data/app/stylesheets/alchemy/_extends.scss +0 -8
  171. data/app/stylesheets/alchemy/_themes.scss +10 -9
  172. data/app/stylesheets/alchemy/admin/_empty-state.scss +29 -0
  173. data/app/stylesheets/alchemy/admin/_help.scss +10 -0
  174. data/app/stylesheets/alchemy/admin/_tom-select.scss +104 -15
  175. data/app/stylesheets/alchemy/admin/archive.scss +56 -11
  176. data/app/stylesheets/alchemy/admin/base.scss +4 -5
  177. data/app/stylesheets/alchemy/admin/buttons.scss +12 -1
  178. data/app/stylesheets/alchemy/admin/dashboard.scss +150 -20
  179. data/app/stylesheets/alchemy/admin/dialogs.scss +27 -36
  180. data/app/stylesheets/alchemy/admin/element-select.scss +1 -1
  181. data/app/stylesheets/alchemy/admin/elements.scss +8 -24
  182. data/app/stylesheets/alchemy/admin/flash.scss +2 -1
  183. data/app/stylesheets/alchemy/admin/forms.scss +60 -24
  184. data/app/stylesheets/alchemy/admin/frame.scss +40 -4
  185. data/app/stylesheets/alchemy/admin/image_library.scss +9 -12
  186. data/app/stylesheets/alchemy/admin/navigation.scss +17 -14
  187. data/app/stylesheets/alchemy/admin/node-select.scss +13 -37
  188. data/app/stylesheets/alchemy/admin/nodes.scss +1 -1
  189. data/app/stylesheets/alchemy/admin/page-select.scss +6 -97
  190. data/app/stylesheets/alchemy/admin/print.scss +0 -4
  191. data/app/stylesheets/alchemy/admin/remote-select.scss +170 -0
  192. data/app/stylesheets/alchemy/admin/search.scss +2 -3
  193. data/app/stylesheets/alchemy/admin/selects.scss +1 -294
  194. data/app/stylesheets/alchemy/admin/sitemap.scss +2 -1
  195. data/app/stylesheets/alchemy/admin/tables.scss +7 -1
  196. data/app/stylesheets/alchemy/admin/tags-autocomplete.scss +17 -0
  197. data/app/stylesheets/alchemy/admin/tags.scss +0 -13
  198. data/app/stylesheets/alchemy/admin/toolbar.scss +9 -6
  199. data/app/stylesheets/alchemy/admin/upload.scss +61 -1
  200. data/app/stylesheets/alchemy/admin.scss +4 -1
  201. data/app/types/alchemy/cache_control_type.rb +84 -0
  202. data/app/views/alchemy/_edit_mode.html.erb +1 -1
  203. data/app/views/alchemy/_menubar.html.erb +2 -154
  204. data/app/views/alchemy/_preview_mode_code.html.erb +0 -3
  205. data/app/views/alchemy/admin/_left_menu.html.erb +18 -5
  206. data/app/views/alchemy/admin/_top_menu.html.erb +1 -1
  207. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +5 -4
  208. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +3 -3
  209. data/app/views/alchemy/admin/attachments/_files_list.html.erb +71 -83
  210. data/app/views/alchemy/admin/attachments/assign.turbo_stream.erb +8 -0
  211. data/app/views/alchemy/admin/attachments/index.html.erb +32 -7
  212. data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +1 -1
  213. data/app/views/alchemy/admin/crop.html.erb +20 -20
  214. data/app/views/alchemy/admin/dashboard/_footer.html.erb +0 -3
  215. data/app/views/alchemy/admin/dashboard/_top.html.erb +1 -0
  216. data/app/views/alchemy/admin/dashboard/help.html.erb +84 -57
  217. data/app/views/alchemy/admin/dashboard/license.html.erb +6 -0
  218. data/app/views/alchemy/admin/elements/_footer.html.erb +0 -1
  219. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  220. data/app/views/alchemy/admin/elements/_header.html.erb +2 -19
  221. data/app/views/alchemy/admin/elements/_preview_text_quote.html.erb +3 -0
  222. data/app/views/alchemy/admin/elements/_schedule.html.erb +7 -7
  223. data/app/views/alchemy/admin/elements/_toolbar.html.erb +1 -1
  224. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +1 -1
  225. data/app/views/alchemy/admin/elements/index.html.erb +1 -1
  226. data/app/views/alchemy/admin/elements/publish.turbo_stream.erb +2 -2
  227. data/app/views/alchemy/admin/elements/update.turbo_stream.erb +31 -0
  228. data/app/views/alchemy/admin/ingredients/update.turbo_stream.erb +6 -3
  229. data/app/views/alchemy/admin/languages/_table.html.erb +0 -2
  230. data/app/views/alchemy/admin/languages/index.html.erb +25 -29
  231. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +1 -3
  232. data/app/views/alchemy/admin/layoutpages/edit.html.erb +1 -1
  233. data/app/views/alchemy/admin/layoutpages/index.html.erb +26 -7
  234. data/app/views/alchemy/admin/nodes/_form.html.erb +3 -21
  235. data/app/views/alchemy/admin/nodes/_node.html.erb +93 -88
  236. data/app/views/alchemy/admin/nodes/index.html.erb +15 -23
  237. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +2 -6
  238. data/app/views/alchemy/admin/pages/_form.html.erb +2 -1
  239. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +1 -1
  240. data/app/views/alchemy/admin/pages/_table.html.erb +2 -4
  241. data/app/views/alchemy/admin/pages/_toolbar.html.erb +2 -1
  242. data/app/views/alchemy/admin/pages/edit.html.erb +10 -21
  243. data/app/views/alchemy/admin/pages/flush.turbo_stream.erb +1 -1
  244. data/app/views/alchemy/admin/pages/index.html.erb +26 -31
  245. data/app/views/alchemy/admin/pages/info.html.erb +2 -2
  246. data/app/views/alchemy/admin/pages/update.turbo_stream.erb +2 -2
  247. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  248. data/app/views/alchemy/admin/partials/_routes.html.erb +24 -48
  249. data/app/views/alchemy/admin/pictures/_archive.html.erb +3 -17
  250. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
  251. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +5 -3
  252. data/app/views/alchemy/admin/pictures/_form.html.erb +0 -1
  253. data/app/views/alchemy/admin/pictures/_infos.html.erb +5 -1
  254. data/app/views/alchemy/admin/pictures/_picture.html.erb +1 -1
  255. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +3 -4
  256. data/app/views/alchemy/admin/pictures/assign.turbo_stream.erb +7 -0
  257. data/app/views/alchemy/admin/pictures/index.html.erb +38 -30
  258. data/app/views/alchemy/admin/pictures/show.html.erb +41 -41
  259. data/app/views/alchemy/admin/resources/_empty_state.html.erb +27 -0
  260. data/app/views/alchemy/admin/resources/_pagination.html.erb +1 -1
  261. data/app/views/alchemy/admin/resources/_per_page_select.html.erb +1 -1
  262. data/app/views/alchemy/admin/resources/_resource_table.html.erb +0 -2
  263. data/app/views/alchemy/admin/resources/_resource_usage_info.html.erb +3 -2
  264. data/app/views/alchemy/admin/resources/index.html.erb +32 -13
  265. data/app/views/alchemy/admin/sites/index.html.erb +24 -22
  266. data/app/views/alchemy/admin/styleguide/index.html.erb +35 -12
  267. data/app/views/alchemy/admin/tags/index.html.erb +27 -25
  268. data/app/views/alchemy/admin/tinymce/_setup.html.erb +6 -8
  269. data/app/views/alchemy/admin/translations/_en.js +3 -0
  270. data/app/views/alchemy/admin/uploader/_button.html.erb +11 -17
  271. data/app/views/alchemy/admin/uploader/_setup.html.erb +3 -3
  272. data/app/views/alchemy/pages/sitemap.xml.erb +2 -0
  273. data/app/views/kaminari/alchemy/_first_page.html.erb +1 -2
  274. data/app/views/kaminari/alchemy/_gap.html.erb +0 -1
  275. data/app/views/kaminari/alchemy/_last_page.html.erb +1 -2
  276. data/app/views/kaminari/alchemy/_next_page.html.erb +1 -2
  277. data/app/views/kaminari/alchemy/_page.html.erb +1 -2
  278. data/app/views/kaminari/alchemy/_paginator.html.erb +0 -1
  279. data/app/views/kaminari/alchemy/_prev_page.html.erb +1 -2
  280. data/app/views/layouts/alchemy/admin/dialog.html.erb +3 -0
  281. data/app/views/layouts/alchemy/admin.html.erb +5 -6
  282. data/config/brakeman.ignore +23 -1
  283. data/config/importmap.rb +10 -8
  284. data/config/initializers/dragonfly.rb +21 -17
  285. data/config/locales/alchemy.en.yml +52 -11
  286. data/config/routes.rb +3 -3
  287. data/db/migrate/20260727120000_add_permitted_roles_to_alchemy_pages.rb +23 -0
  288. data/db/migrate/20260820120000_add_cached_tag_list_to_taggables.rb +57 -0
  289. data/lib/alchemy/configuration/number_option.rb +13 -0
  290. data/lib/alchemy/configuration/proc_option.rb +13 -0
  291. data/lib/alchemy/configuration.rb +2 -0
  292. data/lib/alchemy/configurations/admin_components.rb +30 -0
  293. data/lib/alchemy/configurations/format_matchers.rb +7 -1
  294. data/lib/alchemy/configurations/main.rb +103 -4
  295. data/lib/alchemy/configurations/menu.rb +91 -0
  296. data/lib/alchemy/configurations/menu_item.rb +123 -0
  297. data/lib/alchemy/configurations/sitemap.rb +1 -0
  298. data/lib/alchemy/configurations/uploader.rb +15 -1
  299. data/lib/alchemy/engine.rb +0 -6
  300. data/lib/alchemy/i18n.rb +26 -0
  301. data/lib/alchemy/modules.rb +52 -50
  302. data/lib/alchemy/tasks/generate_thumbnails.rb +99 -0
  303. data/lib/alchemy/tasks/tidy.rb +1 -1
  304. data/lib/alchemy/test_support/capybara_helpers.rb +48 -37
  305. data/lib/alchemy/test_support/current_language_shared_examples.rb +1 -1
  306. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +4 -1
  307. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +132 -0
  308. data/lib/alchemy/test_support/shared_ingredient_examples.rb +52 -0
  309. data/lib/alchemy/test_support/shared_publishable_examples.rb +29 -4
  310. data/lib/alchemy/upgrader/eight_four.rb +237 -0
  311. data/lib/alchemy/upgrader/register_module_rewriter.rb +177 -0
  312. data/lib/alchemy/upgrader.rb +2 -1
  313. data/lib/alchemy/version.rb +1 -1
  314. data/lib/alchemy.rb +0 -1
  315. data/lib/alchemy_cms.rb +0 -13
  316. data/lib/generators/alchemy/elements/templates/view.html.erb +1 -1
  317. data/lib/generators/alchemy/elements/templates/view.html.haml +1 -1
  318. data/lib/generators/alchemy/elements/templates/view.html.slim +1 -1
  319. data/lib/generators/alchemy/install/install_generator.rb +2 -13
  320. data/lib/generators/alchemy/install/templates/alchemy.rb.tt +24 -9
  321. data/lib/generators/alchemy/module/module_generator.rb +1 -0
  322. data/lib/generators/alchemy/module/templates/ability.rb.tt +1 -1
  323. data/lib/generators/alchemy/module/templates/module_config.rb.tt +16 -18
  324. data/lib/generators/alchemy/user_columns_migration/templates/migration.rb.tt +19 -0
  325. data/lib/generators/alchemy/user_columns_migration/user_columns_migration_generator.rb +30 -0
  326. data/lib/tasks/alchemy/thumbnails.rake +16 -29
  327. data/lib/tasks/alchemy/upgrade.rake +45 -3
  328. data/vendor/javascript/cropperjs.min.js +3 -3
  329. data/vendor/javascript/floating-ui.min.js +1 -1
  330. data/vendor/javascript/tinymce.min.js +5 -5
  331. data/vendor/javascript/tom-select.min.js +1 -1
  332. metadata +85 -65
  333. data/app/javascript/alchemy_admin/components/action.js +0 -50
  334. data/app/javascript/alchemy_admin/dirty.js +0 -55
  335. data/app/javascript/alchemy_admin/node_tree.js +0 -82
  336. data/app/javascript/alchemy_admin/picture_selector.js +0 -67
  337. data/app/javascript/alchemy_admin/templates/compiled.js +0 -1
  338. data/app/javascript/alchemy_admin/templates/node_folder.hbs +0 -3
  339. data/app/stylesheets/alchemy/admin/attachment-select.scss +0 -19
  340. data/app/views/alchemy/admin/_main_navi.html.erb +0 -6
  341. data/app/views/alchemy/admin/attachments/assign.js.erb +0 -15
  342. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +0 -30
  343. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +0 -20
  344. data/app/views/alchemy/admin/partials/_sub_navigation.html.erb +0 -11
  345. data/app/views/alchemy/admin/pictures/assign.js.erb +0 -13
  346. data/app/views/alchemy/base/error_notice.js.erb +0 -1
  347. data/app/views/alchemy/base/permission_denied.js.erb +0 -3
  348. data/app/views/alchemy/base/redirect.js.erb +0 -11
  349. data/config/alchemy/config.yml +0 -217
  350. data/config/alchemy/modules.yml +0 -82
  351. data/config/initializers/rails_live_reload.rb +0 -13
  352. data/lib/alchemy/dev_support/live_reload_watcher.rb +0 -5
  353. data/lib/alchemy/taggable.rb +0 -49
  354. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +0 -34
  355. data/vendor/assets/stylesheets/alchemy_admin/select2.css +0 -1
  356. data/vendor/javascript/handlebars.min.js +0 -29
  357. data/vendor/javascript/jquery.min.js +0 -2
  358. data/vendor/javascript/rails-ujs.min.js +0 -1
  359. data/vendor/javascript/select2.min.js +0 -23
  360. /data/{lib → app/controllers/concerns}/alchemy/ability_helper.rb +0 -0
  361. /data/{lib → app/controllers/concerns}/alchemy/admin/locale.rb +0 -0
  362. /data/{lib → app/controllers/concerns}/alchemy/admin/preview_time.rb +0 -0
  363. /data/{lib → app/controllers/concerns}/alchemy/admin/timezone.rb +0 -0
  364. /data/{lib → app/controllers/concerns}/alchemy/configuration_methods.rb +0 -0
  365. /data/{lib → app/models}/alchemy/admin/preview_url.rb +0 -0
  366. /data/{lib → app/models/concerns}/alchemy/hints.rb +0 -0
  367. /data/{lib → app/models/concerns}/alchemy/name_conversions.rb +0 -0
  368. /data/{lib → app/services}/alchemy/elements_finder.rb +0 -0
@@ -1,55 +0,0 @@
1
- import { openConfirmDialog } from "alchemy_admin/confirm_dialog"
2
- import { translate } from "alchemy_admin/i18n"
3
- import pleaseWaitOverlay from "alchemy_admin/please_wait_overlay"
4
-
5
- function checkPageDirtyness(element) {
6
- let callback = () => {}
7
-
8
- if ($(element).is("form")) {
9
- callback = function () {
10
- const $form = $(
11
- `<form action="${element.action}" method="POST" style="display: none" />`
12
- )
13
- $form.append($(element).find("input"))
14
- $form.appendTo("body")
15
-
16
- pleaseWaitOverlay()
17
- $form.trigger("submit")
18
- }
19
- } else if ($(element).is("a")) {
20
- callback = () => Turbo.visit(element.pathname)
21
- }
22
-
23
- const isPageDirty =
24
- document.querySelectorAll("alchemy-element-editor.dirty").length > 0
25
-
26
- if (isPageDirty) {
27
- openConfirmDialog(translate("page_dirty_notice"), {
28
- title: translate("warning"),
29
- ok_label: translate("ok"),
30
- cancel_label: translate("cancel")
31
- }).then((proceed) => {
32
- if (proceed) {
33
- window.onbeforeunload = void 0
34
- callback()
35
- }
36
- })
37
- return false
38
- }
39
- return true
40
- }
41
-
42
- function PageLeaveObserver() {
43
- document.querySelectorAll("#main_navi a").forEach((element) => {
44
- element.addEventListener("click", (event) => {
45
- if (!checkPageDirtyness(event.currentTarget)) {
46
- event.preventDefault()
47
- }
48
- })
49
- })
50
- }
51
-
52
- export default {
53
- checkPageDirtyness,
54
- PageLeaveObserver
55
- }
@@ -1,82 +0,0 @@
1
- import Sortable from "sortablejs"
2
- import { patch } from "alchemy_admin/utils/ajax"
3
- import { on } from "alchemy_admin/utils/events"
4
- import { growl } from "alchemy_admin/growler"
5
-
6
- function displayNodeFolders() {
7
- document.querySelectorAll("li.menu-item").forEach((el) => {
8
- const leftIconArea = el.querySelector(".nodes_tree-left_images")
9
- const list = el.querySelector(".children")
10
- const node = {
11
- folded: el.dataset.folded === "true",
12
- id: el.dataset.id,
13
- type: el.dataset.type
14
- }
15
-
16
- if (list.children.length > 0 || node.folded) {
17
- leftIconArea.innerHTML = Handlebars.templates["node_folder.hbs"]({
18
- node: node
19
- })
20
- } else {
21
- leftIconArea.innerHTML = "&nbsp;"
22
- }
23
- })
24
- }
25
-
26
- function onFinishDragging(evt) {
27
- const url = Alchemy.routes[evt.item.dataset.type].move_api_path(
28
- evt.item.dataset.id
29
- )
30
- const data = {
31
- target_parent_id: evt.to.dataset.recordId,
32
- new_position: evt.newIndex
33
- }
34
-
35
- patch(url, data)
36
- .then(() => {
37
- const message = Alchemy.t("Successfully moved menu item")
38
- growl(message)
39
- displayNodeFolders()
40
- })
41
- .catch((error) => {
42
- growl(error.message || error, "error")
43
- })
44
- }
45
-
46
- function handleNodeFolders() {
47
- on("click", ".nodes_tree", ".node_folder", function () {
48
- const nodeId = this.dataset.recordId
49
- const menu_item = this.closest("li.menu-item")
50
- const url =
51
- Alchemy.routes[this.dataset.recordType].toggle_folded_api_path(nodeId)
52
- const list = menu_item.querySelector(".children")
53
-
54
- patch(url)
55
- .then(() => {
56
- list.classList.toggle("folded")
57
- menu_item.dataset.folded =
58
- menu_item.dataset.folded == "true" ? "false" : "true"
59
- displayNodeFolders()
60
- })
61
- .catch((error) => {
62
- growl(error.message || error)
63
- })
64
- })
65
- }
66
-
67
- export default function NodeTree() {
68
- handleNodeFolders()
69
- displayNodeFolders()
70
-
71
- document.querySelectorAll(".nodes_tree ul.children").forEach((el) => {
72
- new Sortable(el, {
73
- group: "nodes",
74
- animation: 150,
75
- fallbackOnBody: true,
76
- swapThreshold: 0.65,
77
- handle: ".node_name",
78
- invertSwap: true,
79
- onEnd: onFinishDragging
80
- })
81
- })
82
- }
@@ -1,67 +0,0 @@
1
- import { on } from "alchemy_admin/utils/events"
2
- import { openDialog } from "alchemy_admin/dialog"
3
-
4
- function toggleCheckboxes(state) {
5
- document
6
- .querySelectorAll(".picture_tool.select input[type='checkbox']")
7
- .forEach((checkbox) => {
8
- checkbox.checked = state
9
- checkbox.closest(".picture_thumbnail").classList.toggle("active", state)
10
- })
11
- }
12
-
13
- function checkedInputs() {
14
- return document.querySelectorAll("#picture_archive input:checked")
15
- }
16
-
17
- function editMultiplePicturesUrl(href) {
18
- const url = new URL(href)
19
-
20
- checkedInputs().forEach((entry) =>
21
- url.searchParams.append(entry.name, entry.value)
22
- )
23
-
24
- return url.toString()
25
- }
26
-
27
- /**
28
- * Multiple picture select handler for the picture archive.
29
- */
30
- export default function PictureSelector() {
31
- const selectAllButton = document.querySelector("#select_all_pictures")
32
- const selectedItemTools = document.querySelector(".selected_item_tools")
33
-
34
- on("click", ".toolbar_buttons", "a#select_all_pictures", (event) => {
35
- event.preventDefault()
36
-
37
- selectAllButton.classList.toggle("active")
38
-
39
- const state = selectAllButton.classList.contains("active")
40
-
41
- toggleCheckboxes(state)
42
-
43
- selectedItemTools.classList.toggle("hidden", !state)
44
- })
45
-
46
- // make the item toolbar visible and show the checkbox also if it is not hovered anymore
47
- on("change", ".picture_tool.select", "input", (event) => {
48
- selectedItemTools.classList.toggle("hidden", checkedInputs().length === 0)
49
-
50
- const parentElementClassList = event.target.parentElement.classList
51
- const checked = event.target.checked
52
-
53
- parentElementClassList.toggle("visible", checked)
54
- })
55
-
56
- // open the edit view in a dialog modal
57
- on("click", ".selected_item_tools", "a#edit_multiple_pictures", (event) => {
58
- event.preventDefault()
59
-
60
- const url = editMultiplePicturesUrl(event.target.href)
61
-
62
- openDialog(url, {
63
- title: event.target.title,
64
- size: "400x295"
65
- })
66
- })
67
- }
@@ -1 +0,0 @@
1
- (()=>{var n=Handlebars.template;(Handlebars.templates=Handlebars.templates||{})["node_folder.hbs"]=n({0:function(n,e,l,a,r){return"right"},1:function(n,e,l,a,r){return"down"},compiler:[8,">= 4.3.0"],main:function(n,e,l,a,r){var o,t=n.lambda,d=n.escapeExpression,u=n.lookupProperty||function(n,e){if(Object.prototype.hasOwnProperty.call(n,e))return n[e]};return'<a class="node_folder" data-record-id="'+d(t(null!=(o=null!=e?u(e,"node"):e)?u(o,"id"):o,e))+'" data-record-type="'+d(t(null!=(o=null!=e?u(e,"node"):e)?u(o,"type"):o,e))+'">\n <alchemy-icon name="arrow-'+(null!=(o=u(l,"if").call(null!=e?e:n.nullContext||{},null!=(o=null!=e?u(e,"node"):e)?u(o,"folded"):o,{name:"if",hash:{},fn:n.program(0,r,0),inverse:n.program(1,r,0),data:r,loc:{start:{line:2,column:28},end:{line:2,column:72}}}))?o:"")+'-s"></alchemy-icon>\n</a>\n'},useData:!0})})();
@@ -1,3 +0,0 @@
1
- <a class="node_folder" data-record-id="{{ node.id }}" data-record-type="{{ node.type }}">
2
- <alchemy-icon name="arrow-{{#if node.folded }}right{{else}}down{{/if}}-s"></alchemy-icon>
3
- </a>
@@ -1,19 +0,0 @@
1
- .attachment-select--attachment {
2
- display: flex;
3
- align-items: center;
4
- height: 21px;
5
-
6
- .icon {
7
- margin: 0 var(--spacing-1) 0 0;
8
-
9
- .select2-highlighted & {
10
- fill: var(--color-white);
11
- }
12
- }
13
- }
14
-
15
- .attachment-select--attachment-name {
16
- text-overflow: ellipsis;
17
- overflow: hidden;
18
- white-space: nowrap;
19
- }
@@ -1,6 +0,0 @@
1
- <div id="main_navi">
2
- <% sorted_alchemy_modules.each do |alchemy_module| %>
3
- <%= alchemy_main_navigation_entry(alchemy_module) %>
4
- <% end %>
5
- <%= yield(:alchemy_main_navigation) %>
6
- </div>
@@ -1,15 +0,0 @@
1
- (function () {
2
- var $form_field = $("#<%= @form_field_id -%>")
3
- $("#assignable_<%= @assignable_id %> a").attr("href", "#").off("click")
4
- $form_field.val("<%= @assignable_id %>")
5
- $form_field.parent().find("> .file_name").text("<%= @attachment.name %>")
6
- $form_field.parent().find("> .file_icon").html("<%= j render_icon(@attachment.icon_css_class) %>")
7
- $form_field.parent().find("> .remove_file_link").removeClass("hidden")
8
- Alchemy.closeCurrentDialog(() => {
9
- const field = $form_field[0]
10
- const elementEditor = field.closest("alchemy-element-editor")
11
- if (elementEditor) {
12
- elementEditor.setDirty(field)
13
- }
14
- })
15
- })()
@@ -1,30 +0,0 @@
1
- <div id="page_layout_filter">
2
- <label>
3
- <h3><%= Alchemy::Page.human_attribute_name(:page_layout) %></h3>
4
- <%= select_tag(
5
- "page_layout",
6
- options_for_select(
7
- @current_language.site.page_layout_names.map do |layout|
8
- [
9
- Alchemy::Page.human_layout_name(layout),
10
- layout
11
- ]
12
- end,
13
- search_filter_params[:page_layout]
14
- ),
15
- include_blank: Alchemy.t(:all, scope: ["resources", "page", "filters"]),
16
- class: "full_width",
17
- is: "alchemy-select"
18
- ) %>
19
- </label>
20
- </div>
21
-
22
- <script type="module">
23
- $(function() {
24
- $("#page_layout").on("change", function(e) {
25
- var url = "<%= alchemy.admin_pages_path(search_filter_params.except(:page_layout, :page).merge(view: "list")) %>";
26
- delimiter = url.match(/\?/) ? "&" : "?";
27
- Turbo.visit(url + delimiter + "page_layout=" + encodeURIComponent($(this).val()));
28
- });
29
- });
30
- </script>
@@ -1,20 +0,0 @@
1
- <% if can? *navigate_module(navigation) %>
2
- <%= content_tag :div, class: main_navigation_css_classes(navigation), data: navigation["data"] do %>
3
- <%= link_to url_for_module(alchemy_module) do %>
4
- <% if navigation["image"] %>
5
- <%= image_tag(navigation["image"]) %>
6
- <% elsif navigation["inline_image"] %>
7
- <%== navigation["inline_image"] %>
8
- <% elsif navigation["icon"] %>
9
- <%= content_tag :"alchemy-icon", nil,
10
- name: navigation["icon"],
11
- "icon-style": navigation["icon-style"] %>
12
- <% else %>
13
- <%= render_icon :table %>
14
- <% end %>
15
- <label><%= Alchemy.t(navigation['name']) %></label>
16
- <% end %>
17
- <%= render 'alchemy/admin/partials/sub_navigation',
18
- entries: navigation['sub_navigation'] %>
19
- <% end %>
20
- <% end %>
@@ -1,11 +0,0 @@
1
- <% if entries.present? %>
2
- <div class="sub_navigation">
3
- <% entries.each do |entry| %>
4
- <% if can? *navigate_module(entry) %>
5
- <div class="subnavi_tab<%= entry_active?(entry) ? ' active' : nil %>">
6
- <%= link_to Alchemy.t(entry['name']), url_for_module_sub_navigation(entry) %>
7
- </div>
8
- <% end %>
9
- <% end %>
10
- </div>
11
- <% end %>
@@ -1,13 +0,0 @@
1
- (function () {
2
- var $form_field = $("#<%= @form_field_id -%>")
3
- $("#assignable_<%= @assignable_id %> a").attr("href", "#").off("click")
4
- $form_field.val("<%= @assignable_id %>")
5
- $form_field.attr("data-image-file-width", <%= @picture.image_file_width %>)
6
- $form_field.attr("data-image-file-height", <%= @picture.image_file_height %>)
7
- Alchemy.closeCurrentDialog(function() {
8
- var elementEditor = $form_field[0].closest("alchemy-element-editor")
9
- if (elementEditor) {
10
- elementEditor.setDirty()
11
- }
12
- })
13
- })()
@@ -1 +0,0 @@
1
- Alchemy.growl('<%= j @notice %>', 'error');
@@ -1,3 +0,0 @@
1
- Alchemy.closeCurrentDialog(function() {
2
- Turbo.visit('<%= Alchemy.config.login_path %>');
3
- });
@@ -1,11 +0,0 @@
1
- (function() {
2
- var dialog = Alchemy.currentDialog();
3
- var callback = function() {
4
- Turbo.visit('<%= url_for(@redirect_url).html_safe %>');
5
- };
6
- if (dialog) {
7
- Alchemy.closeCurrentDialog(callback);
8
- } else {
9
- callback();
10
- }
11
- })();
@@ -1,217 +0,0 @@
1
- # == This is the global Alchemy configuration file
2
- #
3
-
4
- # === Auto Log Out Time
5
- #
6
- # The amount of time of inactivity in minutes after which the user is kicked out of his current session.
7
- #
8
- # NOTE: This is only active in production environments
9
- #
10
- auto_logout_time: 30
11
-
12
- # === Page caching
13
- #
14
- # Enable/Disable page caching globally.
15
- #
16
- # NOTE: You can enable/disable page caching for single Alchemy::Definitions in the page_layout.yml file.
17
- #
18
- cache_pages: true
19
-
20
- # === Sitemap
21
- #
22
- # Alchemy creates a XML, Google compatible, sitemap for you.
23
- #
24
- # The url is: http://your-domain.tld/sitemap.xml
25
- #
26
- # ==== Config Options:
27
- #
28
- # show_root [Boolean] # Show language root page in sitemap?
29
- # show_flag [Boolean] # Enables the Checkbox in Page#update overlay. So your customer can set the visibility of pages in the sitemap.
30
- #
31
- sitemap:
32
- show_root: true
33
- show_flag: false
34
-
35
- # === Default items per page in admin views
36
- #
37
- # In Alchemy's Admin, change how many items you would get shown per page by Kaminari
38
- items_per_page: 15
39
-
40
- # === Preview window URL configuration
41
- #
42
- # By default Alchemy uses its internal page preview renderer,
43
- # but you can configure it to be any URL instead.
44
- #
45
- # Basic Auth is supported.
46
- #
47
- # preview:
48
- # host: https://www.my-static-site.com
49
- # auth:
50
- # username: <%= ENV["BASIC_AUTH_USERNAME"] %>
51
- # password: <%= ENV["BASIC_AUTH_PASSWORD"] %>
52
- #
53
- # Preview config per site is supported as well.
54
- #
55
- # preview:
56
- # My site name:
57
- # host: https://www.my-static-site.com
58
- # auth:
59
- # username: <%= ENV["BASIC_AUTH_USERNAME"] %>
60
- # password: <%= ENV["BASIC_AUTH_PASSWORD"] %>
61
- #
62
-
63
- # === Picture rendering settings
64
- #
65
- # Alchemy uses Dragonfly to render images. Settings for image rendering are specific to elements and are defined in elements.yml
66
- #
67
- # Example:
68
- # - name: some_element
69
- # ingredients:
70
- # - role: some_picture
71
- # type: Picture
72
- # settings:
73
- # hint: true
74
- # crop: true # turns on image cropping
75
- # size: '500x500' # image will be cropped to this size
76
- #
77
- # See http://markevans.github.com/dragonfly for further info.
78
- #
79
- # ==== Global Options:
80
- #
81
- # output_image_quality [Integer] # If image gets rendered as JPG or WebP this is the quality setting for it. (Default 85)
82
- # 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)
83
- # image_output_format [String] # The global image output format setting. (Default +original+)
84
- #
85
- # NOTE: You can always override the output format in the settings of your ingredients in elements.yml, I.E. {format: 'gif'}
86
- #
87
- output_image_quality: 85
88
- preprocess_image_resize:
89
- image_output_format: original
90
- sharpen_images: false
91
-
92
- # This is used by the seeder to create the default site.
93
- default_site:
94
- name: Default Site
95
- host: "*"
96
-
97
- # This is the default language when seeding.
98
- default_language:
99
- code: en
100
- name: English
101
- page_layout: index
102
- frontpage_name: Index
103
-
104
- # === Mailer Settings:
105
- #
106
- # To send emails via contact forms, you can create your form fields here and set which fields are to be validated.
107
- #
108
- # === Validating fields:
109
- #
110
- # Pass the field name as a symbol and a message_id (will be translated) to :validate_fields:
111
- #
112
- # ==== Options:
113
- #
114
- # page_layout_name: [String] # A +Alchemy::PageDefinition+ name. Used to render the contactform on a page with this layout.
115
- # fields: [Array] # An Array of fieldnames.
116
- # validate_fields: [Array] # An Array of fieldnames to be validated on presence.
117
- #
118
- # ==== Translating validation messages:
119
- #
120
- # The validation messages are passed through ::I18n.t so you can translate it in your language yml file.
121
- #
122
- # ==== Example:
123
- #
124
- # de:
125
- # activemodel:
126
- # attributes:
127
- # alchemy/message:
128
- # firstname: Vorname
129
- #
130
- mailer:
131
- page_layout_name: contact
132
- forward_to_page: false
133
- mail_success_page: thanks
134
- mail_from: your.mail@your-domain.com
135
- mail_to: your.mail@your-domain.com
136
- subject: A new contact form message
137
- fields:
138
- [salutation, firstname, lastname, address, zip, city, phone, email, message]
139
- validate_fields: [lastname, email]
140
-
141
- # === User roles
142
- #
143
- # You can add own user roles.
144
- #
145
- # Further documentation for the auth system used please visit:
146
- #
147
- # https://github.com/ryanb/cancan/wiki
148
- #
149
- # ==== Translating User roles
150
- #
151
- # Userroles can be translated inside your the language yml file under:
152
- #
153
- # alchemy:
154
- # user_roles:
155
- # rolename: Name of the role
156
- #
157
- user_roles: [member, author, editor, admin]
158
-
159
- # === Uploader Settings
160
- #
161
- # upload_limit [Integer] # Set an amount of files upload limit of files which can be uploaded at once. Set 0 for unlimited.
162
- # file_size_limit* [Integer] # Set a file size limit in mega bytes for a per file limit.
163
- #
164
- # *) Allow filetypes to upload. Pass * to allow all kind of files.
165
- #
166
- uploader:
167
- upload_limit: 50
168
- file_size_limit: 100
169
- allowed_filetypes:
170
- alchemy/attachments:
171
- - "*"
172
- alchemy/pictures:
173
- - jpg
174
- - jpeg
175
- - gif
176
- - png
177
- - svg
178
- - webp
179
-
180
- # === Link Target Options
181
- #
182
- # Values for the link target selectbox inside the page link overlay.
183
- # The value gets attached as a data-link-target attribute to the link.
184
- #
185
- # == Example:
186
- #
187
- # Open all links set to overlay inside an jQuery UI Dialog Window.
188
- #
189
- # jQuery(a[data-link-target="overlay"]).dialog();
190
- #
191
- link_target_options: [blank]
192
-
193
- # === Format matchers
194
- #
195
- # Named aliases for regular expressions that can be used in various places.
196
- # The most common use case is the format validation of ingredients, or attribute validations of your individual models.
197
- #
198
- # == Example:
199
- #
200
- # validates_format_of :url, with: Alchemy::Config.get('format_matchers')['url']
201
- #
202
- format_matchers:
203
- email: !ruby/regexp /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
204
- url: !ruby/regexp /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
205
- link_url: !ruby/regexp /^(tel:|mailto:|\/|[a-z]+:\/\/)/
206
-
207
- # The layout used for rendering the +alchemy/admin/pages#show+ action.
208
- admin_page_preview_layout: application
209
-
210
- # The sizes for the preview size select in the page editor.
211
- page_preview_sizes:
212
- - 360
213
- - 640
214
- - 768
215
- - 1024
216
- - 1280
217
- - 1440
@@ -1,82 +0,0 @@
1
- # == Alchemy core modules configuration
2
-
3
- - name: dashboard
4
- engine_name: alchemy
5
- position: 1
6
- navigation:
7
- name: Home
8
- controller: "/alchemy/admin/dashboard"
9
- action: index
10
- icon: home-2
11
-
12
- - name: pages
13
- engine_name: alchemy
14
- position: 2
15
- navigation:
16
- name: "modules.pages"
17
- controller: "/alchemy/admin/pages"
18
- action: index
19
- icon: pages
20
- sub_navigation:
21
- - name: "modules.pages"
22
- controller: "/alchemy/admin/pages"
23
- action: index
24
- - name: "modules.layoutpages"
25
- controller: "/alchemy/admin/layoutpages"
26
- action: index
27
- nested:
28
- - controller: "/alchemy/admin/pages"
29
- action: edit
30
-
31
- - name: menus
32
- engine_name: alchemy
33
- position: 3
34
- navigation:
35
- name: "modules.menus"
36
- controller: "/alchemy/admin/nodes"
37
- action: index
38
- icon: menu-2
39
-
40
- - name: languages
41
- engine_name: alchemy
42
- position: 4
43
- navigation:
44
- name: "modules.languages"
45
- controller: "/alchemy/admin/languages"
46
- action: index
47
- icon: translate-2
48
- icon-style: none
49
-
50
- - name: sites
51
- engine_name: alchemy
52
- position: 5
53
- navigation:
54
- name: "modules.sites"
55
- controller: "/alchemy/admin/sites"
56
- action: index
57
- icon: global
58
-
59
- - name: tags
60
- engine_name: alchemy
61
- position: 6
62
- navigation:
63
- name: "modules.tags"
64
- controller: "/alchemy/admin/tags"
65
- action: index
66
- icon: price-tag-3
67
-
68
- - name: archive
69
- engine_name: alchemy
70
- position: 7
71
- navigation:
72
- controller: "/alchemy/admin/pictures"
73
- action: index
74
- name: "modules.library"
75
- icon: archive-drawer
76
- sub_navigation:
77
- - name: "modules.pictures"
78
- controller: "/alchemy/admin/pictures"
79
- action: index
80
- - name: "modules.attachments"
81
- controller: "/alchemy/admin/attachments"
82
- action: index
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- if defined?(RailsLiveReload)
4
- RailsLiveReload.configure do |config|
5
- # Default watched folders & files
6
- config.watch %r{app/views/.+\.(erb)$}
7
- config.watch %r{(app|vendor)/(assets|javascript)/\w+/(.+\.(s?css|coffee|js|html|png|jpg)).*}, reload: :always
8
-
9
- # More examples:
10
- config.watch %r{app/(helpers|components|decorators)/.+\.rb}, reload: :always
11
- config.watch %r{config/locales/.+\.yml}, reload: :always
12
- end
13
- end
@@ -1,5 +0,0 @@
1
- module Alchemy
2
- class LiveReloadWatcher < RailsLiveReload::Watcher
3
- def root = Alchemy::Engine.root
4
- end
5
- end