alchemy_cms 4.6.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (386) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +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