alchemy_cms 4.4.4 → 5.0.0.beta2

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 +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
@@ -23,7 +23,7 @@ module Alchemy
23
23
  # If no translation is found a humanized name is used.
24
24
  #
25
25
  def display_name_for(name)
26
- Alchemy.t(name, scope: 'element_names', default: name.to_s.humanize)
26
+ Alchemy.t(name, scope: "element_names", default: name.to_s.humanize)
27
27
  end
28
28
  end
29
29
 
@@ -32,7 +32,7 @@ module Alchemy
32
32
  # @see Alchemy::Element::Presenters#display_name_for
33
33
  #
34
34
  def display_name
35
- self.class.display_name_for(definition['name'] || name)
35
+ self.class.display_name_for(definition["name"] || name)
36
36
  end
37
37
 
38
38
  # Returns a preview text for element.
@@ -97,6 +97,7 @@ module Alchemy
97
97
 
98
98
  def preview_text_from_nested_elements(maxlength)
99
99
  return if all_nested_elements.empty?
100
+
100
101
  all_nested_elements.first.preview_text(maxlength)
101
102
  end
102
103
 
@@ -3,7 +3,7 @@
3
3
  module Alchemy
4
4
  class ElementToPage
5
5
  def self.table_name
6
- [Alchemy::Element.table_name, Alchemy::Page.table_name].join('_')
6
+ [Alchemy::Element.table_name, Alchemy::Page.table_name].join("_")
7
7
  end
8
8
  end
9
9
  end
@@ -8,14 +8,12 @@
8
8
  # value :boolean
9
9
  # created_at :datetime not null
10
10
  # updated_at :datetime not null
11
- # creator_id :integer
12
- # updater_id :integer
13
11
  #
14
12
 
15
13
  # Stores boolean values.
16
14
  # Provides a checkbox in the editor views.
17
15
  module Alchemy
18
16
  class EssenceBoolean < BaseRecord
19
- acts_as_essence ingredient_column: 'value'
17
+ acts_as_essence ingredient_column: "value"
20
18
  end
21
19
  end
@@ -6,19 +6,18 @@
6
6
  #
7
7
  # id :integer not null, primary key
8
8
  # date :datetime
9
- # creator_id :integer
10
- # updater_id :integer
11
9
  # created_at :datetime not null
12
10
  # updated_at :datetime not null
13
11
  #
14
12
 
15
13
  module Alchemy
16
14
  class EssenceDate < BaseRecord
17
- acts_as_essence ingredient_column: 'date'
15
+ acts_as_essence ingredient_column: "date"
18
16
 
19
17
  # Returns self.date for the Element#preview_text method.
20
18
  def preview_text(_maxlength = nil)
21
19
  return "" if date.blank?
20
+
22
21
  ::I18n.l(date, format: :'alchemy.essence_date')
23
22
  end
24
23
  end
@@ -8,8 +8,6 @@
8
8
  # attachment_id :integer
9
9
  # title :string
10
10
  # css_class :string
11
- # creator_id :integer
12
- # updater_id :integer
13
11
  # created_at :datetime not null
14
12
  # updated_at :datetime not null
15
13
  # link_text :string
@@ -18,19 +16,21 @@
18
16
  module Alchemy
19
17
  class EssenceFile < BaseRecord
20
18
  belongs_to :attachment, optional: true
21
- acts_as_essence ingredient_column: 'attachment'
19
+ acts_as_essence ingredient_column: "attachment"
22
20
 
23
21
  def attachment_url
24
22
  return if attachment.nil?
23
+
25
24
  routes.download_attachment_path(
26
25
  id: attachment.id,
27
26
  name: attachment.urlname,
28
- format: attachment.suffix
27
+ format: attachment.suffix,
29
28
  )
30
29
  end
31
30
 
32
31
  def preview_text(max = 30)
33
32
  return "" if attachment.blank?
33
+
34
34
  attachment.name.to_s[0..max - 1]
35
35
  end
36
36
 
@@ -6,15 +6,13 @@
6
6
  #
7
7
  # id :integer not null, primary key
8
8
  # source :text
9
- # creator_id :integer
10
- # updater_id :integer
11
9
  # created_at :datetime not null
12
10
  # updated_at :datetime not null
13
11
  #
14
12
 
15
13
  module Alchemy
16
14
  class EssenceHtml < BaseRecord
17
- acts_as_essence ingredient_column: 'source'
15
+ acts_as_essence ingredient_column: "source"
18
16
 
19
17
  # Returns the first x (default = 30) (HTML escaped) characters from self.source for the Element#preview_text method.
20
18
  def preview_text(maxlength = 30)
@@ -11,12 +11,10 @@
11
11
  # link_class_name :string
12
12
  # created_at :datetime not null
13
13
  # updated_at :datetime not null
14
- # creator_id :integer
15
- # updater_id :integer
16
14
  #
17
15
 
18
16
  module Alchemy
19
17
  class EssenceLink < BaseRecord
20
- acts_as_essence ingredient_column: 'link'
18
+ acts_as_essence ingredient_column: "link"
21
19
  end
22
20
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class EssenceNode < BaseRecord
5
+ acts_as_essence(
6
+ ingredient_column: :node,
7
+ preview_text_column: :node_name,
8
+ belongs_to: {
9
+ class_name: "Alchemy::Node",
10
+ foreign_key: :node_id,
11
+ inverse_of: :essence_nodes,
12
+ optional: true,
13
+ },
14
+ )
15
+
16
+ delegate :name, to: :node, prefix: true, allow_nil: true
17
+ end
18
+ end
@@ -2,28 +2,15 @@
2
2
 
3
3
  module Alchemy
4
4
  class EssencePage < BaseRecord
5
- PAGE_ID = /\A\d+\z/
6
-
7
5
  acts_as_essence(
8
6
  ingredient_column: :page,
9
7
  preview_text_method: :name,
10
8
  belongs_to: {
11
- class_name: 'Alchemy::Page',
9
+ class_name: "Alchemy::Page",
12
10
  foreign_key: :page_id,
13
11
  inverse_of: :essence_pages,
14
- optional: true
15
- }
12
+ optional: true,
13
+ },
16
14
  )
17
-
18
- def ingredient=(page)
19
- case page
20
- when PAGE_ID
21
- self.page = Alchemy::Page.new(id: page)
22
- when Alchemy::Page
23
- self.page = page
24
- else
25
- super
26
- end
27
- end
28
15
  end
29
16
  end
@@ -14,8 +14,6 @@
14
14
  # link_title :string
15
15
  # css_class :string
16
16
  # link_target :string
17
- # creator_id :integer
18
- # updater_id :integer
19
17
  # created_at :datetime not null
20
18
  # updated_at :datetime not null
21
19
  # crop_from :string
@@ -26,10 +24,10 @@
26
24
  module Alchemy
27
25
  class EssencePicture < BaseRecord
28
26
  acts_as_essence ingredient_column: :picture, belongs_to: {
29
- class_name: 'Alchemy::Picture',
27
+ class_name: "Alchemy::Picture",
30
28
  foreign_key: :picture_id,
31
29
  inverse_of: :essence_pictures,
32
- optional: true
30
+ optional: true,
33
31
  }
34
32
 
35
33
  delegate :image_file_width, :image_file_height, :image_file, to: :picture
@@ -80,7 +78,7 @@ module Alchemy
80
78
  format: picture.default_render_format,
81
79
  crop_from: crop_from.presence,
82
80
  crop_size: crop_size.presence,
83
- size: content.settings[:size]
81
+ size: content.settings[:size],
84
82
  }.with_indifferent_access
85
83
  end
86
84
 
@@ -90,11 +88,11 @@ module Alchemy
90
88
  # image displayed in the frontend.
91
89
  #
92
90
  # @return [String]
93
- def thumbnail_url(options = {})
91
+ def thumbnail_url
94
92
  return if picture.nil?
95
93
 
96
- crop = crop_values_present? || content.settings_value(:crop, options)
97
- size = render_size || content.settings_value(:size, options)
94
+ crop = crop_values_present? || content.settings[:crop]
95
+ size = render_size || content.settings[:size]
98
96
 
99
97
  options = {
100
98
  size: thumbnail_size(size, crop),
@@ -102,7 +100,7 @@ module Alchemy
102
100
  crop_from: crop_from.presence,
103
101
  crop_size: crop_size.presence,
104
102
  flatten: true,
105
- format: picture.image_file_format
103
+ format: picture.image_file_format,
106
104
  }
107
105
 
108
106
  picture.url(options)
@@ -116,6 +114,7 @@ module Alchemy
116
114
  # @return [String]
117
115
  def preview_text(max = 30)
118
116
  return "" if picture.nil?
117
+
119
118
  picture.name.to_s[0..max - 1]
120
119
  end
121
120
 
@@ -124,6 +123,7 @@ module Alchemy
124
123
  # @return [Hash]
125
124
  def cropping_mask
126
125
  return if crop_from.blank? || crop_size.blank?
126
+
127
127
  crop_from = point_from_string(read_attribute(:crop_from))
128
128
  crop_size = sizes_from_string(read_attribute(:crop_size))
129
129
 
@@ -137,12 +137,12 @@ module Alchemy
137
137
  picture_url(content.settings)
138
138
  end
139
139
 
140
- # Show image cropping link for content and options?
141
- def allow_image_cropping?(options = {})
142
- content && content.settings_value(:crop, options) && picture &&
140
+ # Show image cropping link for content
141
+ def allow_image_cropping?
142
+ content && content.settings[:crop] && picture &&
143
143
  picture.can_be_cropped_to(
144
- content.settings_value(:size, options),
145
- content.settings_value(:upsample, options)
144
+ content.settings[:size],
145
+ content.settings[:upsample],
146
146
  )
147
147
  end
148
148
 
@@ -161,16 +161,17 @@ module Alchemy
161
161
  end
162
162
 
163
163
  def normalize_crop_value(crop_value)
164
- self[crop_value].split('x').map { |n| normalize_number(n) }.join('x')
164
+ self[crop_value].split("x").map { |n| normalize_number(n) }.join("x")
165
165
  end
166
166
 
167
167
  def normalize_number(number)
168
168
  number = number.to_f.round
169
- number < 0 ? 0 : number
169
+ number.negative? ? 0 : number
170
170
  end
171
171
 
172
172
  def replace_newlines
173
173
  return nil if caption.nil?
174
+
174
175
  caption.gsub!(/(\r\n|\r|\n)/, "<br/>")
175
176
  end
176
177
  end
@@ -13,7 +13,7 @@ module Alchemy
13
13
  show_caption: true,
14
14
  disable_link: false,
15
15
  srcset: [],
16
- sizes: []
16
+ sizes: [],
17
17
  }.with_indifferent_access
18
18
 
19
19
  def initialize(content, options = {}, html_options = {})
@@ -33,12 +33,12 @@ module Alchemy
33
33
  output = link_to(output, url_for(essence.link), {
34
34
  title: essence.link_title.presence,
35
35
  target: essence.link_target == "blank" ? "_blank" : nil,
36
- data: {link_target: essence.link_target.presence}
36
+ data: { link_target: essence.link_target.presence },
37
37
  })
38
38
  end
39
39
 
40
40
  if caption
41
- content_tag(:figure, output, {class: essence.css_class.presence}.merge(html_options))
41
+ content_tag(:figure, output, { class: essence.css_class.presence }.merge(html_options))
42
42
  else
43
43
  output
44
44
  end
@@ -48,6 +48,7 @@ module Alchemy
48
48
 
49
49
  def caption
50
50
  return unless show_caption?
51
+
51
52
  @_caption ||= content_tag(:figcaption, essence.caption)
52
53
  end
53
54
 
@@ -57,8 +58,8 @@ module Alchemy
57
58
  alt: essence.alt_tag.presence,
58
59
  title: essence.title.presence,
59
60
  class: caption ? nil : essence.css_class.presence,
60
- srcset: srcset.join(', ').presence,
61
- sizes: options[:sizes].join(', ').presence
61
+ srcset: srcset.join(", ").presence,
62
+ sizes: options[:sizes].join(", ").presence,
62
63
  }.merge(caption ? {} : html_options)
63
64
  )
64
65
  end
@@ -74,7 +75,7 @@ module Alchemy
74
75
  def srcset
75
76
  options[:srcset].map do |size|
76
77
  url = essence.picture_url(size: size)
77
- width, height = size.split('x')
78
+ width, height = size.split("x")
78
79
  width.present? ? "#{url} #{width}w" : "#{url} #{height}h"
79
80
  end
80
81
  end
@@ -8,15 +8,13 @@
8
8
  # body :text
9
9
  # stripped_body :text
10
10
  # public :boolean
11
- # creator_id :integer
12
- # updater_id :integer
13
11
  # created_at :datetime not null
14
12
  # updated_at :datetime not null
15
13
  #
16
14
 
17
15
  module Alchemy
18
16
  class EssenceRichtext < BaseRecord
19
- acts_as_essence preview_text_column: 'stripped_body'
17
+ acts_as_essence preview_text_column: "stripped_body"
20
18
 
21
19
  before_save :strip_content
22
20
 
@@ -8,13 +8,11 @@
8
8
  # value :string
9
9
  # created_at :datetime not null
10
10
  # updated_at :datetime not null
11
- # creator_id :integer
12
- # updater_id :integer
13
11
  #
14
12
 
15
13
  # Provides a select box that stores string values.
16
14
  module Alchemy
17
15
  class EssenceSelect < BaseRecord
18
- acts_as_essence ingredient_column: 'value'
16
+ acts_as_essence ingredient_column: "value"
19
17
  end
20
18
  end
@@ -11,8 +11,6 @@
11
11
  # link_class_name :string
12
12
  # public :boolean default(FALSE)
13
13
  # link_target :string
14
- # creator_id :integer
15
- # updater_id :integer
16
14
  # created_at :datetime not null
17
15
  # updated_at :datetime not null
18
16
  #
@@ -17,6 +17,7 @@ module Alchemy
17
17
 
18
18
  def self.folded_for_user(user)
19
19
  return none unless Alchemy.user_class < ActiveRecord::Base
20
+
20
21
  where(user: user, folded: true)
21
22
  end
22
23
  end
@@ -20,15 +20,18 @@
20
20
  # locale :string
21
21
  #
22
22
 
23
- require_dependency 'alchemy/site'
23
+ require_dependency "alchemy/site"
24
24
 
25
25
  module Alchemy
26
26
  class Language < BaseRecord
27
27
  belongs_to :site
28
- has_many :pages
28
+ has_many :pages, inverse_of: :language
29
+ has_many :nodes, inverse_of: :language
29
30
 
30
31
  before_validation :set_locale, if: -> { locale.blank? }
31
32
 
33
+ has_one :root_page, -> { where(parent: nil, layoutpage: false) }, class_name: "Alchemy::Page"
34
+
32
35
  validates :name, presence: true
33
36
  validates :page_layout, presence: true
34
37
  validates :frontpage_name, presence: true
@@ -54,11 +57,13 @@ module Alchemy
54
57
  after_update :unpublish_pages,
55
58
  if: :should_unpublish_pages?
56
59
 
57
- before_destroy :check_for_default
58
- after_destroy :delete_language_root_page
60
+ before_destroy if: -> { pages.any? } do
61
+ errors.add(:pages, :still_present)
62
+ throw(:abort)
63
+ end
59
64
 
60
- scope :published, -> { where(public: true) }
61
- scope :with_root_page, -> { joins(:pages).where(Page.table_name => {language_root: true}) }
65
+ scope :published, -> { where(public: true) }
66
+ scope :with_root_page, -> { joins(:pages).where(Page.table_name => { language_root: true }) }
62
67
 
63
68
  class << self
64
69
  def on_site(site)
@@ -81,6 +86,8 @@ module Alchemy
81
86
 
82
87
  # The root page of the current language.
83
88
  def current_root_page
89
+ return unless current
90
+
84
91
  current.pages.language_roots.first
85
92
  end
86
93
 
@@ -100,16 +107,6 @@ module Alchemy
100
107
 
101
108
  include Alchemy::Language::Code
102
109
 
103
- # Root page
104
- def root_page
105
- @root_page ||= pages.language_roots.first
106
- end
107
-
108
- # Layout root page
109
- def layout_root_page
110
- @layout_root_page ||= Page.layout_root_for(id)
111
- end
112
-
113
110
  # All available locales matching this language
114
111
  #
115
112
  # Matching either the code (+language_code+ + +country_code+) or the +language_code+
@@ -118,10 +115,14 @@ module Alchemy
118
115
  #
119
116
  def matching_locales
120
117
  @_matching_locales ||= ::I18n.available_locales.select do |locale|
121
- locale.to_s.split('-')[0] == language_code
118
+ locale.to_s.split("-")[0] == language_code
122
119
  end
123
120
  end
124
121
 
122
+ def available_menu_names
123
+ Alchemy::Node.available_menu_names - nodes.reject(&:parent_id).map(&:menu_type)
124
+ end
125
+
125
126
  private
126
127
 
127
128
  def set_locale
@@ -157,36 +158,21 @@ module Alchemy
157
158
  def remove_old_default
158
159
  lang = Language.on_site(site).default
159
160
  return true if lang.nil?
161
+
160
162
  lang.default = false
161
163
  lang.save(validate: false)
162
164
  end
163
165
 
164
166
  def should_set_pages_language?
165
- if active_record_5_1?
166
- saved_change_to_language_code? || saved_change_to_country_code?
167
- else
168
- language_code_changed? || country_code_changed?
169
- end
167
+ saved_change_to_language_code? || saved_change_to_country_code?
170
168
  end
171
169
 
172
170
  def set_pages_language
173
171
  pages.update_all language_code: code
174
172
  end
175
173
 
176
- def check_for_default
177
- raise DefaultLanguageNotDeletable if default?
178
- end
179
-
180
- def delete_language_root_page
181
- root_page.try(:destroy) && layout_root_page.try(:destroy)
182
- end
183
-
184
174
  def should_unpublish_pages?
185
- if active_record_5_1?
186
- saved_changes[:public] == [true, false]
187
- else
188
- changes[:public] == [true, false]
189
- end
175
+ saved_changes[:public] == [true, false]
190
176
  end
191
177
 
192
178
  def unpublish_pages