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
@@ -22,10 +22,13 @@ module Alchemy
22
22
  if definition.blank?
23
23
  raise ContentDefinitionError, "No definition found in elements.yml for #{attributes.inspect} and #{element.inspect}"
24
24
  end
25
- super(name: definition['name'], element_id: element.id)
25
+
26
+ super(
27
+ name: definition[:name],
28
+ essence_type: normalize_essence_type(definition[:type]),
29
+ element_id: element.id
30
+ ).tap(&:build_essence)
26
31
  end
27
- alias_method :build, :new
28
- deprecate build: :new, deprecator: Alchemy::Deprecation
29
32
 
30
33
  # Creates a new content from elements definition in the +elements.yml+ file.
31
34
  #
@@ -34,20 +37,11 @@ module Alchemy
34
37
  #
35
38
  # @return [Alchemy::Content]
36
39
  #
37
- def create(*args)
38
- attributes = args.last || {}
39
- if args.length > 1
40
- Alchemy::Deprecation.warn 'Passing an element as first argument to Alchemy::Content.create is deprecated! Pass an attribute hash with element inside instead.'
41
- element = args.first
42
- else
43
- element = attributes[:element]
44
- end
45
- new(attributes.merge(element: element)).tap do |content|
46
- content.create_essence!(attributes[:essence_type])
40
+ def create(attributes = {})
41
+ new(attributes).tap do |content|
42
+ content.essence.save && content.save
47
43
  end
48
44
  end
49
- alias_method :create_from_scratch, :create
50
- deprecate create_from_scratch: :create, deprecator: Alchemy::Deprecation
51
45
 
52
46
  # Creates a copy of source and also copies the associated essence.
53
47
  #
@@ -62,11 +56,11 @@ module Alchemy
62
56
  new_content = Content.new(
63
57
  source.attributes.
64
58
  except(*SKIPPED_ATTRIBUTES_ON_COPY).
65
- merge(differences.with_indifferent_access)
59
+ merge(differences.with_indifferent_access),
66
60
  )
67
61
  new_essence = source.essence.class.create!(
68
62
  source.essence.attributes.
69
- except(*SKIPPED_ATTRIBUTES_ON_COPY)
63
+ except(*SKIPPED_ATTRIBUTES_ON_COPY),
70
64
  )
71
65
  new_content.tap do |content|
72
66
  content.essence = new_essence
@@ -77,7 +71,7 @@ module Alchemy
77
71
  # Returns all content definitions from elements.yml
78
72
  #
79
73
  def definitions
80
- definitions = Element.definitions.flat_map { |e| e['contents'] }
74
+ definitions = Element.definitions.flat_map { |e| e["contents"] }
81
75
  definitions.compact!
82
76
  definitions
83
77
  end
@@ -119,12 +113,22 @@ module Alchemy
119
113
  element.content_definition_for(name) || {}
120
114
  end
121
115
 
116
+ # Build essence from definition.
117
+ #
118
+ # If an optional type is passed, this type of essence gets created.
119
+ #
120
+ def build_essence(type = essence_type)
121
+ self.essence = essence_class(type).new({
122
+ ingredient: default_value,
123
+ })
124
+ end
125
+
122
126
  # Creates essence from definition.
123
127
  #
124
128
  # If an optional type is passed, this type of essence gets created.
125
129
  #
126
130
  def create_essence!(type = nil)
127
- self.essence = essence_class(type).create!(prepared_attributes_for_essence)
131
+ build_essence(type).save!
128
132
  save!
129
133
  end
130
134
 
@@ -135,18 +139,7 @@ module Alchemy
135
139
  # If an optional type is passed, this type of essence gets constantized.
136
140
  #
137
141
  def essence_class(type = nil)
138
- Content.normalize_essence_type(type || definition['type']).constantize
139
- end
140
-
141
- # Prepares the attributes for creating the essence.
142
- #
143
- # 1. It sets a default text if given in +elements.yml+
144
- #
145
- def prepared_attributes_for_essence
146
- attributes = {
147
- ingredient: default_text(definition['default'])
148
- }
149
- attributes
142
+ Content.normalize_essence_type(type || definition["type"]).constantize
150
143
  end
151
144
  end
152
145
  end
@@ -22,6 +22,8 @@
22
22
 
23
23
  module Alchemy
24
24
  class Element < BaseRecord
25
+ NAME_REGEXP = /\A[a-z0-9_-]+\z/
26
+
25
27
  include Alchemy::Logger
26
28
  include Alchemy::Taggable
27
29
  include Alchemy::Hints
@@ -34,7 +36,7 @@ module Alchemy
34
36
  "hint",
35
37
  "taggable",
36
38
  "compact",
37
- "message"
39
+ "message",
38
40
  ].freeze
39
41
 
40
42
  SKIPPED_ATTRIBUTES_ON_COPY = [
@@ -45,7 +47,7 @@ module Alchemy
45
47
  "folded",
46
48
  "position",
47
49
  "updated_at",
48
- "updater_id"
50
+ "updater_id",
49
51
  ].freeze
50
52
 
51
53
  # All Elements that share the same page id and parent element id and are fixed or not are considered a list.
@@ -60,17 +62,17 @@ module Alchemy
60
62
 
61
63
  stampable stamper_class_name: Alchemy.user_class_name
62
64
 
63
- has_many :contents, -> { order(:position) }, dependent: :destroy, inverse_of: :element
65
+ has_many :contents, dependent: :destroy, inverse_of: :element
64
66
 
65
67
  has_many :all_nested_elements,
66
68
  -> { order(:position).not_trashed },
67
- class_name: 'Alchemy::Element',
69
+ class_name: "Alchemy::Element",
68
70
  foreign_key: :parent_element_id,
69
71
  dependent: :destroy
70
72
 
71
73
  has_many :nested_elements,
72
74
  -> { order(:position).available },
73
- class_name: 'Alchemy::Element',
75
+ class_name: "Alchemy::Element",
74
76
  foreign_key: :parent_element_id,
75
77
  dependent: :destroy,
76
78
  inverse_of: :parent_element
@@ -79,17 +81,17 @@ module Alchemy
79
81
 
80
82
  # A nested element belongs to a parent element.
81
83
  belongs_to :parent_element,
82
- class_name: 'Alchemy::Element',
84
+ class_name: "Alchemy::Element",
83
85
  optional: true,
84
86
  touch: true,
85
87
  inverse_of: :nested_elements
86
88
 
87
89
  has_and_belongs_to_many :touchable_pages, -> { distinct },
88
- class_name: 'Alchemy::Page',
90
+ class_name: "Alchemy::Page",
89
91
  join_table: ElementToPage.table_name
90
92
 
91
93
  validates_presence_of :name, on: :create
92
- validates_format_of :name, on: :create, with: /\A[a-z0-9_-]+\z/
94
+ validates_format_of :name, on: :create, with: NAME_REGEXP
93
95
 
94
96
  attr_accessor :autogenerate_contents
95
97
  attr_accessor :autogenerate_nested_elements
@@ -98,19 +100,19 @@ module Alchemy
98
100
 
99
101
  after_update :touch_touchable_pages
100
102
 
101
- scope :trashed, -> { where(position: nil).order('updated_at DESC') }
102
- scope :not_trashed, -> { where.not(position: nil) }
103
- scope :published, -> { where(public: true) }
104
- scope :not_restricted, -> { joins(:page).merge(Page.not_restricted) }
105
- scope :available, -> { published.not_trashed }
106
- scope :named, ->(names) { where(name: names) }
107
- scope :excluded, ->(names) { where.not(name: names) }
108
- scope :fixed, -> { where(fixed: true) }
109
- scope :unfixed, -> { where(fixed: false) }
110
- scope :from_current_site, -> { where(Language.table_name => {site_id: Site.current || Site.default}).joins(page: 'language') }
111
- scope :folded, -> { where(folded: true) }
112
- scope :expanded, -> { where(folded: false) }
113
- scope :not_nested, -> { where(parent_element_id: nil) }
103
+ scope :trashed, -> { where(position: nil).order("updated_at DESC") }
104
+ scope :not_trashed, -> { where.not(position: nil) }
105
+ scope :published, -> { where(public: true) }
106
+ scope :not_restricted, -> { joins(:page).merge(Page.not_restricted) }
107
+ scope :available, -> { published.not_trashed }
108
+ scope :named, ->(names) { where(name: names) }
109
+ scope :excluded, ->(names) { where.not(name: names) }
110
+ scope :fixed, -> { where(fixed: true) }
111
+ scope :unfixed, -> { where(fixed: false) }
112
+ scope :from_current_site, -> { where(Language.table_name => { site_id: Site.current || Site.default }).joins(page: "language") }
113
+ scope :folded, -> { where(folded: true) }
114
+ scope :expanded, -> { where(folded: false) }
115
+ scope :not_nested, -> { where(parent_element_id: nil) }
114
116
 
115
117
  delegate :restricted?, to: :page, allow_nil: true
116
118
 
@@ -131,7 +133,8 @@ module Alchemy
131
133
  #
132
134
  def new(attributes = {})
133
135
  return super if attributes[:name].blank?
134
- element_attributes = attributes.to_h.merge(name: attributes[:name].split('#').first)
136
+
137
+ element_attributes = attributes.to_h.merge(name: attributes[:name].split("#").first)
135
138
  element_definition = Element.definition_by_name(element_attributes[:name])
136
139
  if element_definition.nil?
137
140
  raise(ElementDefinitionError, attributes)
@@ -139,11 +142,6 @@ module Alchemy
139
142
 
140
143
  super(element_definition.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
141
144
  end
142
- alias_method :new_from_scratch, :new
143
- deprecate new_from_scratch: :new, deprecator: Alchemy::Deprecation
144
-
145
- alias_method :create_from_scratch, :create
146
- deprecate create_from_scratch: :create, deprecator: Alchemy::Deprecation
147
145
 
148
146
  # This methods does a copy of source and all depending contents and all of their depending essences.
149
147
  #
@@ -158,13 +156,13 @@ module Alchemy
158
156
  #
159
157
  def copy(source_element, differences = {})
160
158
  attributes = source_element.attributes.with_indifferent_access
161
- .except(*SKIPPED_ATTRIBUTES_ON_COPY)
162
- .merge(differences)
163
- .merge({
164
- autogenerate_contents: false,
165
- autogenerate_nested_elements: false,
166
- tag_list: source_element.tag_list
167
- })
159
+ .except(*SKIPPED_ATTRIBUTES_ON_COPY)
160
+ .merge(differences)
161
+ .merge({
162
+ autogenerate_contents: false,
163
+ autogenerate_nested_elements: false,
164
+ tag_list: source_element.tag_list,
165
+ })
168
166
 
169
167
  new_element = create!(attributes)
170
168
 
@@ -181,13 +179,15 @@ module Alchemy
181
179
 
182
180
  def all_from_clipboard(clipboard)
183
181
  return [] if clipboard.nil?
184
- where(id: clipboard.collect { |e| e['id'] })
182
+
183
+ where(id: clipboard.collect { |e| e["id"] })
185
184
  end
186
185
 
187
186
  # All elements in clipboard that could be placed on page
188
187
  #
189
188
  def all_from_clipboard_for_page(clipboard, page)
190
189
  return [] if clipboard.nil? || page.nil?
190
+
191
191
  all_from_clipboard(clipboard).select { |ce|
192
192
  page.available_element_names.include?(ce.name)
193
193
  }
@@ -199,7 +199,7 @@ module Alchemy
199
199
  # Pass an element name to get next of this kind.
200
200
  #
201
201
  def next(name = nil)
202
- elements = page.elements.published.where('position > ?', position)
202
+ elements = page.elements.published.where("position > ?", position)
203
203
  select_element(elements, name, :asc)
204
204
  end
205
205
 
@@ -208,13 +208,14 @@ module Alchemy
208
208
  # Pass an element name to get previous of this kind.
209
209
  #
210
210
  def prev(name = nil)
211
- elements = page.elements.published.where('position < ?', position)
211
+ elements = page.elements.published.where("position < ?", position)
212
212
  select_element(elements, name, :desc)
213
213
  end
214
214
 
215
215
  # Stores the page into +touchable_pages+ (Pages that have to be touched after updating the element).
216
216
  def store_page(page)
217
217
  return true if page.nil?
218
+
218
219
  unless touchable_pages.include? page
219
220
  touchable_pages << page
220
221
  end
@@ -233,7 +234,7 @@ module Alchemy
233
234
 
234
235
  # Returns true if the definition of this element has a taggable true value.
235
236
  def taggable?
236
- definition['taggable'] == true
237
+ definition["taggable"] == true
237
238
  end
238
239
 
239
240
  # The opposite of folded?
@@ -243,7 +244,7 @@ module Alchemy
243
244
 
244
245
  # Defined as compact element?
245
246
  def compact?
246
- definition['compact'] == true
247
+ definition["compact"] == true
247
248
  end
248
249
 
249
250
  # The element's view partial is dependent from its name
@@ -261,17 +262,7 @@ module Alchemy
261
262
  # Element partials live in +app/views/alchemy/elements+
262
263
  #
263
264
  def to_partial_path
264
- if Alchemy::LOOKUP_CONTEXT.exists?("#{name}_view", ["elements"], true)
265
- Alchemy::Deprecation.warn <<~WARN
266
- Having the `_view` suffix on your element view partials is deprecated
267
- and will not be supported in Alchemy 5.0 anymore. You can safely remove the suffix now.
268
-
269
- Please also rename the local `element` or `#{name}_view` variable into `#{name}`.
270
- WARN
271
- "alchemy/elements/#{name}_view"
272
- else
273
- "alchemy/elements/#{name}"
274
- end
265
+ "alchemy/elements/#{name}"
275
266
  end
276
267
 
277
268
  # Returns the key that's taken for cache path.
@@ -290,7 +281,7 @@ module Alchemy
290
281
 
291
282
  # A collection of element names that can be nested inside this element.
292
283
  def nestable_elements
293
- definition.fetch('nestable_elements', [])
284
+ definition.fetch("nestable_elements", [])
294
285
  end
295
286
 
296
287
  # Copy all nested elements from current element to given target element.
@@ -298,7 +289,7 @@ module Alchemy
298
289
  nested_elements.map do |nested_element|
299
290
  Element.copy(nested_element, {
300
291
  parent_element_id: target_element.id,
301
- page_id: target_element.page_id
292
+ page_id: target_element.page_id,
302
293
  })
303
294
  end
304
295
  end
@@ -306,7 +297,7 @@ module Alchemy
306
297
  private
307
298
 
308
299
  def generate_nested_elements
309
- definition.fetch('autogenerate', []).each do |nestable_element|
300
+ definition.fetch("autogenerate", []).each do |nestable_element|
310
301
  if nestable_elements.include?(nestable_element)
311
302
  Element.create(page: page, parent_element_id: id, name: nestable_element)
312
303
  else
@@ -326,6 +317,7 @@ module Alchemy
326
317
  #
327
318
  def touch_touchable_pages
328
319
  return unless respond_to?(:touchable_pages)
320
+
329
321
  touchable_pages.each(&:touch)
330
322
  end
331
323
  end
@@ -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