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
@@ -19,7 +19,7 @@ module Alchemy
19
19
  # Returns one element definition by given name.
20
20
  #
21
21
  def definition_by_name(name)
22
- definitions.detect { |d| d['name'] == name }
22
+ definitions.detect { |d| d["name"] == name }
23
23
  end
24
24
 
25
25
  private
@@ -30,21 +30,21 @@ module Alchemy
30
30
  if ::File.exist?(definitions_file_path)
31
31
  ::YAML.safe_load(ERB.new(File.read(definitions_file_path)).result, YAML_WHITELIST_CLASSES, [], true) || []
32
32
  else
33
- raise LoadError, "Could not find elements.yml file! Please run `rails generate alchemy:scaffold`"
33
+ raise LoadError, "Could not find elements.yml file! Please run `rails generate alchemy:install`"
34
34
  end
35
35
  end
36
36
 
37
37
  # Returns the +elements.yml+ file path
38
38
  #
39
39
  def definitions_file_path
40
- Rails.root.join 'config/alchemy/elements.yml'
40
+ Rails.root.join "config/alchemy/elements.yml"
41
41
  end
42
42
  end
43
43
 
44
44
  # The definition of this element.
45
45
  #
46
46
  def definition
47
- if definition = self.class.definitions.detect { |d| d['name'] == name }
47
+ if definition = self.class.definitions.detect { |d| d["name"] == name }
48
48
  definition
49
49
  else
50
50
  log_warning "Could not find element definition for #{name}. Please check your elements.yml file!"
@@ -47,6 +47,7 @@ module Alchemy
47
47
  #
48
48
  def update_contents(contents_attributes)
49
49
  return true if contents_attributes.nil?
50
+
50
51
  contents.each do |content|
51
52
  content_hash = contents_attributes[content.id.to_s] || next
52
53
  content.update_essence(content_hash) || errors.add(:base, :essence_validation_failed)
@@ -72,7 +73,7 @@ module Alchemy
72
73
  # rss_title: true
73
74
  #
74
75
  def content_for_rss_title
75
- content_for_rss_meta('title')
76
+ content_for_rss_meta("title")
76
77
  end
77
78
 
78
79
  # Returns the content that is marked as rss description.
@@ -86,13 +87,14 @@ module Alchemy
86
87
  # rss_description: true
87
88
  #
88
89
  def content_for_rss_description
89
- content_for_rss_meta('description')
90
+ content_for_rss_meta("description")
90
91
  end
91
92
 
92
93
  # Returns the array with the hashes for all element contents in the elements.yml file
93
94
  def content_definitions
94
95
  return nil if definition.blank?
95
- definition['contents']
96
+
97
+ definition["contents"]
96
98
  end
97
99
 
98
100
  # Returns the definition for given content_name
@@ -101,7 +103,7 @@ module Alchemy
101
103
  log_warning "Element #{name} is missing the content definition for #{content_name}"
102
104
  nil
103
105
  else
104
- content_definitions.detect { |d| d['name'] == content_name.to_s }
106
+ content_definitions.detect { |d| d["name"] == content_name.to_s }
105
107
  end
106
108
  end
107
109
 
@@ -136,12 +138,13 @@ module Alchemy
136
138
  def content_for_rss_meta(type)
137
139
  definition = content_definitions.detect { |c| c["rss_#{type}"] }
138
140
  return if definition.blank?
139
- contents.detect { |content| content.name == definition['name'] }
141
+
142
+ contents.detect { |content| content.name == definition["name"] }
140
143
  end
141
144
 
142
145
  # creates the contents for this element as described in the elements.yml
143
146
  def create_contents
144
- definition.fetch('contents', []).each do |attributes|
147
+ definition.fetch("contents", []).each do |attributes|
145
148
  Content.create(attributes.merge(element: self))
146
149
  end
147
150
  end
@@ -6,6 +6,7 @@ module Alchemy
6
6
  def ingredient(name)
7
7
  content = content_by_name(name)
8
8
  return nil if content.blank?
9
+
9
10
  content.ingredient
10
11
  end
11
12
 
@@ -96,12 +97,12 @@ module Alchemy
96
97
  errors.each do |error|
97
98
  messages << Alchemy.t(
98
99
  "#{name}.#{content_name}.#{error}",
99
- scope: 'content_validations',
100
+ scope: "content_validations",
100
101
  default: [
101
102
  "fields.#{content_name}.#{error}".to_sym,
102
- "errors.#{error}".to_sym
103
+ "errors.#{error}".to_sym,
103
104
  ],
104
- field: Content.translated_label_for(content_name, name)
105
+ field: Content.translated_label_for(content_name, name),
105
106
  )
106
107
  end
107
108
  end
@@ -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
- name: attachment.urlname,
28
- format: attachment.suffix
26
+ name: attachment.slug,
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,13 +137,13 @@ 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)
146
- )
144
+ content.settings[:size],
145
+ content.settings[:upsample],
146
+ ) && !!picture.image_file
147
147
  end
148
148
 
149
149
  def crop_values_present?
@@ -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