alchemy_cms 4.4.4 → 5.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (386) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +56 -18
  3. data/.github/workflows/stale.yml +1 -1
  4. data/.gitignore +20 -2
  5. data/.hound.yml +2 -1
  6. data/.prettierrc +6 -0
  7. data/.rubocop.yml +33 -20
  8. data/CHANGELOG.md +121 -0
  9. data/Gemfile +24 -22
  10. data/README.md +31 -19
  11. data/Rakefile +10 -8
  12. data/alchemy_cms.gemspec +7 -5
  13. data/app/assets/javascripts/alchemy/admin.js +1 -2
  14. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +2 -1
  15. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +0 -2
  16. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +5 -5
  17. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +17 -17
  18. data/app/assets/javascripts/alchemy/node_select.js +39 -0
  19. data/app/assets/javascripts/alchemy/templates/index.js +2 -0
  20. data/app/assets/javascripts/alchemy/templates/node.hbs +16 -0
  21. data/app/assets/javascripts/alchemy/templates/node_folder.hbs +3 -0
  22. data/app/assets/javascripts/alchemy/templates/page.hbs +1 -1
  23. data/app/assets/stylesheets/alchemy/_mixins.scss +2 -3
  24. data/app/assets/stylesheets/alchemy/_variables.scss +2 -2
  25. data/app/assets/stylesheets/alchemy/admin.scss +3 -2
  26. data/app/assets/stylesheets/alchemy/base.scss +0 -1
  27. data/app/assets/stylesheets/alchemy/elements.scss +1 -1
  28. data/app/assets/stylesheets/alchemy/forms.scss +5 -0
  29. data/app/assets/stylesheets/alchemy/lists.scss +0 -8
  30. data/app/assets/stylesheets/alchemy/node-select.scss +43 -0
  31. data/app/assets/stylesheets/alchemy/nodes.scss +6 -1
  32. data/app/assets/stylesheets/alchemy/sitemap.scss +63 -21
  33. data/app/assets/stylesheets/alchemy/tables.scss +1 -24
  34. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -7
  35. data/app/controllers/alchemy/admin/base_controller.rb +13 -33
  36. data/app/controllers/alchemy/admin/clipboard_controller.rb +5 -4
  37. data/app/controllers/alchemy/admin/contents_controller.rb +1 -2
  38. data/app/controllers/alchemy/admin/dashboard_controller.rb +10 -9
  39. data/app/controllers/alchemy/admin/elements_controller.rb +20 -20
  40. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +12 -14
  41. data/app/controllers/alchemy/admin/languages_controller.rb +35 -2
  42. data/app/controllers/alchemy/admin/layoutpages_controller.rb +5 -2
  43. data/app/controllers/alchemy/admin/nodes_controller.rb +5 -14
  44. data/app/controllers/alchemy/admin/pages_controller.rb +50 -63
  45. data/app/controllers/alchemy/admin/pictures_controller.rb +16 -16
  46. data/app/controllers/alchemy/admin/resources_controller.rb +21 -13
  47. data/app/controllers/alchemy/admin/sites_controller.rb +18 -0
  48. data/app/controllers/alchemy/admin/styleguide_controller.rb +1 -0
  49. data/app/controllers/alchemy/admin/tags_controller.rb +5 -3
  50. data/app/controllers/alchemy/admin/trash_controller.rb +6 -6
  51. data/app/controllers/alchemy/api/base_controller.rb +2 -2
  52. data/app/controllers/alchemy/api/contents_controller.rb +4 -4
  53. data/app/controllers/alchemy/api/elements_controller.rb +8 -8
  54. data/app/controllers/alchemy/api/nodes_controller.rb +65 -0
  55. data/app/controllers/alchemy/api/pages_controller.rb +15 -22
  56. data/app/controllers/alchemy/attachments_controller.rb +5 -5
  57. data/app/controllers/alchemy/base_controller.rb +10 -9
  58. data/app/controllers/alchemy/messages_controller.rb +16 -23
  59. data/app/controllers/alchemy/pages_controller.rb +13 -11
  60. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +3 -2
  61. data/app/controllers/concerns/alchemy/admin/current_language.rb +23 -0
  62. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +5 -5
  63. data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +4 -4
  64. data/app/controllers/concerns/alchemy/page_redirects.rb +2 -9
  65. data/app/controllers/concerns/alchemy/site_redirects.rb +2 -2
  66. data/app/decorators/alchemy/content_editor.rb +55 -0
  67. data/app/decorators/alchemy/element_editor.rb +39 -0
  68. data/app/helpers/alchemy/admin/attachments_helper.rb +6 -6
  69. data/app/helpers/alchemy/admin/base_helper.rb +36 -35
  70. data/app/helpers/alchemy/admin/contents_helper.rb +3 -3
  71. data/app/helpers/alchemy/admin/elements_helper.rb +3 -88
  72. data/app/helpers/alchemy/admin/essences_helper.rb +8 -117
  73. data/app/helpers/alchemy/admin/form_helper.rb +1 -1
  74. data/app/helpers/alchemy/admin/navigation_helper.rb +24 -23
  75. data/app/helpers/alchemy/admin/pages_helper.rb +12 -12
  76. data/app/helpers/alchemy/admin/pictures_helper.rb +4 -6
  77. data/app/helpers/alchemy/admin/tags_helper.rb +8 -7
  78. data/app/helpers/alchemy/base_helper.rb +13 -8
  79. data/app/helpers/alchemy/elements_block_helper.rb +2 -31
  80. data/app/helpers/alchemy/elements_helper.rb +12 -58
  81. data/app/helpers/alchemy/pages_helper.rb +24 -174
  82. data/app/helpers/alchemy/url_helper.rb +2 -1
  83. data/app/mailers/alchemy/base_mailer.rb +1 -1
  84. data/app/mailers/alchemy/messages_mailer.rb +1 -1
  85. data/app/models/alchemy/attachment.rb +20 -18
  86. data/app/models/alchemy/base_record.rb +2 -5
  87. data/app/models/alchemy/content.rb +33 -52
  88. data/app/models/alchemy/content/factory.rb +24 -31
  89. data/app/models/alchemy/element.rb +45 -53
  90. data/app/models/alchemy/element/definitions.rb +4 -4
  91. data/app/models/alchemy/element/element_contents.rb +9 -6
  92. data/app/models/alchemy/element/element_essences.rb +4 -3
  93. data/app/models/alchemy/element/presenters.rb +3 -2
  94. data/app/models/alchemy/element_to_page.rb +1 -1
  95. data/app/models/alchemy/essence_boolean.rb +1 -3
  96. data/app/models/alchemy/essence_date.rb +2 -3
  97. data/app/models/alchemy/essence_file.rb +4 -4
  98. data/app/models/alchemy/essence_html.rb +1 -3
  99. data/app/models/alchemy/essence_link.rb +1 -3
  100. data/app/models/alchemy/essence_node.rb +18 -0
  101. data/app/models/alchemy/essence_page.rb +3 -16
  102. data/app/models/alchemy/essence_picture.rb +17 -16
  103. data/app/models/alchemy/essence_picture_view.rb +7 -6
  104. data/app/models/alchemy/essence_richtext.rb +1 -3
  105. data/app/models/alchemy/essence_select.rb +1 -3
  106. data/app/models/alchemy/essence_text.rb +0 -2
  107. data/app/models/alchemy/folded_page.rb +1 -0
  108. data/app/models/alchemy/language.rb +21 -35
  109. data/app/models/alchemy/language/code.rb +4 -4
  110. data/app/models/alchemy/legacy_page_url.rb +1 -1
  111. data/app/models/alchemy/message.rb +3 -3
  112. data/app/models/alchemy/node.rb +55 -9
  113. data/app/models/alchemy/page.rb +53 -123
  114. data/app/models/alchemy/page/fixed_attributes.rb +3 -2
  115. data/app/models/alchemy/page/page_elements.rb +35 -44
  116. data/app/models/alchemy/page/page_naming.rb +20 -70
  117. data/app/models/alchemy/page/page_natures.rb +7 -34
  118. data/app/models/alchemy/page/page_scopes.rb +23 -29
  119. data/app/models/alchemy/page/url_path.rb +64 -0
  120. data/app/models/alchemy/picture.rb +40 -30
  121. data/app/models/alchemy/picture/preprocessor.rb +26 -0
  122. data/app/models/alchemy/picture/transformations.rb +9 -7
  123. data/app/models/alchemy/picture/url.rb +5 -5
  124. data/app/models/alchemy/site.rb +6 -36
  125. data/app/models/alchemy/site/layout.rb +2 -2
  126. data/app/models/concerns/alchemy/touch_elements.rb +24 -0
  127. data/app/serializers/alchemy/content_serializer.rb +0 -3
  128. data/app/serializers/alchemy/essence_boolean_serializer.rb +3 -3
  129. data/app/serializers/alchemy/essence_date_serializer.rb +3 -3
  130. data/app/serializers/alchemy/essence_file_serializer.rb +4 -2
  131. data/app/serializers/alchemy/essence_html_serializer.rb +3 -3
  132. data/app/serializers/alchemy/essence_link_serializer.rb +3 -3
  133. data/app/serializers/alchemy/essence_picture_serializer.rb +5 -4
  134. data/app/serializers/alchemy/essence_richtext_serializer.rb +3 -3
  135. data/app/serializers/alchemy/essence_select_serializer.rb +3 -3
  136. data/app/serializers/alchemy/essence_text_serializer.rb +5 -4
  137. data/app/serializers/alchemy/node_serializer.rb +14 -0
  138. data/app/serializers/alchemy/page_serializer.rb +2 -1
  139. data/app/serializers/alchemy/page_tree_serializer.rb +11 -14
  140. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -2
  141. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +1 -2
  142. data/app/views/alchemy/admin/attachments/_files_list.html.erb +4 -4
  143. data/app/views/alchemy/admin/contents/create.js.erb +1 -3
  144. data/app/views/alchemy/admin/elements/_element.html.erb +9 -18
  145. data/app/views/alchemy/admin/elements/create.js.erb +1 -1
  146. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  147. data/app/views/alchemy/admin/elements/index.html.erb +3 -3
  148. data/app/views/alchemy/admin/essence_files/assign.js.erb +1 -6
  149. data/app/views/alchemy/admin/essence_files/edit.html.erb +1 -1
  150. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +1 -7
  151. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
  152. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +7 -7
  153. data/app/views/alchemy/admin/essence_pictures/update.js.erb +1 -1
  154. data/app/views/alchemy/admin/languages/_form.html.erb +5 -5
  155. data/app/views/alchemy/admin/languages/_table.html.erb +3 -3
  156. data/app/views/alchemy/admin/languages/edit.html.erb +1 -0
  157. data/app/views/alchemy/admin/languages/index.html.erb +23 -4
  158. data/app/views/alchemy/admin/languages/new.html.erb +1 -0
  159. data/app/views/alchemy/admin/layoutpages/index.html.erb +6 -2
  160. data/app/views/alchemy/admin/nodes/_form.html.erb +23 -15
  161. data/app/views/alchemy/admin/nodes/_node.html.erb +5 -19
  162. data/app/views/alchemy/admin/nodes/index.html.erb +3 -18
  163. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +0 -8
  164. data/app/views/alchemy/admin/pages/_form.html.erb +1 -2
  165. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -0
  166. data/app/views/alchemy/admin/pages/_page.html.erb +14 -25
  167. data/app/views/alchemy/admin/pages/_page_infos.html.erb +0 -4
  168. data/app/views/alchemy/admin/pages/_sitemap.html.erb +6 -0
  169. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  170. data/app/views/alchemy/admin/pages/info.html.erb +0 -9
  171. data/app/views/alchemy/admin/pages/unlock.js.erb +13 -6
  172. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +0 -2
  173. data/app/views/alchemy/admin/partials/_routes.html.erb +8 -0
  174. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -5
  175. data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +1 -1
  176. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -2
  177. data/app/views/alchemy/admin/pictures/index.html.erb +18 -3
  178. data/app/views/alchemy/admin/resources/_resource.html.erb +1 -1
  179. data/app/views/alchemy/admin/resources/_table.html.erb +2 -2
  180. data/app/views/alchemy/admin/sites/_form.html.erb +8 -0
  181. data/app/views/alchemy/admin/sites/edit.html.erb +1 -0
  182. data/app/views/alchemy/admin/sites/index.html.erb +21 -9
  183. data/app/views/alchemy/admin/sites/new.html.erb +1 -0
  184. data/app/views/alchemy/admin/tags/index.html.erb +2 -2
  185. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +10 -12
  186. data/app/views/alchemy/essences/_essence_date_editor.html.erb +11 -8
  187. data/app/views/alchemy/essences/_essence_file_editor.html.erb +16 -17
  188. data/app/views/alchemy/essences/_essence_html_editor.html.erb +8 -5
  189. data/app/views/alchemy/essences/_essence_link_editor.html.erb +18 -15
  190. data/app/views/alchemy/essences/_essence_node_editor.html.erb +27 -0
  191. data/app/views/alchemy/essences/_essence_node_view.html.erb +1 -0
  192. data/app/views/alchemy/essences/_essence_page_editor.html.erb +14 -11
  193. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +22 -20
  194. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +10 -7
  195. data/app/views/alchemy/essences/_essence_select_editor.html.erb +12 -16
  196. data/app/views/alchemy/essences/_essence_text_editor.html.erb +18 -17
  197. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +6 -11
  198. data/app/views/alchemy/pages/show.rss.builder +3 -2
  199. data/app/views/layouts/alchemy/admin.html.erb +1 -0
  200. data/babel.config.js +12 -0
  201. data/bin/rails +5 -4
  202. data/config/alchemy/config.yml +23 -22
  203. data/config/brakeman.ignore +1 -1
  204. data/config/initializers/assets.rb +2 -1
  205. data/config/initializers/dragonfly.rb +2 -1
  206. data/config/initializers/mime_types.rb +1 -0
  207. data/config/initializers/mini_profiler.rb +3 -2
  208. data/config/initializers/simple_form.rb +6 -6
  209. data/config/locales/alchemy.en.yml +37 -14
  210. data/config/routes.rb +32 -28
  211. data/config/spring.rb +3 -2
  212. data/db/migrate/20200226213334_alchemy_four_point_four.rb +313 -0
  213. data/db/migrate/20200423073425_create_alchemy_essence_nodes.rb +11 -0
  214. data/db/migrate/20200504210159_remove_site_id_from_nodes.rb +28 -0
  215. data/db/migrate/20200505215518_add_language_id_foreign_key_to_alchemy_pages.rb +8 -0
  216. data/db/migrate/20200511113603_add_menu_type_to_alchemy_nodes.rb +27 -0
  217. data/db/migrate/20200514091507_make_page_layoutpage_null_false.rb +6 -0
  218. data/db/migrate/20200519073500_remove_visible_from_alchemy_pages.rb +24 -0
  219. data/lib/alchemy/admin/locale.rb +3 -1
  220. data/lib/alchemy/admin/preview_url.rb +85 -0
  221. data/lib/alchemy/auth_accessors.rb +8 -7
  222. data/lib/alchemy/cache_digests/template_tracker.rb +5 -4
  223. data/lib/alchemy/config.rb +26 -2
  224. data/lib/alchemy/configuration_methods.rb +3 -1
  225. data/lib/alchemy/controller_actions.rb +6 -5
  226. data/lib/alchemy/deprecation.rb +2 -1
  227. data/lib/alchemy/elements_finder.rb +5 -5
  228. data/lib/alchemy/engine.rb +23 -8
  229. data/lib/alchemy/errors.rb +0 -7
  230. data/lib/alchemy/essence.rb +17 -16
  231. data/lib/alchemy/filetypes.rb +5 -5
  232. data/lib/alchemy/forms/builder.rb +4 -4
  233. data/lib/alchemy/hints.rb +1 -1
  234. data/lib/alchemy/i18n.rb +2 -1
  235. data/lib/alchemy/modules.rb +12 -12
  236. data/lib/alchemy/name_conversions.rb +5 -5
  237. data/lib/alchemy/on_page_layout/callbacks_runner.rb +1 -0
  238. data/lib/alchemy/page_layout.rb +15 -12
  239. data/lib/alchemy/paths.rb +1 -1
  240. data/lib/alchemy/permissions.rb +7 -6
  241. data/lib/alchemy/resource.rb +23 -13
  242. data/lib/alchemy/resources_helper.rb +12 -18
  243. data/lib/alchemy/routing_constraints.rb +1 -1
  244. data/lib/alchemy/seeder.rb +42 -14
  245. data/lib/alchemy/shell.rb +13 -10
  246. data/lib/alchemy/taggable.rb +1 -0
  247. data/lib/alchemy/tasks/tidy.rb +4 -3
  248. data/lib/alchemy/test_support/config_stubbing.rb +1 -0
  249. data/lib/alchemy/test_support/essence_shared_examples.rb +72 -72
  250. data/lib/alchemy/test_support/factories.rb +1 -1
  251. data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -5
  252. data/lib/alchemy/test_support/factories/content_factory.rb +6 -6
  253. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +7 -7
  254. data/lib/alchemy/test_support/factories/element_factory.rb +9 -9
  255. data/lib/alchemy/test_support/factories/essence_file_factory.rb +3 -3
  256. data/lib/alchemy/test_support/factories/essence_page_factory.rb +3 -3
  257. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +4 -4
  258. data/lib/alchemy/test_support/factories/essence_text_factory.rb +3 -3
  259. data/lib/alchemy/test_support/factories/language_factory.rb +21 -14
  260. data/lib/alchemy/test_support/factories/node_factory.rb +8 -8
  261. data/lib/alchemy/test_support/factories/page_factory.rb +15 -27
  262. data/lib/alchemy/test_support/factories/picture_factory.rb +5 -5
  263. data/lib/alchemy/test_support/factories/site_factory.rb +7 -6
  264. data/lib/alchemy/test_support/integration_helpers.rb +1 -0
  265. data/lib/alchemy/test_support/shared_contexts.rb +5 -4
  266. data/lib/alchemy/test_support/shared_uploader_examples.rb +4 -3
  267. data/lib/alchemy/tinymce.rb +15 -13
  268. data/lib/alchemy/upgrader.rb +8 -7
  269. data/lib/alchemy/upgrader/five_point_zero.rb +41 -0
  270. data/lib/alchemy/upgrader/tasks/element_views_updater.rb +4 -4
  271. data/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb +29 -0
  272. data/lib/alchemy/version.rb +1 -1
  273. data/lib/alchemy_cms.rb +52 -50
  274. data/lib/{rails/generators → generators}/alchemy/base.rb +5 -4
  275. data/lib/{rails/generators → generators}/alchemy/elements/elements_generator.rb +13 -9
  276. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.erb +0 -0
  277. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.haml +0 -0
  278. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.slim +0 -0
  279. data/lib/{rails/generators → generators}/alchemy/essence/essence_generator.rb +15 -13
  280. data/lib/generators/alchemy/essence/templates/editor.html.erb +17 -0
  281. data/lib/{rails/generators → generators}/alchemy/essence/templates/view.html.erb +0 -0
  282. data/lib/{rails/generators → generators}/alchemy/install/files/_article.html.erb +0 -0
  283. data/lib/{rails/generators → generators}/alchemy/install/files/_standard.html.erb +0 -0
  284. data/lib/{rails/generators → generators}/alchemy/install/files/alchemy.en.yml +0 -0
  285. data/lib/generators/alchemy/install/files/alchemy_admin.js +1 -0
  286. data/lib/{rails/generators → generators}/alchemy/install/files/all.css +0 -0
  287. data/lib/{rails/generators → generators}/alchemy/install/files/all.js +0 -0
  288. data/lib/{rails/generators → generators}/alchemy/install/files/application.html.erb +0 -0
  289. data/lib/{rails/generators → generators}/alchemy/install/files/article.scss +0 -0
  290. data/lib/generators/alchemy/install/install_generator.rb +110 -0
  291. data/lib/{rails/generators → generators}/alchemy/install/templates/dragonfly.rb.tt +0 -0
  292. data/lib/{rails/generators → generators}/alchemy/install/templates/elements.yml.tt +0 -0
  293. data/lib/generators/alchemy/install/templates/menus.yml.tt +8 -0
  294. data/lib/{rails/generators → generators}/alchemy/install/templates/page_layouts.yml.tt +0 -0
  295. data/lib/{rails/generators → generators}/alchemy/menus/menus_generator.rb +5 -5
  296. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.erb +1 -4
  297. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.haml +1 -4
  298. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.slim +1 -4
  299. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.erb +1 -1
  300. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.haml +2 -2
  301. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.slim +2 -2
  302. data/lib/{rails/generators → generators}/alchemy/module/module_generator.rb +3 -2
  303. data/lib/{rails/generators → generators}/alchemy/module/templates/ability.rb.tt +0 -0
  304. data/lib/{rails/generators → generators}/alchemy/module/templates/controller.rb.tt +0 -0
  305. data/lib/{rails/generators → generators}/alchemy/module/templates/module_config.rb.tt +0 -0
  306. data/lib/{rails/generators → generators}/alchemy/page_layouts/page_layouts_generator.rb +5 -4
  307. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.erb +0 -0
  308. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.haml +0 -0
  309. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.slim +0 -0
  310. data/lib/{rails/generators → generators}/alchemy/site_layouts/site_layouts_generator.rb +4 -2
  311. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.erb +0 -0
  312. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.haml +0 -0
  313. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.slim +0 -0
  314. data/lib/{rails/generators → generators}/alchemy/views/views_generator.rb +7 -6
  315. data/lib/kaminari/scoped_pagination_url_helper.rb +1 -0
  316. data/lib/tasks/alchemy/db.rake +3 -19
  317. data/lib/tasks/alchemy/install.rake +3 -2
  318. data/lib/tasks/alchemy/tidy.rake +9 -8
  319. data/lib/tasks/alchemy/upgrade.rake +28 -105
  320. data/package.json +45 -0
  321. data/package/admin.js +14 -0
  322. data/package/src/__tests__/i18n.spec.js +70 -0
  323. data/package/src/i18n.js +48 -0
  324. data/package/src/node_tree.js +72 -0
  325. data/package/src/translations.js +32 -0
  326. data/package/src/utils/__tests__/ajax.spec.js +124 -0
  327. data/package/src/utils/__tests__/events.spec.js +38 -0
  328. data/package/src/utils/ajax.js +48 -0
  329. data/package/src/utils/events.js +16 -0
  330. data/vendor/assets/fonts/fa-regular-400.eot +0 -0
  331. data/vendor/assets/fonts/fa-regular-400.svg +798 -358
  332. data/vendor/assets/fonts/fa-regular-400.ttf +0 -0
  333. data/vendor/assets/fonts/fa-regular-400.woff +0 -0
  334. data/vendor/assets/fonts/fa-regular-400.woff2 +0 -0
  335. data/vendor/assets/fonts/fa-solid-900.eot +0 -0
  336. data/vendor/assets/fonts/fa-solid-900.svg +4933 -1408
  337. data/vendor/assets/fonts/fa-solid-900.ttf +0 -0
  338. data/vendor/assets/fonts/fa-solid-900.woff +0 -0
  339. data/vendor/assets/fonts/fa-solid-900.woff2 +0 -0
  340. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +1 -2
  341. data/vendor/assets/stylesheets/fontawesome/_core.scss +5 -0
  342. data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +1 -1
  343. data/vendor/assets/stylesheets/fontawesome/_icons.scss +651 -2
  344. data/vendor/assets/stylesheets/fontawesome/_mixins.scss +0 -1
  345. data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +3 -2
  346. data/vendor/assets/stylesheets/fontawesome/_stacked.scss +1 -1
  347. data/vendor/assets/stylesheets/fontawesome/_variables.scss +662 -9
  348. data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +2 -2
  349. data/vendor/assets/stylesheets/fontawesome/regular.scss +23 -0
  350. data/vendor/assets/stylesheets/fontawesome/solid.scss +24 -0
  351. metadata +131 -83
  352. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +0 -32
  353. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +0 -29
  354. data/app/helpers/alchemy/essences_helper.rb +0 -119
  355. data/app/models/concerns/alchemy/content_touching.rb +0 -23
  356. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -15
  357. data/app/views/alchemy/admin/contents/_missing.html.erb +0 -17
  358. data/app/views/alchemy/admin/pages/_menu_fields.html.erb +0 -33
  359. data/app/views/alchemy/admin/pages/configure_external.html.erb +0 -32
  360. data/app/views/alchemy/elements/_editor_not_found.html.erb +0 -4
  361. data/app/views/alchemy/navigation/_image_link.html.erb +0 -14
  362. data/app/views/alchemy/navigation/_link.html.erb +0 -19
  363. data/app/views/alchemy/navigation/_renderer.html.erb +0 -29
  364. data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -363
  365. data/db/migrate/20180227224537_migrate_tags_to_gutentag.rb +0 -41
  366. data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +0 -6
  367. data/db/migrate/20191016073858_create_alchemy_essence_pages.rb +0 -8
  368. data/db/migrate/20191029212236_create_alchemy_nodes.rb +0 -24
  369. data/db/migrate/20200226081535_add_site_id_to_alchemy_nodes.rb +0 -15
  370. data/lib/alchemy/ssl_protection.rb +0 -32
  371. data/lib/alchemy/tasks/helpers.rb +0 -81
  372. data/lib/alchemy/test_support/controller_requests.rb +0 -93
  373. data/lib/alchemy/upgrader/four_point_four.rb +0 -52
  374. data/lib/alchemy/upgrader/four_point_one.rb +0 -42
  375. data/lib/alchemy/upgrader/four_point_two.rb +0 -85
  376. data/lib/alchemy/upgrader/tasks/cells_migration.rb +0 -43
  377. data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +0 -148
  378. data/lib/alchemy/upgrader/tasks/element_partial_name_variable_updater.rb +0 -28
  379. data/lib/alchemy/upgrader/tasks/harden_acts_as_taggable_on_migrations.rb +0 -27
  380. data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +0 -65
  381. data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +0 -210
  382. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +0 -15
  383. data/lib/rails/generators/alchemy/install/install_generator.rb +0 -60
  384. data/lib/tasks/alchemy/convert.rake +0 -95
  385. data/vendor/assets/stylesheets/fontawesome/fa-regular.scss +0 -22
  386. data/vendor/assets/stylesheets/fontawesome/fa-solid.scss +0 -23
@@ -15,7 +15,6 @@ module Alchemy
15
15
  # fixed_attributes:
16
16
  # - public_on: nil
17
17
  # - public_until: nil
18
- # - visible: false
19
18
  #
20
19
  class Page::FixedAttributes
21
20
  attr_reader :page
@@ -31,7 +30,7 @@ module Alchemy
31
30
  # @return Hash
32
31
  #
33
32
  def attributes
34
- @_attributes ||= page.definition.fetch('fixed_attributes', {}).symbolize_keys
33
+ @_attributes ||= page.definition.fetch("fixed_attributes", {}).symbolize_keys
35
34
  end
36
35
  alias_method :all, :attributes
37
36
 
@@ -52,6 +51,7 @@ module Alchemy
52
51
  #
53
52
  def fixed?(name)
54
53
  return false if name.nil?
54
+
55
55
  attributes.key?(name.to_sym)
56
56
  end
57
57
 
@@ -59,6 +59,7 @@ module Alchemy
59
59
  #
60
60
  def [](name)
61
61
  return nil if name.nil?
62
+
62
63
  attributes[name.to_sym]
63
64
  end
64
65
  end
@@ -9,37 +9,37 @@ module Alchemy
9
9
 
10
10
  has_many :all_elements,
11
11
  -> { order(:position) },
12
- class_name: 'Alchemy::Element',
12
+ class_name: "Alchemy::Element",
13
13
  inverse_of: :page
14
14
  has_many :elements,
15
15
  -> { order(:position).not_nested.unfixed.available },
16
- class_name: 'Alchemy::Element',
16
+ class_name: "Alchemy::Element",
17
17
  inverse_of: :page
18
18
  has_many :trashed_elements,
19
19
  -> { Element.trashed.order(:position) },
20
- class_name: 'Alchemy::Element',
20
+ class_name: "Alchemy::Element",
21
21
  inverse_of: :page
22
22
  has_many :fixed_elements,
23
23
  -> { order(:position).fixed.available },
24
- class_name: 'Alchemy::Element',
24
+ class_name: "Alchemy::Element",
25
25
  inverse_of: :page
26
26
  has_many :dependent_destroyable_elements,
27
27
  -> { not_nested },
28
- class_name: 'Alchemy::Element',
28
+ class_name: "Alchemy::Element",
29
29
  dependent: :destroy
30
30
  has_many :contents, through: :elements
31
31
  has_and_belongs_to_many :to_be_swept_elements, -> { distinct },
32
- class_name: 'Alchemy::Element',
32
+ class_name: "Alchemy::Element",
33
33
  join_table: ElementToPage.table_name
34
34
 
35
35
  after_create :generate_elements,
36
- unless: -> { systempage? || autogenerate_elements == false }
36
+ unless: -> { autogenerate_elements == false }
37
37
 
38
38
  after_update :trash_not_allowed_elements!,
39
- if: :has_page_layout_changed?
39
+ if: :saved_change_to_page_layout?
40
40
 
41
41
  after_update :generate_elements,
42
- if: :has_page_layout_changed?
42
+ if: :saved_change_to_page_layout?
43
43
  end
44
44
 
45
45
  module ClassMethods
@@ -53,7 +53,7 @@ module Alchemy
53
53
  source_elements = source.all_elements.not_nested.not_trashed
54
54
  source_elements.order(:position).map do |source_element|
55
55
  Element.copy(source_element, {
56
- page_id: target.id
56
+ page_id: target.id,
57
57
  }).tap(&:move_to_bottom)
58
58
  end
59
59
  end
@@ -81,11 +81,11 @@ module Alchemy
81
81
  #
82
82
  def available_element_definitions(only_element_named = nil)
83
83
  @_element_definitions ||= if only_element_named
84
- definition = Element.definition_by_name(only_element_named)
85
- element_definitions_by_name(definition['nestable_elements'])
86
- else
87
- element_definitions
88
- end
84
+ definition = Element.definition_by_name(only_element_named)
85
+ element_definitions_by_name(definition["nestable_elements"])
86
+ else
87
+ element_definitions
88
+ end
89
89
 
90
90
  return [] if @_element_definitions.blank?
91
91
 
@@ -100,20 +100,20 @@ module Alchemy
100
100
  # All names of elements that can actually be placed on current page.
101
101
  #
102
102
  def available_element_names
103
- @_available_element_names ||= available_element_definitions.map { |e| e['name'] }
103
+ @_available_element_names ||= available_element_definitions.map { |e| e["name"] }
104
104
  end
105
105
 
106
106
  # Available element definitions excluding nested unique elements.
107
107
  #
108
108
  def available_elements_within_current_scope(parent)
109
109
  @_available_elements = if parent
110
- parents_unique_nested_elements = parent.nested_elements.where(unique: true).pluck(:name)
111
- available_element_definitions(parent.name).reject do |e|
112
- parents_unique_nested_elements.include? e['name']
110
+ parents_unique_nested_elements = parent.nested_elements.where(unique: true).pluck(:name)
111
+ available_element_definitions(parent.name).reject do |e|
112
+ parents_unique_nested_elements.include? e["name"]
113
+ end
114
+ else
115
+ available_element_definitions
113
116
  end
114
- else
115
- available_element_definitions
116
- end
117
117
  end
118
118
 
119
119
  # All element definitions defined for page's page layout
@@ -129,10 +129,10 @@ module Alchemy
129
129
  #
130
130
  def descendent_element_definitions
131
131
  definitions = element_definitions_by_name(element_definition_names)
132
- definitions.select { |d| d.key?('nestable_elements') }.each do |d|
133
- definitions += element_definitions_by_name(d['nestable_elements'])
132
+ definitions.select { |d| d.key?("nestable_elements") }.each do |d|
133
+ definitions += element_definitions_by_name(d["nestable_elements"])
134
134
  end
135
- definitions.uniq { |d| d['name'] }
135
+ definitions.uniq { |d| d["name"] }
136
136
  end
137
137
 
138
138
  # All names of elements that are defined in the page definition.
@@ -145,10 +145,8 @@ module Alchemy
145
145
  # elements: [headline, contactform]
146
146
  #
147
147
  def element_definition_names
148
- definition['elements'] || []
148
+ definition["elements"] || []
149
149
  end
150
- alias_method :element_names_from_definition, :element_definition_names
151
- deprecate element_names_from_definition: :element_definition_names, deprecator: Alchemy::Deprecation
152
150
 
153
151
  # Element definitions with given name(s)
154
152
  #
@@ -163,7 +161,7 @@ module Alchemy
163
161
  if names.to_s == "all"
164
162
  Element.definitions
165
163
  else
166
- Element.definitions.select { |e| names.include? e['name'] }
164
+ Element.definitions.select { |e| names.include? e["name"] }
167
165
  end
168
166
  end
169
167
 
@@ -176,14 +174,14 @@ module Alchemy
176
174
  # feed_elements: [element_name, element_2_name]
177
175
  #
178
176
  def feed_elements
179
- elements.named(definition['feed_elements'])
177
+ elements.named(definition["feed_elements"])
180
178
  end
181
179
 
182
180
  # Returns an array of all EssenceRichtext contents ids from not folded elements
183
181
  #
184
182
  def richtext_contents_ids
185
183
  Alchemy::Content.joins(:element)
186
- .where(Element.table_name => {page_id: id, folded: false})
184
+ .where(Element.table_name => { page_id: id, folded: false })
187
185
  .select(&:has_tinymce?)
188
186
  .collect(&:id)
189
187
  end
@@ -197,8 +195,9 @@ module Alchemy
197
195
  def generate_elements
198
196
  existing_elements = all_elements.not_nested.not_trashed
199
197
  existing_element_names = existing_elements.pluck(:name).uniq
200
- definition.fetch('autogenerate', []).each do |element_name|
198
+ definition.fetch("autogenerate", []).each do |element_name|
201
199
  next if existing_element_names.include?(element_name)
200
+
202
201
  Element.create(page: self, name: element_name)
203
202
  end
204
203
  end
@@ -207,24 +206,16 @@ module Alchemy
207
206
  def trash_not_allowed_elements!
208
207
  not_allowed_elements = elements.where([
209
208
  "#{Element.table_name}.name NOT IN (?)",
210
- element_definition_names
209
+ element_definition_names,
211
210
  ])
212
211
  not_allowed_elements.to_a.map(&:trash!)
213
212
  end
214
213
 
215
- def has_page_layout_changed?
216
- if active_record_5_1?
217
- saved_change_to_page_layout?
218
- else
219
- page_layout_changed?
220
- end
221
- end
222
-
223
214
  # Deletes unique and already present definitions from @_element_definitions.
224
215
  #
225
216
  def delete_unique_element_definitions!
226
217
  @_element_definitions.delete_if do |element|
227
- element['unique'] && @_existing_element_names.include?(element['name'])
218
+ element["unique"] && @_existing_element_names.include?(element["name"])
228
219
  end
229
220
  end
230
221
 
@@ -232,8 +223,8 @@ module Alchemy
232
223
  #
233
224
  def delete_outnumbered_element_definitions!
234
225
  @_element_definitions.delete_if do |element|
235
- outnumbered = @_existing_element_names.select { |name| name == element['name'] }
236
- element['amount'] && outnumbered.count >= element['amount'].to_i
226
+ outnumbered = @_existing_element_names.select { |name| name == element["name"] }
227
+ element["amount"] && outnumbered.count >= element["amount"].to_i
237
228
  end
238
229
  end
239
230
  end
@@ -9,29 +9,22 @@ module Alchemy
9
9
  included do
10
10
  before_validation :set_urlname,
11
11
  if: :renamed?,
12
- unless: -> { systempage? || definition['redirects_to_external'] || name.blank? }
12
+ unless: -> { name.blank? }
13
13
 
14
14
  validates :name,
15
15
  presence: true
16
16
  validates :urlname,
17
- uniqueness: {scope: [:language_id, :layoutpage], if: -> { urlname.present? }},
18
- exclusion: {in: RESERVED_URLNAMES},
19
- length: {minimum: 3, if: -> { urlname.present? }},
20
- format: {with: /\A[:\.\w\-+_\/\?&%;=]*\z/, if: -> { definition['redirects_to_external'] }}
21
- validates :urlname,
22
- on: :update,
23
- presence: {if: -> { definition['redirects_to_external'] }}
17
+ uniqueness: { scope: [:language_id, :layoutpage], if: -> { urlname.present? } },
18
+ exclusion: { in: RESERVED_URLNAMES },
19
+ length: { minimum: 3, if: -> { urlname.present? } }
24
20
 
25
21
  before_save :set_title,
26
- unless: -> { systempage? || definition['redirects_to_external'] },
27
22
  if: -> { title.blank? }
28
23
 
29
24
  after_update :update_descendants_urlnames,
30
- if: :should_update_descendants_urlnames?
25
+ if: :saved_change_to_urlname?
31
26
 
32
- after_move :update_urlname!,
33
- if: -> { Config.get(:url_nesting) },
34
- unless: -> { definition['redirects_to_external'] }
27
+ after_move :update_urlname!
35
28
  end
36
29
 
37
30
  # Returns true if name or urlname has changed.
@@ -42,7 +35,7 @@ module Alchemy
42
35
  # Makes a slug of all ancestors urlnames including mine and delimit them be slash.
43
36
  # So the whole path is stored as urlname in the database.
44
37
  def update_urlname!
45
- new_urlname = nested_url_name(slug)
38
+ new_urlname = nested_url_name
46
39
  if urlname != new_urlname
47
40
  legacy_urls.create(urlname: urlname)
48
41
  update_column(:urlname, new_urlname)
@@ -51,56 +44,21 @@ module Alchemy
51
44
 
52
45
  # Returns always the last part of a urlname path
53
46
  def slug
54
- urlname.to_s.split('/').last
55
- end
56
-
57
- # Returns an urlname prefixed with http://, if no protocol is given
58
- def external_urlname
59
- return urlname if urlname =~ /\A(\/|[a-z]+:\/\/)/
60
- "http://#{urlname}"
61
- end
62
-
63
- # Returns an array of visible/non-language_root ancestors.
64
- def visible_ancestors
65
- return [] unless parent
66
- if new_record?
67
- parent.visible_ancestors.tap do |base|
68
- base.push(parent) if parent.visible?
69
- end
70
- else
71
- ancestors.visible.contentpages.where(language_root: nil).to_a
72
- end
47
+ urlname.to_s.split("/").last
73
48
  end
74
49
 
75
50
  private
76
51
 
77
- def should_update_descendants_urlnames?
78
- return false if !Config.get(:url_nesting)
79
- if active_record_5_1?
80
- saved_change_to_urlname? || saved_change_to_visible?
81
- else
82
- urlname_changed? || visible_changed?
83
- end
84
- end
85
-
86
52
  def update_descendants_urlnames
87
53
  reload
88
- descendants.each do |descendant|
89
- next if descendant.definition['redirects_to_external']
90
- descendant.update_urlname!
91
- end
54
+ descendants.each(&:update_urlname!)
92
55
  end
93
56
 
94
57
  # Sets the urlname to a url friendly slug.
95
58
  # Either from name, or if present, from urlname.
96
- # If url_nesting is enabled the urlname contains the whole path.
59
+ # The urlname contains the whole path including parent urlnames.
97
60
  def set_urlname
98
- if Config.get(:url_nesting)
99
- value = slug
100
- else
101
- value = urlname
102
- end
103
- self[:urlname] = nested_url_name(value)
61
+ self[:urlname] = nested_url_name
104
62
  end
105
63
 
106
64
  def set_title
@@ -112,25 +70,17 @@ module Alchemy
112
70
  # Names shorter than 3 will be filled up with dashes,
113
71
  # so it does not collidate with the language code.
114
72
  #
115
- def convert_url_name(value)
116
- url_name = convert_to_urlname(value.blank? ? name : value)
117
- if url_name.length < 3
118
- ('-' * (3 - url_name.length)) + url_name
119
- else
120
- url_name
121
- end
122
- end
123
-
124
- def nested_url_name(value)
125
- (ancestor_slugs << convert_url_name(value)).join('/')
73
+ def converted_url_name
74
+ url_name = convert_to_urlname(slug.blank? ? name : slug)
75
+ url_name.rjust(3, "-")
126
76
  end
127
77
 
128
- # Slugs of all visible/non-language_root ancestors.
129
- # Returns [], if there is no parent, the parent is
130
- # the root page itself, or url_nesting is off.
131
- def ancestor_slugs
132
- return [] if !Config.get(:url_nesting) || parent.nil? || parent.root?
133
- visible_ancestors.map(&:slug).compact
78
+ def nested_url_name
79
+ if parent&.language_root?
80
+ converted_url_name
81
+ else
82
+ [parent&.urlname, converted_url_name].compact.join("/")
83
+ end
134
84
  end
135
85
  end
136
86
  end
@@ -14,20 +14,16 @@ module Alchemy
14
14
  end
15
15
 
16
16
  def taggable?
17
- definition['taggable'] == true
17
+ definition["taggable"] == true
18
18
  end
19
19
 
20
20
  def rootpage?
21
21
  !new_record? && parent_id.blank?
22
22
  end
23
23
 
24
- def systempage?
25
- return true if Page.count.zero?
26
- rootpage? || (parent_id == Page.root.id && !language_root?)
27
- end
28
-
29
24
  def folded?(user_id)
30
25
  return unless Alchemy.user_class < ActiveRecord::Base
26
+
31
27
  folded_pages.where(user_id: user_id, folded: true).any?
32
28
  end
33
29
 
@@ -51,46 +47,22 @@ module Alchemy
51
47
 
52
48
  def editor_roles
53
49
  return unless has_limited_editors?
54
- definition["editable_by"]
55
- end
56
-
57
- # Returns true or false if the pages definition for config/alchemy/page_layouts.yml contains redirects_to_external: true
58
- # @deprecated Please use a menu node with an external url instead.
59
- def redirects_to_external?
60
- !!definition["redirects_to_external"]
61
- end
62
- deprecate redirects_to_external?: 'Please use a menu node with an external url instead.', deprecator: Alchemy::Deprecation
63
50
 
64
- # @deprecated
65
- def has_controller?
66
- !PageLayout.get(page_layout).nil? && !PageLayout.get(page_layout)["controller"].blank?
51
+ definition["editable_by"]
67
52
  end
68
- deprecate :has_controller?, deprecator: Alchemy::Deprecation
69
53
 
70
54
  # True if page locked_at timestamp and locked_by id are set
71
55
  def locked?
72
56
  locked_by? && locked_at?
73
57
  end
74
58
 
75
- # @deprecated Please use a menu node with an url pointing to your controller path instead.
76
- def controller_and_action
77
- if definition['controller']
78
- {
79
- controller: definition["controller"].gsub(/(^\b)/, "/#{$1}"),
80
- action: definition["action"]
81
- }
82
- end
83
- end
84
- deprecate controller_and_action: 'Please use a menu node with an url pointing to your controller path instead.', deprecator: Alchemy::Deprecation
85
-
86
59
  # Returns a Hash describing the status of the Page.
87
60
  #
88
61
  def status
89
62
  {
90
63
  public: public?,
91
- visible: visible?,
92
64
  locked: locked?,
93
- restricted: restricted?
65
+ restricted: restricted?,
94
66
  }
95
67
  end
96
68
 
@@ -116,7 +88,7 @@ module Alchemy
116
88
  # Page layout names are defined inside the config/alchemy/page_layouts.yml file.
117
89
  # Translate the name in your config/locales language yml file.
118
90
  def layout_display_name
119
- Alchemy.t(page_layout, scope: 'page_layout_names')
91
+ Alchemy.t(page_layout, scope: "page_layout_names")
120
92
  end
121
93
 
122
94
  # Returns the name for the layout partial
@@ -174,8 +146,9 @@ module Alchemy
174
146
  #
175
147
  def cache_page?
176
148
  return false unless caching_enabled?
149
+
177
150
  page_layout = PageLayout.get(self.page_layout)
178
- page_layout['cache'] != false && page_layout['searchresults'] != true
151
+ page_layout["cache"] != false && page_layout["searchresults"] != true
179
152
  end
180
153
 
181
154
  private