alchemy_cms 4.6.1 → 5.0.0

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 (386) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +33 -1
  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 +30 -9
  8. data/CHANGELOG.md +102 -1
  9. data/Gemfile +24 -22
  10. data/README.md +32 -20
  11. data/Rakefile +11 -8
  12. data/alchemy_cms.gemspec +6 -5
  13. data/app/assets/javascripts/alchemy/admin.js +1 -5
  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.page_sorter.js +17 -17
  17. data/app/assets/javascripts/alchemy/node_select.js +39 -0
  18. data/app/assets/javascripts/alchemy/templates/index.js +1 -0
  19. data/app/assets/javascripts/alchemy/templates/node.hbs +16 -0
  20. data/app/assets/stylesheets/alchemy/admin.scss +3 -2
  21. data/app/assets/stylesheets/alchemy/base.scss +0 -1
  22. data/app/assets/stylesheets/alchemy/elements.scss +1 -1
  23. data/app/assets/stylesheets/alchemy/forms.scss +5 -0
  24. data/app/assets/stylesheets/alchemy/navigation.scss +1 -0
  25. data/app/assets/stylesheets/alchemy/node-select.scss +43 -0
  26. data/app/assets/stylesheets/alchemy/nodes.scss +1 -1
  27. data/app/assets/stylesheets/alchemy/sitemap.scss +5 -1
  28. data/app/assets/stylesheets/alchemy/tables.scss +1 -24
  29. data/app/assets/stylesheets/alchemy/tags.scss +2 -2
  30. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -7
  31. data/app/controllers/alchemy/admin/base_controller.rb +13 -33
  32. data/app/controllers/alchemy/admin/clipboard_controller.rb +5 -4
  33. data/app/controllers/alchemy/admin/contents_controller.rb +1 -2
  34. data/app/controllers/alchemy/admin/dashboard_controller.rb +10 -9
  35. data/app/controllers/alchemy/admin/elements_controller.rb +20 -20
  36. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +12 -14
  37. data/app/controllers/alchemy/admin/languages_controller.rb +35 -2
  38. data/app/controllers/alchemy/admin/layoutpages_controller.rb +5 -2
  39. data/app/controllers/alchemy/admin/nodes_controller.rb +5 -4
  40. data/app/controllers/alchemy/admin/pages_controller.rb +51 -63
  41. data/app/controllers/alchemy/admin/pictures_controller.rb +16 -16
  42. data/app/controllers/alchemy/admin/resources_controller.rb +21 -13
  43. data/app/controllers/alchemy/admin/sites_controller.rb +18 -0
  44. data/app/controllers/alchemy/admin/styleguide_controller.rb +1 -0
  45. data/app/controllers/alchemy/admin/tags_controller.rb +5 -3
  46. data/app/controllers/alchemy/admin/trash_controller.rb +6 -6
  47. data/app/controllers/alchemy/api/base_controller.rb +2 -2
  48. data/app/controllers/alchemy/api/contents_controller.rb +4 -4
  49. data/app/controllers/alchemy/api/elements_controller.rb +8 -8
  50. data/app/controllers/alchemy/api/nodes_controller.rb +37 -1
  51. data/app/controllers/alchemy/api/pages_controller.rb +14 -23
  52. data/app/controllers/alchemy/attachments_controller.rb +5 -5
  53. data/app/controllers/alchemy/base_controller.rb +10 -9
  54. data/app/controllers/alchemy/messages_controller.rb +16 -23
  55. data/app/controllers/alchemy/pages_controller.rb +13 -11
  56. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +3 -2
  57. data/app/controllers/concerns/alchemy/admin/current_language.rb +23 -0
  58. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +5 -5
  59. data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +4 -4
  60. data/app/controllers/concerns/alchemy/page_redirects.rb +2 -9
  61. data/app/controllers/concerns/alchemy/site_redirects.rb +2 -2
  62. data/app/decorators/alchemy/element_editor.rb +39 -0
  63. data/app/helpers/alchemy/admin/attachments_helper.rb +6 -6
  64. data/app/helpers/alchemy/admin/base_helper.rb +38 -35
  65. data/app/helpers/alchemy/admin/contents_helper.rb +3 -3
  66. data/app/helpers/alchemy/admin/elements_helper.rb +3 -88
  67. data/app/helpers/alchemy/admin/essences_helper.rb +8 -117
  68. data/app/helpers/alchemy/admin/form_helper.rb +1 -1
  69. data/app/helpers/alchemy/admin/navigation_helper.rb +24 -23
  70. data/app/helpers/alchemy/admin/pages_helper.rb +4 -4
  71. data/app/helpers/alchemy/admin/pictures_helper.rb +4 -6
  72. data/app/helpers/alchemy/admin/tags_helper.rb +8 -7
  73. data/app/helpers/alchemy/base_helper.rb +13 -8
  74. data/app/helpers/alchemy/elements_block_helper.rb +2 -31
  75. data/app/helpers/alchemy/elements_helper.rb +12 -58
  76. data/app/helpers/alchemy/pages_helper.rb +24 -174
  77. data/app/helpers/alchemy/url_helper.rb +4 -3
  78. data/app/mailers/alchemy/base_mailer.rb +1 -1
  79. data/app/mailers/alchemy/messages_mailer.rb +1 -1
  80. data/app/models/alchemy/attachment.rb +24 -19
  81. data/app/models/alchemy/base_record.rb +2 -5
  82. data/app/models/alchemy/content.rb +33 -38
  83. data/app/models/alchemy/content/factory.rb +24 -31
  84. data/app/models/alchemy/element.rb +45 -53
  85. data/app/models/alchemy/element/definitions.rb +4 -4
  86. data/app/models/alchemy/element/element_contents.rb +9 -6
  87. data/app/models/alchemy/element/element_essences.rb +4 -3
  88. data/app/models/alchemy/element/presenters.rb +3 -2
  89. data/app/models/alchemy/element_to_page.rb +1 -1
  90. data/app/models/alchemy/essence_boolean.rb +1 -3
  91. data/app/models/alchemy/essence_date.rb +2 -3
  92. data/app/models/alchemy/essence_file.rb +5 -5
  93. data/app/models/alchemy/essence_html.rb +1 -3
  94. data/app/models/alchemy/essence_link.rb +1 -3
  95. data/app/models/alchemy/essence_node.rb +18 -0
  96. data/app/models/alchemy/essence_page.rb +3 -16
  97. data/app/models/alchemy/essence_picture.rb +18 -17
  98. data/app/models/alchemy/essence_picture_view.rb +7 -6
  99. data/app/models/alchemy/essence_richtext.rb +1 -3
  100. data/app/models/alchemy/essence_select.rb +1 -3
  101. data/app/models/alchemy/essence_text.rb +0 -2
  102. data/app/models/alchemy/folded_page.rb +1 -0
  103. data/app/models/alchemy/language.rb +21 -35
  104. data/app/models/alchemy/language/code.rb +4 -4
  105. data/app/models/alchemy/legacy_page_url.rb +1 -1
  106. data/app/models/alchemy/message.rb +3 -3
  107. data/app/models/alchemy/node.rb +27 -4
  108. data/app/models/alchemy/page.rb +46 -127
  109. data/app/models/alchemy/page/fixed_attributes.rb +3 -2
  110. data/app/models/alchemy/page/page_elements.rb +35 -44
  111. data/app/models/alchemy/page/page_naming.rb +20 -70
  112. data/app/models/alchemy/page/page_natures.rb +7 -34
  113. data/app/models/alchemy/page/page_scopes.rb +23 -29
  114. data/app/models/alchemy/page/url_path.rb +0 -2
  115. data/app/models/alchemy/picture.rb +40 -30
  116. data/app/models/alchemy/picture/preprocessor.rb +26 -0
  117. data/app/models/alchemy/picture/transformations.rb +9 -7
  118. data/app/models/alchemy/picture/url.rb +9 -7
  119. data/app/models/alchemy/site.rb +6 -36
  120. data/app/models/alchemy/site/layout.rb +2 -2
  121. data/app/models/concerns/alchemy/touch_elements.rb +24 -0
  122. data/app/serializers/alchemy/content_serializer.rb +0 -3
  123. data/app/serializers/alchemy/essence_boolean_serializer.rb +3 -3
  124. data/app/serializers/alchemy/essence_date_serializer.rb +3 -3
  125. data/app/serializers/alchemy/essence_file_serializer.rb +4 -2
  126. data/app/serializers/alchemy/essence_html_serializer.rb +3 -3
  127. data/app/serializers/alchemy/essence_link_serializer.rb +3 -3
  128. data/app/serializers/alchemy/essence_picture_serializer.rb +5 -4
  129. data/app/serializers/alchemy/essence_richtext_serializer.rb +3 -3
  130. data/app/serializers/alchemy/essence_select_serializer.rb +3 -3
  131. data/app/serializers/alchemy/essence_text_serializer.rb +5 -4
  132. data/app/serializers/alchemy/node_serializer.rb +2 -0
  133. data/app/serializers/alchemy/page_tree_serializer.rb +9 -13
  134. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -2
  135. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +1 -2
  136. data/app/views/alchemy/admin/attachments/_files_list.html.erb +4 -4
  137. data/app/views/alchemy/admin/contents/create.js.erb +1 -3
  138. data/app/views/alchemy/admin/elements/_element.html.erb +9 -18
  139. data/app/views/alchemy/admin/elements/create.js.erb +1 -1
  140. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  141. data/app/views/alchemy/admin/elements/index.html.erb +3 -3
  142. data/app/views/alchemy/admin/essence_files/assign.js.erb +1 -6
  143. data/app/views/alchemy/admin/essence_files/edit.html.erb +1 -1
  144. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +1 -7
  145. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
  146. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +7 -7
  147. data/app/views/alchemy/admin/essence_pictures/update.js.erb +1 -1
  148. data/app/views/alchemy/admin/languages/_form.html.erb +5 -5
  149. data/app/views/alchemy/admin/languages/_table.html.erb +3 -3
  150. data/app/views/alchemy/admin/languages/edit.html.erb +1 -0
  151. data/app/views/alchemy/admin/languages/index.html.erb +23 -4
  152. data/app/views/alchemy/admin/languages/new.html.erb +1 -0
  153. data/app/views/alchemy/admin/layoutpages/index.html.erb +3 -3
  154. data/app/views/alchemy/admin/nodes/_form.html.erb +18 -15
  155. data/app/views/alchemy/admin/nodes/_node.html.erb +1 -5
  156. data/app/views/alchemy/admin/nodes/index.html.erb +3 -4
  157. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +0 -8
  158. data/app/views/alchemy/admin/pages/_form.html.erb +0 -1
  159. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -0
  160. data/app/views/alchemy/admin/pages/_page.html.erb +11 -19
  161. data/app/views/alchemy/admin/pages/_page_infos.html.erb +0 -4
  162. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  163. data/app/views/alchemy/admin/pages/info.html.erb +0 -9
  164. data/app/views/alchemy/admin/pages/unlock.js.erb +13 -6
  165. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +0 -2
  166. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -5
  167. data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +1 -1
  168. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -2
  169. data/app/views/alchemy/admin/pictures/index.html.erb +18 -3
  170. data/app/views/alchemy/admin/pictures/show.html.erb +1 -1
  171. data/app/views/alchemy/admin/resources/_resource.html.erb +1 -1
  172. data/app/views/alchemy/admin/resources/_table.html.erb +2 -2
  173. data/app/views/alchemy/admin/resources/index.html.erb +21 -22
  174. data/app/views/alchemy/admin/sites/_form.html.erb +8 -0
  175. data/app/views/alchemy/admin/sites/edit.html.erb +1 -0
  176. data/app/views/alchemy/admin/sites/index.html.erb +21 -9
  177. data/app/views/alchemy/admin/sites/new.html.erb +1 -0
  178. data/app/views/alchemy/admin/tags/index.html.erb +2 -2
  179. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +10 -12
  180. data/app/views/alchemy/essences/_essence_date_editor.html.erb +11 -8
  181. data/app/views/alchemy/essences/_essence_file_editor.html.erb +16 -17
  182. data/app/views/alchemy/essences/_essence_file_view.html.erb +1 -1
  183. data/app/views/alchemy/essences/_essence_html_editor.html.erb +8 -5
  184. data/app/views/alchemy/essences/_essence_link_editor.html.erb +18 -15
  185. data/app/views/alchemy/essences/_essence_node_editor.html.erb +27 -0
  186. data/app/views/alchemy/essences/_essence_node_view.html.erb +1 -0
  187. data/app/views/alchemy/essences/_essence_page_editor.html.erb +14 -11
  188. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +22 -20
  189. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +10 -7
  190. data/app/views/alchemy/essences/_essence_select_editor.html.erb +12 -16
  191. data/app/views/alchemy/essences/_essence_text_editor.html.erb +18 -17
  192. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +6 -11
  193. data/app/views/alchemy/pages/show.rss.builder +3 -2
  194. data/app/views/layouts/alchemy/admin.html.erb +1 -0
  195. data/babel.config.js +12 -0
  196. data/bin/rails +5 -4
  197. data/config/alchemy/config.yml +23 -16
  198. data/config/brakeman.ignore +1 -1
  199. data/config/initializers/assets.rb +2 -1
  200. data/config/initializers/dragonfly.rb +2 -1
  201. data/config/initializers/mime_types.rb +1 -0
  202. data/config/initializers/mini_profiler.rb +3 -2
  203. data/config/initializers/simple_form.rb +6 -6
  204. data/config/locales/alchemy.en.yml +23 -8
  205. data/config/routes.rb +25 -24
  206. data/config/spring.rb +3 -2
  207. data/db/migrate/20200226213334_alchemy_four_point_four.rb +313 -0
  208. data/db/migrate/20200423073425_create_alchemy_essence_nodes.rb +11 -0
  209. data/db/migrate/20200504210159_remove_site_id_from_nodes.rb +28 -0
  210. data/db/migrate/20200505215518_add_language_id_foreign_key_to_alchemy_pages.rb +8 -0
  211. data/db/migrate/20200511113603_add_menu_type_to_alchemy_nodes.rb +27 -0
  212. data/db/migrate/20200514091507_make_page_layoutpage_null_false.rb +6 -0
  213. data/db/migrate/20200519073500_remove_visible_from_alchemy_pages.rb +24 -0
  214. data/lib/alchemy/admin/locale.rb +3 -1
  215. data/lib/alchemy/admin/preview_url.rb +85 -0
  216. data/lib/alchemy/auth_accessors.rb +8 -7
  217. data/lib/alchemy/cache_digests/template_tracker.rb +5 -4
  218. data/lib/alchemy/config.rb +3 -5
  219. data/lib/alchemy/configuration_methods.rb +3 -1
  220. data/lib/alchemy/controller_actions.rb +6 -5
  221. data/lib/alchemy/deprecation.rb +2 -1
  222. data/lib/alchemy/elements_finder.rb +5 -5
  223. data/lib/alchemy/engine.rb +23 -8
  224. data/lib/alchemy/errors.rb +0 -7
  225. data/lib/alchemy/essence.rb +17 -16
  226. data/lib/alchemy/filetypes.rb +5 -5
  227. data/lib/alchemy/forms/builder.rb +4 -4
  228. data/lib/alchemy/hints.rb +1 -1
  229. data/lib/alchemy/i18n.rb +2 -1
  230. data/lib/alchemy/install/tasks.rb +41 -0
  231. data/lib/alchemy/modules.rb +12 -12
  232. data/lib/alchemy/name_conversions.rb +5 -5
  233. data/lib/alchemy/on_page_layout/callbacks_runner.rb +1 -0
  234. data/lib/alchemy/page_layout.rb +15 -12
  235. data/lib/alchemy/paths.rb +1 -1
  236. data/lib/alchemy/permissions.rb +7 -6
  237. data/lib/alchemy/resource.rb +25 -15
  238. data/lib/alchemy/resources_helper.rb +12 -18
  239. data/lib/alchemy/routing_constraints.rb +1 -1
  240. data/lib/alchemy/seeder.rb +42 -14
  241. data/lib/alchemy/shell.rb +13 -10
  242. data/lib/alchemy/taggable.rb +1 -0
  243. data/lib/alchemy/tasks/tidy.rb +4 -3
  244. data/lib/alchemy/test_support/config_stubbing.rb +1 -0
  245. data/lib/alchemy/test_support/essence_shared_examples.rb +72 -72
  246. data/lib/alchemy/test_support/factories.rb +1 -1
  247. data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -5
  248. data/lib/alchemy/test_support/factories/content_factory.rb +6 -6
  249. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +7 -7
  250. data/lib/alchemy/test_support/factories/element_factory.rb +9 -9
  251. data/lib/alchemy/test_support/factories/essence_file_factory.rb +3 -3
  252. data/lib/alchemy/test_support/factories/essence_page_factory.rb +3 -3
  253. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +4 -4
  254. data/lib/alchemy/test_support/factories/essence_text_factory.rb +3 -3
  255. data/lib/alchemy/test_support/factories/language_factory.rb +21 -14
  256. data/lib/alchemy/test_support/factories/node_factory.rb +8 -8
  257. data/lib/alchemy/test_support/factories/page_factory.rb +15 -27
  258. data/lib/alchemy/test_support/factories/picture_factory.rb +5 -5
  259. data/lib/alchemy/test_support/factories/site_factory.rb +7 -6
  260. data/lib/alchemy/test_support/integration_helpers.rb +1 -0
  261. data/lib/alchemy/test_support/shared_contexts.rb +5 -4
  262. data/lib/alchemy/test_support/shared_uploader_examples.rb +4 -3
  263. data/lib/alchemy/tinymce.rb +15 -13
  264. data/lib/alchemy/upgrader.rb +8 -7
  265. data/lib/alchemy/upgrader/five_point_zero.rb +41 -0
  266. data/lib/alchemy/upgrader/tasks/element_views_updater.rb +4 -4
  267. data/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb +29 -0
  268. data/lib/alchemy/version.rb +1 -1
  269. data/lib/alchemy_cms.rb +52 -50
  270. data/lib/{rails/generators → generators}/alchemy/base.rb +5 -4
  271. data/lib/{rails/generators → generators}/alchemy/elements/elements_generator.rb +13 -9
  272. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.erb +0 -0
  273. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.haml +0 -0
  274. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.slim +0 -0
  275. data/lib/{rails/generators → generators}/alchemy/essence/essence_generator.rb +15 -13
  276. data/lib/generators/alchemy/essence/templates/editor.html.erb +17 -0
  277. data/lib/{rails/generators → generators}/alchemy/essence/templates/view.html.erb +0 -0
  278. data/lib/{rails/generators → generators}/alchemy/install/files/_article.html.erb +0 -0
  279. data/lib/{rails/generators → generators}/alchemy/install/files/_standard.html.erb +0 -0
  280. data/lib/{rails/generators → generators}/alchemy/install/files/alchemy.en.yml +0 -0
  281. data/lib/generators/alchemy/install/files/alchemy_admin.js +1 -0
  282. data/lib/{rails/generators → generators}/alchemy/install/files/all.css +0 -0
  283. data/lib/{rails/generators → generators}/alchemy/install/files/all.js +0 -0
  284. data/lib/{rails/generators → generators}/alchemy/install/files/application.html.erb +0 -0
  285. data/lib/{rails/generators → generators}/alchemy/install/files/article.scss +0 -0
  286. data/lib/generators/alchemy/install/install_generator.rb +169 -0
  287. data/lib/{rails/generators → generators}/alchemy/install/templates/dragonfly.rb.tt +0 -0
  288. data/lib/{rails/generators → generators}/alchemy/install/templates/elements.yml.tt +0 -0
  289. data/lib/{rails/generators → generators}/alchemy/install/templates/menus.yml.tt +0 -0
  290. data/lib/{rails/generators → generators}/alchemy/install/templates/page_layouts.yml.tt +0 -0
  291. data/lib/{rails/generators → generators}/alchemy/menus/menus_generator.rb +2 -2
  292. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.erb +1 -4
  293. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.haml +1 -4
  294. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.slim +1 -4
  295. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.erb +1 -1
  296. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.haml +1 -1
  297. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.slim +1 -1
  298. data/lib/{rails/generators → generators}/alchemy/module/module_generator.rb +3 -2
  299. data/lib/{rails/generators → generators}/alchemy/module/templates/ability.rb.tt +0 -0
  300. data/lib/{rails/generators → generators}/alchemy/module/templates/controller.rb.tt +0 -0
  301. data/lib/{rails/generators → generators}/alchemy/module/templates/module_config.rb.tt +0 -0
  302. data/lib/{rails/generators → generators}/alchemy/page_layouts/page_layouts_generator.rb +5 -4
  303. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.erb +0 -0
  304. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.haml +0 -0
  305. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.slim +0 -0
  306. data/lib/{rails/generators → generators}/alchemy/site_layouts/site_layouts_generator.rb +4 -2
  307. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.erb +0 -0
  308. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.haml +0 -0
  309. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.slim +0 -0
  310. data/lib/{rails/generators → generators}/alchemy/views/views_generator.rb +7 -6
  311. data/lib/kaminari/scoped_pagination_url_helper.rb +1 -0
  312. data/lib/tasks/alchemy/db.rake +3 -19
  313. data/lib/tasks/alchemy/install.rake +5 -48
  314. data/lib/tasks/alchemy/tidy.rake +9 -8
  315. data/lib/tasks/alchemy/upgrade.rake +18 -116
  316. data/package.json +45 -0
  317. data/package/admin.js +14 -0
  318. data/package/src/__tests__/i18n.spec.js +70 -0
  319. data/package/src/i18n.js +48 -0
  320. data/package/src/node_tree.js +72 -0
  321. data/package/src/translations.js +32 -0
  322. data/package/src/utils/__tests__/ajax.spec.js +124 -0
  323. data/package/src/utils/__tests__/events.spec.js +38 -0
  324. data/package/src/utils/ajax.js +48 -0
  325. data/package/src/utils/events.js +16 -0
  326. data/vendor/assets/fonts/fa-regular-400.eot +0 -0
  327. data/vendor/assets/fonts/fa-regular-400.svg +798 -358
  328. data/vendor/assets/fonts/fa-regular-400.ttf +0 -0
  329. data/vendor/assets/fonts/fa-regular-400.woff +0 -0
  330. data/vendor/assets/fonts/fa-regular-400.woff2 +0 -0
  331. data/vendor/assets/fonts/fa-solid-900.eot +0 -0
  332. data/vendor/assets/fonts/fa-solid-900.svg +4933 -1408
  333. data/vendor/assets/fonts/fa-solid-900.ttf +0 -0
  334. data/vendor/assets/fonts/fa-solid-900.woff +0 -0
  335. data/vendor/assets/fonts/fa-solid-900.woff2 +0 -0
  336. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +1 -2
  337. data/vendor/assets/stylesheets/fontawesome/_core.scss +5 -0
  338. data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +1 -1
  339. data/vendor/assets/stylesheets/fontawesome/_icons.scss +651 -2
  340. data/vendor/assets/stylesheets/fontawesome/_mixins.scss +0 -1
  341. data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +3 -2
  342. data/vendor/assets/stylesheets/fontawesome/_stacked.scss +1 -1
  343. data/vendor/assets/stylesheets/fontawesome/_variables.scss +662 -9
  344. data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +2 -2
  345. data/vendor/assets/stylesheets/fontawesome/regular.scss +23 -0
  346. data/vendor/assets/stylesheets/fontawesome/solid.scss +24 -0
  347. metadata +112 -88
  348. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +0 -32
  349. data/app/assets/javascripts/alchemy/alchemy.node_tree.js +0 -66
  350. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +0 -29
  351. data/app/assets/javascripts/alchemy/alchemy.utils.js +0 -45
  352. data/app/helpers/alchemy/essences_helper.rb +0 -119
  353. data/app/models/concerns/alchemy/content_touching.rb +0 -23
  354. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -15
  355. data/app/views/alchemy/admin/contents/_missing.html.erb +0 -17
  356. data/app/views/alchemy/admin/pages/_menu_fields.html.erb +0 -37
  357. data/app/views/alchemy/admin/pages/configure_external.html.erb +0 -32
  358. data/app/views/alchemy/elements/_editor_not_found.html.erb +0 -4
  359. data/app/views/alchemy/navigation/_image_link.html.erb +0 -14
  360. data/app/views/alchemy/navigation/_link.html.erb +0 -19
  361. data/app/views/alchemy/navigation/_renderer.html.erb +0 -29
  362. data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -363
  363. data/db/migrate/20180227224537_migrate_tags_to_gutentag.rb +0 -41
  364. data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +0 -6
  365. data/db/migrate/20191016073858_create_alchemy_essence_pages.rb +0 -8
  366. data/db/migrate/20191029212236_create_alchemy_nodes.rb +0 -24
  367. data/db/migrate/20200226081535_add_site_id_to_alchemy_nodes.rb +0 -15
  368. data/lib/alchemy/ssl_protection.rb +0 -34
  369. data/lib/alchemy/tasks/helpers.rb +0 -81
  370. data/lib/alchemy/test_support/controller_requests.rb +0 -93
  371. data/lib/alchemy/upgrader/four_point_four.rb +0 -52
  372. data/lib/alchemy/upgrader/four_point_one.rb +0 -42
  373. data/lib/alchemy/upgrader/four_point_six.rb +0 -50
  374. data/lib/alchemy/upgrader/four_point_two.rb +0 -85
  375. data/lib/alchemy/upgrader/tasks/cells_migration.rb +0 -43
  376. data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +0 -148
  377. data/lib/alchemy/upgrader/tasks/element_partial_name_variable_updater.rb +0 -28
  378. data/lib/alchemy/upgrader/tasks/harden_acts_as_taggable_on_migrations.rb +0 -27
  379. data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +0 -65
  380. data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +0 -210
  381. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +0 -15
  382. data/lib/rails/generators/alchemy/install/install_generator.rb +0 -60
  383. data/lib/tasks/alchemy/convert.rake +0 -97
  384. data/vendor/assets/javascripts/sortable/Sortable.min.js +0 -2
  385. data/vendor/assets/stylesheets/fontawesome/fa-regular.scss +0 -22
  386. data/vendor/assets/stylesheets/fontawesome/fa-solid.scss +0 -23
@@ -3,10 +3,10 @@
3
3
  module Alchemy
4
4
  class PagesController < Alchemy::BaseController
5
5
  SHOW_PAGE_PARAMS_KEYS = [
6
- 'action',
7
- 'controller',
8
- 'urlname',
9
- 'locale'
6
+ "action",
7
+ "controller",
8
+ "urlname",
9
+ "locale",
10
10
  ]
11
11
 
12
12
  include OnPageLayout::CallbacksRunner
@@ -78,7 +78,7 @@ module Alchemy
78
78
  def sitemap
79
79
  @pages = Page.sitemap
80
80
  respond_to do |format|
81
- format.xml { render layout: 'alchemy/sitemap' }
81
+ format.xml { render layout: "alchemy/sitemap" }
82
82
  end
83
83
  end
84
84
 
@@ -95,7 +95,7 @@ module Alchemy
95
95
  #
96
96
  def load_index_page
97
97
  @page ||= Language.current_root_page
98
- render template: 'alchemy/welcome', layout: false if signup_required?
98
+ render template: "alchemy/welcome", layout: false if signup_required?
99
99
  end
100
100
 
101
101
  # == Loads page by urlname
@@ -108,9 +108,11 @@ module Alchemy
108
108
  # @return NilClass
109
109
  #
110
110
  def load_page
111
+ page_not_found! unless Language.current
112
+
111
113
  @page ||= Language.current.pages.contentpages.find_by(
112
114
  urlname: params[:urlname],
113
- language_code: params[:locale] || Language.current.code
115
+ language_code: params[:locale] || Language.current.code,
114
116
  )
115
117
  end
116
118
 
@@ -148,7 +150,7 @@ module Alchemy
148
150
  if @page.contains_feed?
149
151
  render action: :show, layout: false, handlers: [:builder]
150
152
  else
151
- render xml: {error: 'Not found'}, status: 404
153
+ render xml: { error: "Not found" }, status: 404
152
154
  end
153
155
  end
154
156
  end
@@ -191,9 +193,9 @@ module Alchemy
191
193
  #
192
194
  def render_fresh_page?
193
195
  must_not_cache? || stale?(etag: page_etag,
194
- last_modified: @page.published_at,
195
- public: !@page.restricted,
196
- template: 'pages/show')
196
+ last_modified: @page.published_at,
197
+ public: !@page.restricted,
198
+ template: "pages/show")
197
199
  end
198
200
 
199
201
  # don't cache pages if we have flash message to display or the page has caching disabled
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Alchemy
2
3
  module Admin
3
4
  module ArchiveOverlay
@@ -11,8 +12,8 @@ module Alchemy
11
12
  @content = Content.find_by(id: params[:content_id])
12
13
 
13
14
  respond_to do |format|
14
- format.html { render partial: 'archive_overlay' }
15
- format.js { render action: 'archive_overlay' }
15
+ format.html { render partial: "archive_overlay" }
16
+ format.js { render action: "archive_overlay" }
16
17
  end
17
18
  end
18
19
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Admin
5
+ module CurrentLanguage
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_action :load_current_language
10
+ end
11
+
12
+ private
13
+
14
+ def load_current_language
15
+ @current_language = Alchemy::Language.current
16
+ if @current_language.nil?
17
+ flash[:warning] = Alchemy.t("Please create a language first.")
18
+ redirect_to admin_languages_path
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -8,12 +8,12 @@ module Alchemy
8
8
  def successful_uploader_response(file:, status: :created)
9
9
  message = Alchemy.t(:upload_success,
10
10
  scope: [:uploader, file.class.model_name.i18n_key],
11
- name: file.name
11
+ name: file.name,
12
12
  )
13
13
 
14
14
  {
15
15
  json: uploader_response(file: file, message: message),
16
- status: status
16
+ status: status,
17
17
  }
18
18
  end
19
19
 
@@ -21,12 +21,12 @@ module Alchemy
21
21
  message = Alchemy.t(:upload_failure,
22
22
  scope: [:uploader, file.class.model_name.i18n_key],
23
23
  error: file.errors[:file].join,
24
- name: file.name
24
+ name: file.name,
25
25
  )
26
26
 
27
27
  {
28
28
  json: uploader_response(file: file, message: message),
29
- status: :unprocessable_entity
29
+ status: :unprocessable_entity,
30
30
  }
31
31
  end
32
32
 
@@ -35,7 +35,7 @@ module Alchemy
35
35
  def uploader_response(file:, message:)
36
36
  {
37
37
  files: [file.to_jq_upload],
38
- growl_message: message
38
+ growl_message: message,
39
39
  }
40
40
  end
41
41
  end
@@ -36,18 +36,18 @@ module Alchemy
36
36
 
37
37
  alchemy.show_page_path(
38
38
  locale: prefix_locale? ? page.language_code : nil,
39
- urlname: page.urlname
39
+ urlname: page.urlname,
40
40
  )
41
41
  end
42
42
 
43
43
  def legacy_urls
44
44
  # /slug/tree => slug/tree
45
- urlname = (request.fullpath[1..-1] if request.fullpath[0] == '/') || request.fullpath
45
+ urlname = (request.fullpath[1..-1] if request.fullpath[0] == "/") || request.fullpath
46
46
  LegacyPageUrl.joins(:page).where(
47
47
  urlname: urlname,
48
48
  Page.table_name => {
49
- language_id: Language.current.id
50
- }
49
+ language_id: Language.current.id,
50
+ },
51
51
  )
52
52
  end
53
53
 
@@ -27,8 +27,7 @@ module Alchemy
27
27
  # @return NilClass
28
28
  #
29
29
  def redirect_url
30
- @_redirect_url ||= public_child_redirect_url || controller_and_action_url ||
31
- locale_prefixed_url || nil
30
+ @_redirect_url ||= public_child_redirect_url || locale_prefixed_url || nil
32
31
  end
33
32
 
34
33
  def locale_prefixed_url
@@ -48,17 +47,11 @@ module Alchemy
48
47
  end
49
48
  end
50
49
 
51
- def controller_and_action_url
52
- return unless @page.definition['controller']
53
-
54
- main_app.url_for(@page.controller_and_action)
55
- end
56
-
57
50
  # Page url with or without locale while keeping all additional params
58
51
  def page_redirect_url(options = {})
59
52
  options = {
60
53
  locale: prefix_locale? ? @page.language_code : nil,
61
- urlname: @page.urlname
54
+ urlname: @page.urlname,
62
55
  }.merge(options)
63
56
 
64
57
  alchemy.show_page_path additional_params.merge(options)
@@ -16,8 +16,8 @@ module Alchemy
16
16
  end
17
17
 
18
18
  def needs_redirect_to_primary_host?
19
- current_alchemy_site.redirect_to_primary_host? &&
20
- current_alchemy_site.host != '*' &&
19
+ current_alchemy_site&.redirect_to_primary_host? &&
20
+ current_alchemy_site.host != "*" &&
21
21
  current_alchemy_site.host != request.host
22
22
  end
23
23
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class ElementEditor < SimpleDelegator
5
+ alias_method :element, :__getobj__
6
+
7
+ def to_partial_path
8
+ "alchemy/admin/elements/element"
9
+ end
10
+
11
+ # CSS classes for the element editor partial.
12
+ def css_classes
13
+ [
14
+ "element-editor",
15
+ content_definitions.present? ? "with-contents" : "without-contents",
16
+ nestable_elements.any? ? "nestable" : "not-nestable",
17
+ taggable? ? "taggable" : "not-taggable",
18
+ folded ? "folded" : "expanded",
19
+ compact? ? "compact" : nil,
20
+ fixed? ? "is-fixed" : "not-fixed",
21
+ ].join(" ")
22
+ end
23
+
24
+ # Tells us, if we should show the element footer and form inputs.
25
+ def editable?
26
+ return false if folded?
27
+
28
+ content_definitions.present? || taggable?
29
+ end
30
+
31
+ # Fixes Rails partial renderer calling to_model on the object
32
+ # which reveals the delegated element instead of this decorator.
33
+ def respond_to?(method_name)
34
+ return false if method_name == :to_model
35
+
36
+ super
37
+ end
38
+ end
39
+ end
@@ -6,17 +6,17 @@ module Alchemy
6
6
  include Alchemy::Admin::BaseHelper
7
7
 
8
8
  def mime_to_human(mime)
9
- Alchemy.t(mime, scope: 'mime_types', default: Alchemy.t(:document))
9
+ Alchemy.t(mime, scope: "mime_types", default: Alchemy.t(:document))
10
10
  end
11
11
 
12
12
  def attachment_preview_size(attachment)
13
13
  case attachment.icon_css_class
14
- when 'image' then '600x475'
15
- when 'audio' then '600x190'
16
- when 'video' then '600x485'
17
- when 'pdf' then '600x500'
14
+ when "image" then "600x475"
15
+ when "audio" then "600x190"
16
+ when "video" then "600x485"
17
+ when "pdf" then "600x500"
18
18
  else
19
- '600x145'
19
+ "600x145"
20
20
  end
21
21
  end
22
22
  end
@@ -23,7 +23,7 @@ module Alchemy
23
23
  def current_alchemy_user_name
24
24
  name = current_alchemy_user.try(:alchemy_display_name)
25
25
  if name.present?
26
- content_tag :span, "#{Alchemy.t('Logged in as')} #{name}", class: 'current-user-name'
26
+ content_tag :span, "#{Alchemy.t("Logged in as")} #{name}", class: "current-user-name"
27
27
  end
28
28
  end
29
29
 
@@ -55,7 +55,7 @@ module Alchemy
55
55
  default_options = {modal: true}
56
56
  options = default_options.merge(options)
57
57
  link_to content, url,
58
- html_options.merge('data-alchemy-dialog' => options.to_json)
58
+ html_options.merge("data-alchemy-dialog" => options.to_json)
59
59
  end
60
60
 
61
61
  # Used for translations selector in Alchemy cockpit user settings.
@@ -99,13 +99,13 @@ module Alchemy
99
99
  #
100
100
  def js_filter_field(items, options = {})
101
101
  options = {
102
- class: 'js_filter_field',
103
- data: {'alchemy-list-filter' => items}
102
+ class: "js_filter_field",
103
+ data: {"alchemy-list-filter" => items},
104
104
  }.merge(options)
105
- content_tag(:div, class: 'js_filter_field_box') do
105
+ content_tag(:div, class: "js_filter_field_box") do
106
106
  concat text_field_tag(nil, nil, options)
107
107
  concat render_icon(:search)
108
- concat link_to(render_icon(:times, size: 'xs'), '', class: 'js_filter_field_clear', title: Alchemy.t(:click_to_show_all))
108
+ concat link_to(render_icon(:times, size: "xs"), "", class: "js_filter_field_clear", title: Alchemy.t(:click_to_show_all))
109
109
  end
110
110
  end
111
111
 
@@ -136,12 +136,12 @@ module Alchemy
136
136
  def link_to_confirm_dialog(link_string = "", message = "", url = "", html_options = {})
137
137
  link_to(link_string, url,
138
138
  html_options.merge(
139
- 'data-alchemy-confirm-delete' => {
139
+ "data-alchemy-confirm-delete" => {
140
140
  title: Alchemy.t(:please_confirm),
141
141
  message: message,
142
142
  ok_label: Alchemy.t("Yes"),
143
- cancel_label: Alchemy.t("No")
144
- }.to_json
143
+ cancel_label: Alchemy.t("No"),
144
+ }.to_json,
145
145
  )
146
146
  )
147
147
  end
@@ -170,10 +170,10 @@ module Alchemy
170
170
  message: Alchemy.t(:confirm_to_proceed),
171
171
  ok_label: Alchemy.t("Yes"),
172
172
  title: Alchemy.t(:please_confirm),
173
- cancel_label: Alchemy.t("No")
173
+ cancel_label: Alchemy.t("No"),
174
174
  }.merge(options)
175
- form_tag url, {method: html_options.delete(:method), class: 'button-with-confirm'} do
176
- button_tag value, html_options.merge('data-alchemy-confirm' => options.to_json)
175
+ form_tag url, {method: html_options.delete(:method), class: "button-with-confirm"} do
176
+ button_tag value, html_options.merge("data-alchemy-confirm" => options.to_json)
177
177
  end
178
178
  end
179
179
 
@@ -188,18 +188,18 @@ module Alchemy
188
188
  #
189
189
  def delete_button(url, options = {}, html_options = {})
190
190
  options = {
191
- title: Alchemy.t('Delete'),
192
- message: Alchemy.t('Are you sure?'),
193
- icon: :minus
191
+ title: Alchemy.t("Delete"),
192
+ message: Alchemy.t("Are you sure?"),
193
+ icon: :minus,
194
194
  }.merge(options)
195
195
  button_with_confirm(
196
196
  render_icon(options[:icon]),
197
197
  url, {
198
- message: options[:message]
198
+ message: options[:message],
199
199
  }, {
200
- method: 'delete',
200
+ method: "delete",
201
201
  title: options[:title],
202
- class: "icon_button #{html_options.delete(:class)}".strip
202
+ class: "icon_button #{html_options.delete(:class)}".strip,
203
203
  }.merge(html_options)
204
204
  )
205
205
  end
@@ -259,11 +259,11 @@ module Alchemy
259
259
  active: false,
260
260
  link_options: {},
261
261
  dialog_options: {},
262
- loading_indicator: false
262
+ loading_indicator: false,
263
263
  }.merge(options.symbolize_keys)
264
264
  button = render(
265
- 'alchemy/admin/partials/toolbar_button',
266
- options: options
265
+ "alchemy/admin/partials/toolbar_button",
266
+ options: options,
267
267
  )
268
268
  if options[:skip_permission_check] || can?(*permission_from_options(options))
269
269
  button
@@ -302,18 +302,20 @@ module Alchemy
302
302
  def toolbar(options = {})
303
303
  defaults = {
304
304
  buttons: [],
305
- search: true
305
+ search: true,
306
306
  }
307
307
  options = defaults.merge(options)
308
308
  content_for(:toolbar) do
309
309
  content = <<-CONTENT.strip_heredoc
310
310
  #{options[:buttons].map { |button_options| toolbar_button(button_options) }.join}
311
- #{render('alchemy/admin/partials/search_form', url: options[:search_url]) if options[:search]}
311
+ #{render("alchemy/admin/partials/search_form", url: options[:search_url]) if options[:search]}
312
312
  CONTENT
313
313
  content.html_safe
314
314
  end
315
315
  end
316
316
 
317
+ deprecate toolbar: "Please use `content_for(:toolbar)` instead", deprecator: Alchemy::Deprecation
318
+
317
319
  # (internal) Used by upload form
318
320
  def new_asset_path_with_session_information(asset_type)
319
321
  session_key = Rails.application.config.session_options[:key]
@@ -360,7 +362,7 @@ module Alchemy
360
362
  # The value the input displays. If you pass a String its parsed with +Time.parse+
361
363
  #
362
364
  def alchemy_datepicker(object, method, html_options = {})
363
- type = html_options.delete(:type) || 'date'
365
+ type = html_options.delete(:type) || "date"
364
366
  date = html_options.delete(:value) || object.send(method.to_sym).presence
365
367
  date = Time.zone.parse(date) if date.is_a?(String)
366
368
  value = date ? date.iso8601 : nil
@@ -373,9 +375,10 @@ module Alchemy
373
375
  # The model class needs to include the hints module
374
376
  def render_hint_for(element)
375
377
  return unless element.has_hint?
376
- content_tag :span, class: 'hint-with-icon' do
377
- render_icon('question-circle') +
378
- content_tag(:span, element.hint.html_safe, class: 'hint-bubble')
378
+
379
+ content_tag :span, class: "hint-with-icon" do
380
+ render_icon("question-circle") +
381
+ content_tag(:span, element.hint.html_safe, class: "hint-bubble")
379
382
  end
380
383
  end
381
384
 
@@ -385,7 +388,7 @@ module Alchemy
385
388
  controller_name,
386
389
  action_name,
387
390
  content_for(:main_menu_style),
388
- content_for(:alchemy_body_class)
391
+ content_for(:alchemy_body_class),
389
392
  ].compact
390
393
  end
391
394
 
@@ -404,7 +407,7 @@ module Alchemy
404
407
 
405
408
  # Returns the regular expression used for external url validation in link dialog.
406
409
  def link_url_regexp
407
- Alchemy::Config.get(:format_matchers)['link_url'] || /^(mailto:|\/|[a-z]+:\/\/)/
410
+ Alchemy::Config.get(:format_matchers)["link_url"] || /^(mailto:|\/|[a-z]+:\/\/)/
408
411
  end
409
412
 
410
413
  # Renders a hint with tooltip
@@ -417,9 +420,9 @@ module Alchemy
417
420
  # @param icon: 'exclamation-triangle' [String] - Icon name
418
421
  #
419
422
  # @return [String]
420
- def hint_with_tooltip(text, icon: 'exclamation-triangle')
421
- content_tag :span, class: 'hint-with-icon' do
422
- render_icon(icon) + content_tag(:span, text, class: 'hint-bubble')
423
+ def hint_with_tooltip(text, icon: "exclamation-triangle")
424
+ content_tag :span, class: "hint-with-icon" do
425
+ render_icon(icon) + content_tag(:span, text, class: "hint-bubble")
423
426
  end
424
427
  end
425
428
 
@@ -427,7 +430,7 @@ module Alchemy
427
430
  # that explains the user that the page layout is missing
428
431
  def page_layout_missing_warning
429
432
  hint_with_tooltip(
430
- Alchemy.t(:page_definition_missing)
433
+ Alchemy.t(:page_definition_missing),
431
434
  )
432
435
  end
433
436
 
@@ -442,10 +445,10 @@ module Alchemy
442
445
  end
443
446
 
444
447
  def permission_array_from_url(options)
445
- action_controller = options[:url].gsub(/\A\//, '').split('/')
448
+ action_controller = options[:url].gsub(/\A\//, "").split("/")
446
449
  [
447
450
  action_controller.last.to_sym,
448
- action_controller[0..action_controller.length - 2].join('_').to_sym
451
+ action_controller[0..action_controller.length - 2].join("_").to_sym,
449
452
  ]
450
453
  end
451
454
  end