alchemy_cms 4.6.7 → 5.0.0.beta1

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 (384) 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 +31 -10
  8. data/CHANGELOG.md +89 -32
  9. data/Gemfile +24 -22
  10. data/README.md +31 -19
  11. data/Rakefile +10 -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/node-select.scss +43 -0
  25. data/app/assets/stylesheets/alchemy/nodes.scss +1 -1
  26. data/app/assets/stylesheets/alchemy/sitemap.scss +5 -1
  27. data/app/assets/stylesheets/alchemy/tables.scss +1 -24
  28. data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +3 -3
  29. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +7 -7
  30. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -7
  31. data/app/controllers/alchemy/admin/base_controller.rb +16 -42
  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 +50 -62
  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 +36 -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 +3 -3
  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 +2 -1
  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 +21 -19
  81. data/app/models/alchemy/base_record.rb +2 -5
  82. data/app/models/alchemy/content/factory.rb +24 -31
  83. data/app/models/alchemy/content.rb +33 -38
  84. data/app/models/alchemy/element/definitions.rb +4 -4
  85. data/app/models/alchemy/element/element_contents.rb +9 -6
  86. data/app/models/alchemy/element/element_essences.rb +4 -3
  87. data/app/models/alchemy/element/presenters.rb +3 -2
  88. data/app/models/alchemy/element.rb +46 -54
  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 +4 -4
  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 +17 -16
  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/code.rb +4 -4
  104. data/app/models/alchemy/language.rb +21 -35
  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 +28 -5
  108. data/app/models/alchemy/page/fixed_attributes.rb +3 -2
  109. data/app/models/alchemy/page/page_elements.rb +35 -44
  110. data/app/models/alchemy/page/page_naming.rb +20 -70
  111. data/app/models/alchemy/page/page_natures.rb +7 -34
  112. data/app/models/alchemy/page/page_scopes.rb +23 -29
  113. data/app/models/alchemy/page/url_path.rb +0 -2
  114. data/app/models/alchemy/page.rb +47 -128
  115. data/app/models/alchemy/picture/transformations.rb +9 -7
  116. data/app/models/alchemy/picture/url.rb +5 -5
  117. data/app/models/alchemy/picture.rb +19 -28
  118. data/app/models/alchemy/site/layout.rb +2 -2
  119. data/app/models/alchemy/site.rb +6 -36
  120. data/app/models/concerns/alchemy/touch_elements.rb +24 -0
  121. data/app/serializers/alchemy/content_serializer.rb +0 -3
  122. data/app/serializers/alchemy/essence_boolean_serializer.rb +3 -3
  123. data/app/serializers/alchemy/essence_date_serializer.rb +3 -3
  124. data/app/serializers/alchemy/essence_file_serializer.rb +4 -2
  125. data/app/serializers/alchemy/essence_html_serializer.rb +3 -3
  126. data/app/serializers/alchemy/essence_link_serializer.rb +3 -3
  127. data/app/serializers/alchemy/essence_picture_serializer.rb +5 -4
  128. data/app/serializers/alchemy/essence_richtext_serializer.rb +3 -3
  129. data/app/serializers/alchemy/essence_select_serializer.rb +3 -3
  130. data/app/serializers/alchemy/essence_text_serializer.rb +5 -4
  131. data/app/serializers/alchemy/node_serializer.rb +2 -0
  132. data/app/serializers/alchemy/page_tree_serializer.rb +9 -13
  133. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -2
  134. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +1 -2
  135. data/app/views/alchemy/admin/attachments/_files_list.html.erb +4 -4
  136. data/app/views/alchemy/admin/contents/create.js.erb +1 -3
  137. data/app/views/alchemy/admin/elements/_element.html.erb +9 -18
  138. data/app/views/alchemy/admin/elements/create.js.erb +1 -1
  139. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  140. data/app/views/alchemy/admin/elements/index.html.erb +3 -3
  141. data/app/views/alchemy/admin/essence_files/assign.js.erb +1 -6
  142. data/app/views/alchemy/admin/essence_files/edit.html.erb +1 -1
  143. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +1 -7
  144. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
  145. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +7 -7
  146. data/app/views/alchemy/admin/essence_pictures/update.js.erb +1 -1
  147. data/app/views/alchemy/admin/languages/_form.html.erb +5 -5
  148. data/app/views/alchemy/admin/languages/_table.html.erb +3 -3
  149. data/app/views/alchemy/admin/languages/edit.html.erb +1 -0
  150. data/app/views/alchemy/admin/languages/index.html.erb +23 -4
  151. data/app/views/alchemy/admin/languages/new.html.erb +1 -0
  152. data/app/views/alchemy/admin/layoutpages/index.html.erb +3 -3
  153. data/app/views/alchemy/admin/nodes/_form.html.erb +18 -15
  154. data/app/views/alchemy/admin/nodes/_node.html.erb +1 -5
  155. data/app/views/alchemy/admin/nodes/index.html.erb +3 -4
  156. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +0 -8
  157. data/app/views/alchemy/admin/pages/_form.html.erb +0 -1
  158. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -0
  159. data/app/views/alchemy/admin/pages/_page.html.erb +11 -19
  160. data/app/views/alchemy/admin/pages/_page_infos.html.erb +0 -4
  161. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  162. data/app/views/alchemy/admin/pages/info.html.erb +0 -9
  163. data/app/views/alchemy/admin/pages/unlock.js.erb +13 -6
  164. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +0 -2
  165. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -5
  166. data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +1 -1
  167. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -2
  168. data/app/views/alchemy/admin/resources/_resource.html.erb +1 -1
  169. data/app/views/alchemy/admin/resources/_table.html.erb +2 -2
  170. data/app/views/alchemy/admin/sites/_form.html.erb +8 -0
  171. data/app/views/alchemy/admin/sites/edit.html.erb +1 -0
  172. data/app/views/alchemy/admin/sites/index.html.erb +21 -9
  173. data/app/views/alchemy/admin/sites/new.html.erb +1 -0
  174. data/app/views/alchemy/admin/tags/index.html.erb +2 -2
  175. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +10 -12
  176. data/app/views/alchemy/essences/_essence_date_editor.html.erb +11 -8
  177. data/app/views/alchemy/essences/_essence_file_editor.html.erb +16 -17
  178. data/app/views/alchemy/essences/_essence_html_editor.html.erb +8 -5
  179. data/app/views/alchemy/essences/_essence_link_editor.html.erb +18 -15
  180. data/app/views/alchemy/essences/_essence_node_editor.html.erb +27 -0
  181. data/app/views/alchemy/essences/_essence_node_view.html.erb +1 -0
  182. data/app/views/alchemy/essences/_essence_page_editor.html.erb +14 -11
  183. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +22 -20
  184. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +10 -7
  185. data/app/views/alchemy/essences/_essence_select_editor.html.erb +12 -16
  186. data/app/views/alchemy/essences/_essence_text_editor.html.erb +18 -17
  187. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +6 -11
  188. data/app/views/alchemy/pages/show.rss.builder +3 -2
  189. data/app/views/layouts/alchemy/admin.html.erb +1 -0
  190. data/babel.config.js +12 -0
  191. data/bin/rails +5 -4
  192. data/config/alchemy/config.yml +15 -18
  193. data/config/brakeman.ignore +1 -1
  194. data/config/initializers/assets.rb +2 -1
  195. data/config/initializers/dragonfly.rb +2 -1
  196. data/config/initializers/mime_types.rb +1 -0
  197. data/config/initializers/mini_profiler.rb +3 -2
  198. data/config/initializers/simple_form.rb +6 -6
  199. data/config/locales/alchemy.en.yml +23 -8
  200. data/config/routes.rb +25 -24
  201. data/config/spring.rb +3 -2
  202. data/db/migrate/20200226213334_alchemy_four_point_four.rb +313 -0
  203. data/db/migrate/20200423073425_create_alchemy_essence_nodes.rb +11 -0
  204. data/db/migrate/20200504210159_remove_site_id_from_nodes.rb +28 -0
  205. data/db/migrate/20200505215518_add_language_id_foreign_key_to_alchemy_pages.rb +8 -0
  206. data/db/migrate/20200511113603_add_menu_type_to_alchemy_nodes.rb +27 -0
  207. data/db/migrate/20200514091507_make_page_layoutpage_null_false.rb +6 -0
  208. data/db/migrate/20200519073500_remove_visible_from_alchemy_pages.rb +24 -0
  209. data/lib/alchemy/admin/locale.rb +3 -1
  210. data/lib/alchemy/admin/preview_url.rb +64 -0
  211. data/lib/alchemy/auth_accessors.rb +8 -7
  212. data/lib/alchemy/cache_digests/template_tracker.rb +5 -4
  213. data/lib/alchemy/config.rb +1 -5
  214. data/lib/alchemy/configuration_methods.rb +3 -1
  215. data/lib/alchemy/controller_actions.rb +6 -5
  216. data/lib/alchemy/deprecation.rb +2 -1
  217. data/lib/alchemy/elements_finder.rb +5 -5
  218. data/lib/alchemy/engine.rb +22 -14
  219. data/lib/alchemy/errors.rb +0 -7
  220. data/lib/alchemy/essence.rb +17 -16
  221. data/lib/alchemy/filetypes.rb +5 -5
  222. data/lib/alchemy/forms/builder.rb +4 -4
  223. data/lib/alchemy/hints.rb +1 -1
  224. data/lib/alchemy/i18n.rb +2 -1
  225. data/lib/alchemy/modules.rb +12 -12
  226. data/lib/alchemy/name_conversions.rb +5 -5
  227. data/lib/alchemy/on_page_layout/callbacks_runner.rb +1 -0
  228. data/lib/alchemy/page_layout.rb +15 -12
  229. data/lib/alchemy/paths.rb +1 -1
  230. data/lib/alchemy/permissions.rb +7 -6
  231. data/lib/alchemy/resource.rb +25 -17
  232. data/lib/alchemy/resources_helper.rb +12 -18
  233. data/lib/alchemy/routing_constraints.rb +1 -1
  234. data/lib/alchemy/seeder.rb +42 -14
  235. data/lib/alchemy/shell.rb +13 -10
  236. data/lib/alchemy/taggable.rb +1 -0
  237. data/lib/alchemy/tasks/tidy.rb +4 -3
  238. data/lib/alchemy/test_support/config_stubbing.rb +1 -0
  239. data/lib/alchemy/test_support/essence_shared_examples.rb +72 -72
  240. data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -5
  241. data/lib/alchemy/test_support/factories/content_factory.rb +6 -6
  242. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +7 -7
  243. data/lib/alchemy/test_support/factories/element_factory.rb +9 -9
  244. data/lib/alchemy/test_support/factories/essence_file_factory.rb +3 -3
  245. data/lib/alchemy/test_support/factories/essence_page_factory.rb +3 -3
  246. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +4 -4
  247. data/lib/alchemy/test_support/factories/essence_text_factory.rb +3 -3
  248. data/lib/alchemy/test_support/factories/language_factory.rb +16 -14
  249. data/lib/alchemy/test_support/factories/node_factory.rb +8 -8
  250. data/lib/alchemy/test_support/factories/page_factory.rb +15 -27
  251. data/lib/alchemy/test_support/factories/picture_factory.rb +5 -5
  252. data/lib/alchemy/test_support/factories/site_factory.rb +7 -6
  253. data/lib/alchemy/test_support/factories.rb +1 -1
  254. data/lib/alchemy/test_support/integration_helpers.rb +1 -0
  255. data/lib/alchemy/test_support/shared_contexts.rb +5 -4
  256. data/lib/alchemy/test_support/shared_uploader_examples.rb +4 -3
  257. data/lib/alchemy/tinymce.rb +15 -13
  258. data/lib/alchemy/upgrader/five_point_zero.rb +41 -0
  259. data/lib/alchemy/upgrader/tasks/element_views_updater.rb +4 -4
  260. data/lib/alchemy/upgrader/tasks/harden_gutentag_migrations.rb +29 -0
  261. data/lib/alchemy/upgrader.rb +8 -7
  262. data/lib/alchemy/userstamp.rb +1 -1
  263. data/lib/alchemy/version.rb +1 -1
  264. data/lib/alchemy_cms.rb +52 -51
  265. data/lib/{rails/generators → generators}/alchemy/base.rb +5 -4
  266. data/lib/{rails/generators → generators}/alchemy/elements/elements_generator.rb +13 -9
  267. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.erb +0 -0
  268. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.haml +0 -0
  269. data/lib/{rails/generators → generators}/alchemy/elements/templates/view.html.slim +0 -0
  270. data/lib/{rails/generators → generators}/alchemy/essence/essence_generator.rb +15 -13
  271. data/lib/generators/alchemy/essence/templates/editor.html.erb +17 -0
  272. data/lib/{rails/generators → generators}/alchemy/essence/templates/view.html.erb +0 -0
  273. data/lib/{rails/generators → generators}/alchemy/install/files/_article.html.erb +0 -0
  274. data/lib/{rails/generators → generators}/alchemy/install/files/_standard.html.erb +0 -0
  275. data/lib/{rails/generators → generators}/alchemy/install/files/alchemy.en.yml +0 -0
  276. data/lib/generators/alchemy/install/files/alchemy_admin.js +1 -0
  277. data/lib/{rails/generators → generators}/alchemy/install/files/all.css +0 -0
  278. data/lib/{rails/generators → generators}/alchemy/install/files/all.js +0 -0
  279. data/lib/{rails/generators → generators}/alchemy/install/files/application.html.erb +0 -0
  280. data/lib/{rails/generators → generators}/alchemy/install/files/article.scss +0 -0
  281. data/lib/generators/alchemy/install/install_generator.rb +110 -0
  282. data/lib/{rails/generators → generators}/alchemy/install/templates/dragonfly.rb.tt +0 -0
  283. data/lib/{rails/generators → generators}/alchemy/install/templates/elements.yml.tt +0 -0
  284. data/lib/{rails/generators → generators}/alchemy/install/templates/menus.yml.tt +0 -0
  285. data/lib/{rails/generators → generators}/alchemy/install/templates/page_layouts.yml.tt +0 -0
  286. data/lib/{rails/generators → generators}/alchemy/menus/menus_generator.rb +2 -2
  287. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.erb +1 -4
  288. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.haml +1 -4
  289. data/lib/{rails/generators → generators}/alchemy/menus/templates/node.html.slim +1 -4
  290. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.erb +1 -1
  291. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.haml +1 -1
  292. data/lib/{rails/generators → generators}/alchemy/menus/templates/wrapper.html.slim +1 -1
  293. data/lib/{rails/generators → generators}/alchemy/module/module_generator.rb +3 -2
  294. data/lib/{rails/generators → generators}/alchemy/module/templates/ability.rb.tt +0 -0
  295. data/lib/{rails/generators → generators}/alchemy/module/templates/controller.rb.tt +0 -0
  296. data/lib/{rails/generators → generators}/alchemy/module/templates/module_config.rb.tt +0 -0
  297. data/lib/{rails/generators → generators}/alchemy/page_layouts/page_layouts_generator.rb +5 -4
  298. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.erb +0 -0
  299. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.haml +0 -0
  300. data/lib/{rails/generators → generators}/alchemy/page_layouts/templates/layout.html.slim +0 -0
  301. data/lib/{rails/generators → generators}/alchemy/site_layouts/site_layouts_generator.rb +4 -2
  302. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.erb +0 -0
  303. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.haml +0 -0
  304. data/lib/{rails/generators → generators}/alchemy/site_layouts/templates/layout.html.slim +0 -0
  305. data/lib/{rails/generators → generators}/alchemy/views/views_generator.rb +7 -6
  306. data/lib/kaminari/scoped_pagination_url_helper.rb +1 -0
  307. data/lib/tasks/alchemy/db.rake +3 -19
  308. data/lib/tasks/alchemy/install.rake +3 -2
  309. data/lib/tasks/alchemy/tidy.rake +9 -8
  310. data/lib/tasks/alchemy/upgrade.rake +18 -120
  311. data/package/admin.js +14 -0
  312. data/package/src/__tests__/i18n.spec.js +70 -0
  313. data/package/src/i18n.js +48 -0
  314. data/package/src/node_tree.js +72 -0
  315. data/package/src/translations.js +32 -0
  316. data/package/src/utils/__tests__/ajax.spec.js +124 -0
  317. data/package/src/utils/__tests__/events.spec.js +38 -0
  318. data/package/src/utils/ajax.js +48 -0
  319. data/package/src/utils/events.js +16 -0
  320. data/package.json +45 -0
  321. data/vendor/assets/fonts/fa-regular-400.eot +0 -0
  322. data/vendor/assets/fonts/fa-regular-400.svg +798 -358
  323. data/vendor/assets/fonts/fa-regular-400.ttf +0 -0
  324. data/vendor/assets/fonts/fa-regular-400.woff +0 -0
  325. data/vendor/assets/fonts/fa-regular-400.woff2 +0 -0
  326. data/vendor/assets/fonts/fa-solid-900.eot +0 -0
  327. data/vendor/assets/fonts/fa-solid-900.svg +4933 -1408
  328. data/vendor/assets/fonts/fa-solid-900.ttf +0 -0
  329. data/vendor/assets/fonts/fa-solid-900.woff +0 -0
  330. data/vendor/assets/fonts/fa-solid-900.woff2 +0 -0
  331. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +1 -2
  332. data/vendor/assets/stylesheets/fontawesome/_core.scss +5 -0
  333. data/vendor/assets/stylesheets/fontawesome/_fixed-width.scss +1 -1
  334. data/vendor/assets/stylesheets/fontawesome/_icons.scss +651 -2
  335. data/vendor/assets/stylesheets/fontawesome/_mixins.scss +0 -1
  336. data/vendor/assets/stylesheets/fontawesome/_rotated-flipped.scss +3 -2
  337. data/vendor/assets/stylesheets/fontawesome/_stacked.scss +1 -1
  338. data/vendor/assets/stylesheets/fontawesome/_variables.scss +662 -9
  339. data/vendor/assets/stylesheets/fontawesome/fontawesome.scss +2 -2
  340. data/vendor/assets/stylesheets/fontawesome/regular.scss +23 -0
  341. data/vendor/assets/stylesheets/fontawesome/solid.scss +24 -0
  342. metadata +117 -98
  343. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +0 -32
  344. data/app/assets/javascripts/alchemy/alchemy.node_tree.js +0 -66
  345. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +0 -29
  346. data/app/assets/javascripts/alchemy/alchemy.utils.js +0 -45
  347. data/app/helpers/alchemy/essences_helper.rb +0 -119
  348. data/app/models/concerns/alchemy/content_touching.rb +0 -23
  349. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -15
  350. data/app/views/alchemy/admin/contents/_missing.html.erb +0 -17
  351. data/app/views/alchemy/admin/pages/_menu_fields.html.erb +0 -37
  352. data/app/views/alchemy/admin/pages/configure_external.html.erb +0 -32
  353. data/app/views/alchemy/elements/_editor_not_found.html.erb +0 -4
  354. data/app/views/alchemy/navigation/_image_link.html.erb +0 -14
  355. data/app/views/alchemy/navigation/_link.html.erb +0 -19
  356. data/app/views/alchemy/navigation/_renderer.html.erb +0 -29
  357. data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -363
  358. data/db/migrate/20180227224537_migrate_tags_to_gutentag.rb +0 -41
  359. data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +0 -6
  360. data/db/migrate/20191016073858_create_alchemy_essence_pages.rb +0 -8
  361. data/db/migrate/20191029212236_create_alchemy_nodes.rb +0 -24
  362. data/db/migrate/20200226081535_add_site_id_to_alchemy_nodes.rb +0 -15
  363. data/lib/alchemy/error_tracking/airbrake_handler.rb +0 -13
  364. data/lib/alchemy/error_tracking.rb +0 -14
  365. data/lib/alchemy/ssl_protection.rb +0 -34
  366. data/lib/alchemy/tasks/helpers.rb +0 -81
  367. data/lib/alchemy/test_support/controller_requests.rb +0 -93
  368. data/lib/alchemy/upgrader/four_point_four.rb +0 -52
  369. data/lib/alchemy/upgrader/four_point_one.rb +0 -42
  370. data/lib/alchemy/upgrader/four_point_six.rb +0 -50
  371. data/lib/alchemy/upgrader/four_point_two.rb +0 -86
  372. data/lib/alchemy/upgrader/tasks/cells_migration.rb +0 -45
  373. data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +0 -166
  374. data/lib/alchemy/upgrader/tasks/element_partial_name_variable_updater.rb +0 -32
  375. data/lib/alchemy/upgrader/tasks/fixed_element_name_finder.rb +0 -31
  376. data/lib/alchemy/upgrader/tasks/harden_acts_as_taggable_on_migrations.rb +0 -27
  377. data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +0 -65
  378. data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +0 -210
  379. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +0 -15
  380. data/lib/rails/generators/alchemy/install/install_generator.rb +0 -60
  381. data/lib/tasks/alchemy/convert.rake +0 -98
  382. data/vendor/assets/javascripts/sortable/Sortable.min.js +0 -2
  383. data/vendor/assets/stylesheets/fontawesome/fa-regular.scss +0 -22
  384. data/vendor/assets/stylesheets/fontawesome/fa-solid.scss +0 -23
@@ -17,7 +17,6 @@
17
17
  # rgt :integer
18
18
  # parent_id :integer
19
19
  # depth :integer
20
- # visible :boolean default(FALSE)
21
20
  # locked_by :integer
22
21
  # restricted :boolean default(FALSE)
23
22
  # robot_index :boolean default(TRUE)
@@ -44,11 +43,10 @@ module Alchemy
44
43
 
45
44
  DEFAULT_ATTRIBUTES_FOR_COPY = {
46
45
  autogenerate_elements: false,
47
- visible: false,
48
46
  public_on: nil,
49
47
  public_until: nil,
50
48
  locked_at: nil,
51
- locked_by: nil
49
+ locked_by: nil,
52
50
  }
53
51
 
54
52
  SKIPPED_ATTRIBUTES_ON_COPY = %w(
@@ -78,16 +76,15 @@ module Alchemy
78
76
  :tag_list,
79
77
  :title,
80
78
  :urlname,
81
- :visible,
82
79
  :layoutpage,
83
- :menu_id
80
+ :menu_id,
84
81
  ]
85
82
 
86
- acts_as_nested_set(dependent: :destroy)
83
+ acts_as_nested_set(dependent: :destroy, scope: [:layoutpage, :language_id])
87
84
 
88
- stampable stamper_class_name: Alchemy.user_class.name
85
+ stampable stamper_class_name: Alchemy.user_class_name
89
86
 
90
- belongs_to :language, optional: true
87
+ belongs_to :language
91
88
 
92
89
  belongs_to :creator,
93
90
  primary_key: Alchemy.user_class_primary_key,
@@ -110,43 +107,33 @@ module Alchemy
110
107
  has_one :site, through: :language
111
108
  has_many :site_languages, through: :site, source: :languages
112
109
  has_many :folded_pages
113
- has_many :legacy_urls, class_name: 'Alchemy::LegacyPageUrl'
114
- has_many :nodes, class_name: 'Alchemy::Node', inverse_of: :page
110
+ has_many :legacy_urls, class_name: "Alchemy::LegacyPageUrl"
111
+ has_many :nodes, class_name: "Alchemy::Node", inverse_of: :page
115
112
 
116
- validates_presence_of :language, on: :create, unless: :root
117
- validates_presence_of :page_layout, unless: :systempage?
118
- validates_format_of :page_layout, with: /\A[a-z0-9_-]+\z/, unless: -> { systempage? || page_layout.blank? }
119
- validates_presence_of :parent_id, if: proc { Page.count > 1 }
113
+ before_validation :set_language,
114
+ if: -> { language.nil? }
115
+
116
+ validates_presence_of :page_layout
117
+ validates_format_of :page_layout, with: /\A[a-z0-9_-]+\z/, unless: -> { page_layout.blank? }
118
+ validates_presence_of :parent, unless: -> { layoutpage? || language_root? }
120
119
 
121
120
  before_save :set_language_code,
122
- if: -> { language.present? },
123
- unless: :systempage?
121
+ if: -> { language.present? }
124
122
 
125
123
  before_save :set_restrictions_to_child_pages,
126
- if: :restricted_changed?,
127
- unless: :systempage?
124
+ if: :restricted_changed?
128
125
 
129
126
  before_save :inherit_restricted_status,
130
- if: -> { parent && parent.restricted? },
131
- unless: :systempage?
127
+ if: -> { parent && parent.restricted? }
132
128
 
133
129
  before_save :set_published_at,
134
- if: -> { public_on.present? && published_at.nil? },
135
- unless: :systempage?
130
+ if: -> { public_on.present? && published_at.nil? }
136
131
 
137
132
  before_save :set_fixed_attributes,
138
133
  if: -> { fixed_attributes.any? }
139
134
 
140
- before_create :set_language_from_parent_or_default,
141
- if: -> { language_id.blank? },
142
- unless: :systempage?
143
-
144
135
  after_update :create_legacy_url,
145
- if: :should_create_legacy_url?,
146
- unless: -> { definition['redirects_to_external'] }
147
-
148
- after_update :attach_to_menu!,
149
- if: :should_attach_to_menu?
136
+ if: :saved_change_to_urlname?
150
137
 
151
138
  after_update -> { nodes.update_all(updated_at: Time.current) }
152
139
 
@@ -159,26 +146,9 @@ module Alchemy
159
146
  # site_name accessor
160
147
  delegate :name, to: :site, prefix: true, allow_nil: true
161
148
 
162
- attr_accessor :menu_id
163
-
164
- deprecate visible: "Page slugs will be visible in URLs of child pages all the time. " \
165
- "Please use Menus and Tags instead to re-organize your pages if your page tree does not reflect the URL hierarchy.",
166
- deprecator: Alchemy::Deprecation
167
-
168
149
  # Class methods
169
150
  #
170
151
  class << self
171
- # The root page of the page tree
172
- #
173
- # Internal use only. You wouldn't use this page ever.
174
- #
175
- # Automatically created when accessed the first time.
176
- #
177
- def root
178
- super || create!(name: 'Root')
179
- end
180
- alias_method :rootpage, :root
181
-
182
152
  # Used to store the current page previewed in the edit page template.
183
153
  #
184
154
  def current_preview=(page)
@@ -222,29 +192,12 @@ module Alchemy
222
192
  end
223
193
  end
224
194
 
225
- def layout_root_for(language_id)
226
- where({parent_id: Page.root.id, layoutpage: true, language_id: language_id}).limit(1).first
227
- end
228
-
229
- def find_or_create_layout_root_for(language_id)
230
- layoutroot = layout_root_for(language_id)
231
- return layoutroot if layoutroot
232
- language = Language.find(language_id)
233
- Page.create!(
234
- name: "Layoutroot for #{language.name}",
235
- layoutpage: true,
236
- language: language,
237
- autogenerate_elements: false,
238
- parent_id: Page.root.id
239
- )
240
- end
241
-
242
195
  def copy_and_paste(source, new_parent, new_name)
243
196
  page = copy(source, {
244
197
  parent_id: new_parent.id,
245
198
  language: new_parent.language,
246
199
  name: new_name,
247
- title: new_name
200
+ title: new_name,
248
201
  })
249
202
  if source.children.any?
250
203
  source.copy_children_to(page)
@@ -254,34 +207,29 @@ module Alchemy
254
207
 
255
208
  def all_from_clipboard(clipboard)
256
209
  return [] if clipboard.blank?
257
- where(id: clipboard.collect { |p| p['id'] })
210
+
211
+ where(id: clipboard.collect { |p| p["id"] })
258
212
  end
259
213
 
260
214
  def all_from_clipboard_for_select(clipboard, language_id, layoutpage = false)
261
215
  return [] if clipboard.blank?
216
+
262
217
  clipboard_pages = all_from_clipboard(clipboard)
263
218
  allowed_page_layouts = Alchemy::PageLayout.selectable_layouts(language_id, layoutpage)
264
- allowed_page_layout_names = allowed_page_layouts.collect { |p| p['name'] }
219
+ allowed_page_layout_names = allowed_page_layouts.collect { |p| p["name"] }
265
220
  clipboard_pages.select { |cp| allowed_page_layout_names.include?(cp.page_layout) }
266
221
  end
267
222
 
268
223
  def link_target_options
269
- options = [[Alchemy.t(:default, scope: 'link_target_options'), '']]
224
+ options = [[Alchemy.t(:default, scope: "link_target_options"), ""]]
270
225
  link_target_options = Config.get(:link_target_options)
271
226
  link_target_options.each do |option|
272
- options << [Alchemy.t(option, scope: 'link_target_options',
273
- default: option.to_s.humanize), option]
227
+ options << [Alchemy.t(option, scope: "link_target_options",
228
+ default: option.to_s.humanize), option]
274
229
  end
275
230
  options
276
231
  end
277
232
 
278
- # Returns an array of all pages in the same branch from current.
279
- # I.e. used to find the active page in navigation.
280
- def ancestors_for(current)
281
- return [] if current.nil?
282
- current.self_and_ancestors.contentpages
283
- end
284
-
285
233
  private
286
234
 
287
235
  # Aggregates the attributes from given source for copy of page.
@@ -296,7 +244,7 @@ module Alchemy
296
244
  differences.stringify_keys!
297
245
  attributes = source.attributes.merge(differences)
298
246
  attributes.merge!(DEFAULT_ATTRIBUTES_FOR_COPY)
299
- attributes['name'] = new_name_for_copy(differences['name'], source.name)
247
+ attributes["name"] = new_name_for_copy(differences["name"], source.name)
300
248
  attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY)
301
249
  end
302
250
 
@@ -312,7 +260,8 @@ module Alchemy
312
260
  #
313
261
  def new_name_for_copy(custom_name, source_name)
314
262
  return custom_name if custom_name.present?
315
- "#{source_name} (#{Alchemy.t('Copy')})"
263
+
264
+ "#{source_name} (#{Alchemy.t("Copy")})"
316
265
  end
317
266
  end
318
267
 
@@ -340,13 +289,7 @@ module Alchemy
340
289
  # Use this for your custom element loading logic.
341
290
  #
342
291
  # @return [ActiveRecord::Relation]
343
- def find_elements(options = {}, show_non_public = false)
344
- if show_non_public
345
- Alchemy::Deprecation.warn "Passing true as second argument to page#find_elements to include" \
346
- " invisible elements has been removed. Please implement your own ElementsFinder" \
347
- " and pass it with options[:finder]."
348
- end
349
-
292
+ def find_elements(options = {})
350
293
  finder = options[:finder] || Alchemy::ElementsFinder.new(options)
351
294
  finder.elements(page: self)
352
295
  end
@@ -384,9 +327,10 @@ module Alchemy
384
327
  # only public pages (true), skip public pages (false)
385
328
  #
386
329
  def previous(options = {})
387
- pages = self_and_siblings.where('lft < ?', lft)
330
+ pages = self_and_siblings.where("lft < ?", lft)
388
331
  select_page(pages, options.merge(order: :desc))
389
332
  end
333
+
390
334
  alias_method :previous_page, :previous
391
335
 
392
336
  # Returns the next page on the same level or nil.
@@ -397,9 +341,10 @@ module Alchemy
397
341
  # only public pages (true), skip public pages (false)
398
342
  #
399
343
  def next(options = {})
400
- pages = self_and_siblings.where('lft > ?', lft)
344
+ pages = self_and_siblings.where("lft > ?", lft)
401
345
  select_page(pages, options.merge(order: :asc))
402
346
  end
347
+
403
348
  alias_method :next_page, :next
404
349
 
405
350
  # Locks the page to given user
@@ -445,9 +390,10 @@ module Alchemy
445
390
  def copy_children_to(new_parent)
446
391
  children.each do |child|
447
392
  next if child == new_parent
393
+
448
394
  new_child = Page.copy(child, {
449
395
  language_id: new_parent.language_id,
450
- language_code: new_parent.language_code
396
+ language_code: new_parent.language_code,
451
397
  })
452
398
  new_child.move_to_child_of(new_parent)
453
399
  child.copy_children_to(new_child) unless child.children.blank?
@@ -466,22 +412,22 @@ module Alchemy
466
412
  update_columns(
467
413
  published_at: current_time,
468
414
  public_on: already_public_for?(current_time) ? public_on : current_time,
469
- public_until: still_public_for?(current_time) ? public_until : nil
415
+ public_until: still_public_for?(current_time) ? public_until : nil,
470
416
  )
471
417
  end
472
418
 
473
419
  # Updates an Alchemy::Page based on a new ordering to be applied to it
474
420
  #
475
421
  # Note: Page's urls should not be updated (and a legacy URL created) if nesting is OFF
476
- # or if a page is external or if the URL is the same
422
+ # or if the URL is the same
477
423
  #
478
424
  # @param [TreeNode]
479
425
  # A tree node with new lft, rgt, depth, url, parent_id and restricted indexes to be updated
480
426
  #
481
427
  def update_node!(node)
482
- hash = {lft: node.left, rgt: node.right, parent_id: node.parent, depth: node.depth, restricted: node.restricted}
428
+ hash = { lft: node.left, rgt: node.right, parent_id: node.parent, depth: node.depth, restricted: node.restricted }
483
429
 
484
- if Config.get(:url_nesting) && !definition['redirects_to_external'] && urlname != node.url
430
+ if urlname != node.url
485
431
  LegacyPageUrl.create(page_id: id, urlname: urlname)
486
432
  hash[:urlname] = node.url
487
433
  end
@@ -506,6 +452,7 @@ module Alchemy
506
452
  #
507
453
  def editable_by?(user)
508
454
  return true unless has_limited_editors?
455
+
509
456
  (editor_roles & user.alchemy_roles).any?
510
457
  end
511
458
 
@@ -531,7 +478,7 @@ module Alchemy
531
478
  # does not respond to +#name+ it returns +'unknown'+
532
479
  #
533
480
  def creator_name
534
- creator.try(:name) || Alchemy.t('unknown')
481
+ creator.try(:name) || Alchemy.t("unknown")
535
482
  end
536
483
 
537
484
  # Returns the name of the last updater of this page.
@@ -540,7 +487,7 @@ module Alchemy
540
487
  # does not respond to +#name+ it returns +'unknown'+
541
488
  #
542
489
  def updater_name
543
- updater.try(:name) || Alchemy.t('unknown')
490
+ updater.try(:name) || Alchemy.t("unknown")
544
491
  end
545
492
 
546
493
  # Returns the name of the user currently editing this page.
@@ -549,7 +496,7 @@ module Alchemy
549
496
  # does not respond to +#name+ it returns +'unknown'+
550
497
  #
551
498
  def locker_name
552
- locker.try(:name) || Alchemy.t('unknown')
499
+ locker.try(:name) || Alchemy.t("unknown")
553
500
  end
554
501
 
555
502
  # Menus (aka. root nodes) this page is attached to
@@ -573,8 +520,8 @@ module Alchemy
573
520
  .limit(1).first
574
521
  end
575
522
 
576
- def set_language_from_parent_or_default
577
- self.language = parent.language || Language.default
523
+ def set_language
524
+ self.language = parent&.language || Language.current
578
525
  set_language_code
579
526
  end
580
527
 
@@ -582,41 +529,13 @@ module Alchemy
582
529
  self.language_code = language.code
583
530
  end
584
531
 
585
- def should_create_legacy_url?
586
- if active_record_5_1?
587
- saved_change_to_urlname?
588
- else
589
- urlname_changed?
590
- end
591
- end
592
-
593
532
  # Stores the old urlname in a LegacyPageUrl
594
533
  def create_legacy_url
595
- if active_record_5_1?
596
- former_urlname = urlname_before_last_save
597
- else
598
- former_urlname = urlname_was
599
- end
600
- legacy_urls.find_or_create_by(urlname: former_urlname)
534
+ legacy_urls.find_or_create_by(urlname: urlname_before_last_save)
601
535
  end
602
536
 
603
537
  def set_published_at
604
538
  self.published_at = Time.current
605
539
  end
606
-
607
- def attach_to_menu!
608
- current_site_id = Alchemy::Site.current.id
609
- node = Alchemy::Node.find_by!(id: menu_id, site_id: current_site_id)
610
- node.children.create!(
611
- site_id: current_site_id,
612
- language_id: language_id,
613
- page_id: id,
614
- name: name
615
- )
616
- end
617
-
618
- def should_attach_to_menu?
619
- menu_id.present? && nodes.none?
620
- end
621
540
  end
622
541
  end
@@ -49,6 +49,7 @@ module Alchemy
49
49
  #
50
50
  def crop(size, crop_from = nil, crop_size = nil, upsample = false)
51
51
  raise "No size given!" if size.empty?
52
+
52
53
  render_to = sizes_from_string(size)
53
54
  if crop_from && crop_size
54
55
  top_left = point_from_string(crop_from)
@@ -79,7 +80,7 @@ module Alchemy
79
80
  height = 0 if height.nil?
80
81
  {
81
82
  width: width,
82
- height: height
83
+ height: height,
83
84
  }
84
85
  end
85
86
 
@@ -109,7 +110,7 @@ module Alchemy
109
110
  def image_size
110
111
  {
111
112
  width: image_file_width,
112
- height: image_file_height
113
+ height: image_file_height,
113
114
  }
114
115
  end
115
116
 
@@ -118,6 +119,7 @@ module Alchemy
118
119
  #
119
120
  def can_be_cropped_to(string, upsample = false)
120
121
  return true if upsample
122
+
121
123
  is_bigger_than sizes_from_string(string)
122
124
  end
123
125
 
@@ -147,7 +149,7 @@ module Alchemy
147
149
  y = 0 if y.nil?
148
150
  {
149
151
  x: x,
150
- y: y
152
+ y: y,
151
153
  }
152
154
  end
153
155
 
@@ -158,7 +160,7 @@ module Alchemy
158
160
  def get_top_left_crop_corner(dimensions)
159
161
  {
160
162
  x: (image_file_width - dimensions[:width]) / 2,
161
- y: (image_file_height - dimensions[:height]) / 2
163
+ y: (image_file_height - dimensions[:height]) / 2,
162
164
  }
163
165
  end
164
166
 
@@ -182,7 +184,7 @@ module Alchemy
182
184
  def size_when_fitting(target, dimensions = get_base_dimensions)
183
185
  zoom = [
184
186
  dimensions[:width].to_f / target[:width],
185
- dimensions[:height].to_f / target[:height]
187
+ dimensions[:height].to_f / target[:height],
186
188
  ].max
187
189
 
188
190
  if zoom == 0.0
@@ -205,7 +207,7 @@ module Alchemy
205
207
  x1: point[:x],
206
208
  y1: point[:y],
207
209
  x2: point[:x] + mask[:width],
208
- y2: point[:y] + mask[:height]
210
+ y2: point[:y] + mask[:height],
209
211
  }
210
212
  end
211
213
 
@@ -252,7 +254,7 @@ module Alchemy
252
254
  def reduce_to_image(dimensions)
253
255
  {
254
256
  width: [dimensions[:width], image_file_width].min,
255
- height: [dimensions[:height], image_file_height].min
257
+ height: [dimensions[:height], image_file_height].min,
256
258
  }
257
259
  end
258
260
  end
@@ -12,7 +12,7 @@ module Alchemy
12
12
  :format,
13
13
  :quality,
14
14
  :size,
15
- :upsample
15
+ :upsample,
16
16
  ]
17
17
 
18
18
  # Returns a path to picture for use inside a image_tag helper.
@@ -66,8 +66,8 @@ module Alchemy
66
66
  end
67
67
 
68
68
  options = {
69
- flatten: target_format != 'gif' && image_file_format == 'gif'
70
- }.merge(options)
69
+ flatten: target_format != "gif" && image_file_format == "gif",
70
+ }.with_indifferent_access.merge(options)
71
71
 
72
72
  encoding_options = []
73
73
 
@@ -77,13 +77,13 @@ module Alchemy
77
77
  end
78
78
 
79
79
  if options[:flatten]
80
- encoding_options << '-flatten'
80
+ encoding_options << "-flatten"
81
81
  end
82
82
 
83
83
  convertion_needed = target_format != image_file_format || encoding_options.present?
84
84
 
85
85
  if has_convertible_format? && convertion_needed
86
- image = image.encode(target_format, encoding_options.join(' '))
86
+ image = image.encode(target_format, encoding_options.join(" "))
87
87
  end
88
88
 
89
89
  image
@@ -26,13 +26,13 @@ module Alchemy
26
26
 
27
27
  include Alchemy::NameConversions
28
28
  include Alchemy::Taggable
29
- include Alchemy::ContentTouching
29
+ include Alchemy::TouchElements
30
30
  include Alchemy::Picture::Transformations
31
31
  include Alchemy::Picture::Url
32
32
 
33
33
  has_many :essence_pictures,
34
- class_name: 'Alchemy::EssencePicture',
35
- foreign_key: 'picture_id',
34
+ class_name: "Alchemy::EssencePicture",
35
+ foreign_key: "picture_id",
36
36
  inverse_of: :ingredient_association
37
37
 
38
38
  has_many :contents, through: :essence_pictures
@@ -62,35 +62,24 @@ module Alchemy
62
62
  # We need to define this method here to have it available in the validations below.
63
63
  class << self
64
64
  def allowed_filetypes
65
- Config.get(:uploader).fetch('allowed_filetypes', {}).fetch('alchemy/pictures', [])
65
+ Config.get(:uploader).fetch("allowed_filetypes", {}).fetch("alchemy/pictures", [])
66
66
  end
67
67
  end
68
68
 
69
69
  validates_presence_of :image_file
70
- validates_size_of :image_file, maximum: Config.get(:uploader)['file_size_limit'].megabytes
70
+ validates_size_of :image_file, maximum: Config.get(:uploader)["file_size_limit"].megabytes
71
71
  validates_property :format,
72
72
  of: :image_file,
73
73
  in: allowed_filetypes,
74
74
  case_sensitive: false,
75
75
  message: Alchemy.t("not a valid image")
76
76
 
77
- stampable stamper_class_name: Alchemy.user_class.name
77
+ stampable stamper_class_name: Alchemy.user_class_name
78
78
 
79
- scope :named, ->(name) {
80
- where("#{table_name}.name LIKE ?", "%#{name}%")
81
- }
82
-
83
- scope :recent, -> {
84
- where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at)
85
- }
86
-
87
- scope :deletable, -> {
88
- where("#{table_name}.id NOT IN (SELECT picture_id FROM #{EssencePicture.table_name})")
89
- }
90
-
91
- scope :without_tag, -> {
92
- left_outer_joins(:taggings).where(gutentag_taggings: {id: nil})
93
- }
79
+ scope :named, ->(name) { where("#{table_name}.name LIKE ?", "%#{name}%") }
80
+ scope :recent, -> { where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at) }
81
+ scope :deletable, -> { where("#{table_name}.id NOT IN (SELECT picture_id FROM #{EssencePicture.table_name})") }
82
+ scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: { id: nil }) }
94
83
 
95
84
  # Class methods
96
85
 
@@ -102,6 +91,7 @@ module Alchemy
102
91
  def last_upload
103
92
  last_picture = Picture.last
104
93
  return Picture.all unless last_picture
94
+
105
95
  Picture.where(upload_hash: last_picture.upload_hash)
106
96
  end
107
97
 
@@ -123,11 +113,11 @@ module Alchemy
123
113
  pictures.order(:name)
124
114
  end
125
115
 
126
- def filtered_by(filter = '')
116
+ def filtered_by(filter = "")
127
117
  case filter
128
- when 'recent' then recent
129
- when 'last_upload' then last_upload
130
- when 'without_tag' then without_tag
118
+ when "recent" then recent
119
+ when "last_upload" then last_upload
120
+ when "without_tag" then without_tag
131
121
  else
132
122
  all
133
123
  end
@@ -166,7 +156,7 @@ module Alchemy
166
156
  {
167
157
  name: image_file_name,
168
158
  size: image_file_size,
169
- error: errors[:image_file].join
159
+ error: errors[:image_file].join,
170
160
  }
171
161
  end
172
162
 
@@ -176,7 +166,7 @@ module Alchemy
176
166
  if name.blank?
177
167
  "image_#{id}"
178
168
  else
179
- ::CGI.escape(name.gsub(/\.(gif|png|jpe?g|tiff?)/i, '').tr('.', ' '))
169
+ ::CGI.escape(name.gsub(/\.(gif|png|jpe?g|tiff?)/i, "").tr(".", " "))
180
170
  end
181
171
  end
182
172
 
@@ -190,6 +180,7 @@ module Alchemy
190
180
  #
191
181
  def humanized_name
192
182
  return "" if image_file_name.blank?
183
+
193
184
  convert_to_humanized_name(image_file_name, suffix)
194
185
  end
195
186
 
@@ -213,7 +204,7 @@ module Alchemy
213
204
  #
214
205
  def convertible?
215
206
  Config.get(:image_output_format) &&
216
- Config.get(:image_output_format) != 'original' &&
207
+ Config.get(:image_output_format) != "original" &&
217
208
  has_convertible_format?
218
209
  end
219
210
 
@@ -3,7 +3,7 @@
3
3
  module Alchemy
4
4
  module Site::Layout
5
5
  extend ActiveSupport::Concern
6
- SITE_DEFINITIONS_FILE = Rails.root.join('config/alchemy/site_layouts.yml')
6
+ SITE_DEFINITIONS_FILE = Rails.root.join("config/alchemy/site_layouts.yml")
7
7
 
8
8
  module ClassMethods
9
9
  # Returns the site layouts definition defined in +site_layouts.yml+ file
@@ -28,7 +28,7 @@ module Alchemy
28
28
  # Returns site's layout definition
29
29
  #
30
30
  def definition
31
- self.class.definitions.detect { |l| l['name'] == partial_name }
31
+ self.class.definitions.detect { |l| l["name"] == partial_name }
32
32
  end
33
33
 
34
34
  # Returns the name for the layout partial
@@ -23,10 +23,12 @@ module Alchemy
23
23
  # associations
24
24
  has_many :languages
25
25
 
26
- scope :published, -> { where(public: true) }
26
+ before_destroy if: -> { languages.any? } do
27
+ errors.add(:languages, :still_present)
28
+ throw(:abort)
29
+ end
27
30
 
28
- # Callbacks
29
- before_create :create_default_language!, unless: -> { languages.any? }
31
+ scope :published, -> { where(public: true) }
30
32
 
31
33
  # concerns
32
34
  include Alchemy::Site::Layout
@@ -64,7 +66,7 @@ module Alchemy
64
66
  end
65
67
 
66
68
  def default
67
- Site.first || create_default_site!
69
+ Site.first
68
70
  end
69
71
 
70
72
  def find_for_host(host)
@@ -81,38 +83,6 @@ module Alchemy
81
83
  site.aliases.split.include?(host) if site.aliases.present?
82
84
  end
83
85
  end
84
-
85
- private
86
-
87
- def create_default_site!
88
- default_site = Alchemy::Config.get(:default_site)
89
- if default_site
90
- create!(name: default_site['name'], host: default_site['host'])
91
- else
92
- raise DefaultSiteNotFoundError
93
- end
94
- end
95
- end
96
-
97
- private
98
-
99
- # If no languages are present, create a default language based
100
- # on the host app's Alchemy configuration.
101
- def create_default_language!
102
- default_language = Alchemy::Config.get(:default_language)
103
- if default_language
104
- languages.build(
105
- name: default_language['name'],
106
- language_code: default_language['code'],
107
- locale: default_language['code'],
108
- frontpage_name: default_language['frontpage_name'],
109
- page_layout: default_language['page_layout'],
110
- public: true,
111
- default: true
112
- )
113
- else
114
- raise DefaultLanguageNotFoundError
115
- end
116
86
  end
117
87
  end
118
88
  end