alchemy_cms 5.2.0 → 6.0.0.b3

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 (289) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -14
  3. data/.gitignore +0 -1
  4. data/.hound.yml +1 -1
  5. data/.rubocop.yml +46 -4
  6. data/CHANGELOG.md +114 -5
  7. data/Gemfile +8 -1
  8. data/README.md +5 -2
  9. data/alchemy_cms.gemspec +78 -65
  10. data/app/assets/javascripts/alchemy/admin.js +0 -2
  11. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -27
  12. data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +2 -1
  13. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +1 -1
  14. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +0 -25
  15. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +1 -1
  16. data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +2 -0
  17. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +1 -1
  18. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +3 -1
  19. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +1 -1
  20. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +40 -27
  21. data/app/assets/javascripts/alchemy/templates/node_folder.hbs +1 -1
  22. data/app/assets/stylesheets/alchemy/_extends.scss +15 -2
  23. data/app/assets/stylesheets/alchemy/admin.scss +1 -1
  24. data/app/assets/stylesheets/alchemy/archive.scss +20 -5
  25. data/app/assets/stylesheets/alchemy/buttons.scss +0 -4
  26. data/app/assets/stylesheets/alchemy/elements.scss +73 -61
  27. data/app/assets/stylesheets/alchemy/images.scss +8 -0
  28. data/app/assets/stylesheets/alchemy/node-select.scss +4 -3
  29. data/app/assets/stylesheets/alchemy/page-select.scss +1 -0
  30. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -4
  31. data/app/controllers/alchemy/admin/base_controller.rb +5 -7
  32. data/app/controllers/alchemy/admin/elements_controller.rb +59 -34
  33. data/app/controllers/alchemy/admin/essence_audios_controller.rb +30 -0
  34. data/app/controllers/alchemy/admin/essence_files_controller.rb +0 -14
  35. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +8 -79
  36. data/app/controllers/alchemy/admin/essence_videos_controller.rb +33 -0
  37. data/app/controllers/alchemy/admin/ingredients_controller.rb +30 -0
  38. data/app/controllers/alchemy/admin/layoutpages_controller.rb +0 -1
  39. data/app/controllers/alchemy/admin/pages_controller.rb +7 -22
  40. data/app/controllers/alchemy/admin/pictures_controller.rb +56 -17
  41. data/app/controllers/alchemy/admin/resources_controller.rb +84 -10
  42. data/app/controllers/alchemy/api/elements_controller.rb +13 -4
  43. data/app/controllers/alchemy/api/pages_controller.rb +4 -3
  44. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +13 -3
  45. data/app/controllers/concerns/alchemy/admin/crop_action.rb +26 -0
  46. data/app/decorators/alchemy/element_editor.rb +26 -1
  47. data/app/decorators/alchemy/ingredient_editor.rb +158 -0
  48. data/app/helpers/alchemy/admin/elements_helper.rb +1 -0
  49. data/app/helpers/alchemy/admin/essences_helper.rb +1 -1
  50. data/app/helpers/alchemy/admin/ingredients_helper.rb +42 -0
  51. data/app/helpers/alchemy/elements_block_helper.rb +23 -6
  52. data/app/helpers/alchemy/elements_helper.rb +12 -5
  53. data/app/helpers/alchemy/pages_helper.rb +3 -11
  54. data/app/jobs/alchemy/base_job.rb +11 -0
  55. data/app/jobs/alchemy/publish_page_job.rb +11 -0
  56. data/app/models/alchemy/attachment.rb +24 -7
  57. data/app/models/alchemy/content.rb +1 -6
  58. data/app/models/alchemy/content/factory.rb +23 -27
  59. data/app/models/alchemy/element.rb +39 -72
  60. data/app/models/alchemy/element/definitions.rb +29 -27
  61. data/app/models/alchemy/element/element_contents.rb +131 -122
  62. data/app/models/alchemy/element/element_essences.rb +111 -98
  63. data/app/models/alchemy/element/element_ingredients.rb +184 -0
  64. data/app/models/alchemy/element/presenters.rb +104 -85
  65. data/app/models/alchemy/elements_repository.rb +126 -0
  66. data/app/models/alchemy/essence_audio.rb +12 -0
  67. data/app/models/alchemy/essence_headline.rb +40 -0
  68. data/app/models/alchemy/essence_picture.rb +4 -116
  69. data/app/models/alchemy/essence_richtext.rb +12 -0
  70. data/app/models/alchemy/essence_video.rb +12 -0
  71. data/app/models/alchemy/image_cropper_settings.rb +87 -0
  72. data/app/models/alchemy/ingredient.rb +183 -0
  73. data/app/models/alchemy/ingredient_validator.rb +97 -0
  74. data/app/models/alchemy/ingredients/audio.rb +29 -0
  75. data/app/models/alchemy/ingredients/boolean.rb +21 -0
  76. data/app/models/alchemy/ingredients/datetime.rb +20 -0
  77. data/app/models/alchemy/ingredients/file.rb +30 -0
  78. data/app/models/alchemy/ingredients/headline.rb +42 -0
  79. data/app/models/alchemy/ingredients/html.rb +19 -0
  80. data/app/models/alchemy/ingredients/link.rb +16 -0
  81. data/app/models/alchemy/ingredients/node.rb +23 -0
  82. data/app/models/alchemy/ingredients/page.rb +23 -0
  83. data/app/models/alchemy/ingredients/picture.rb +41 -0
  84. data/app/models/alchemy/ingredients/richtext.rb +57 -0
  85. data/app/models/alchemy/ingredients/select.rb +10 -0
  86. data/app/models/alchemy/ingredients/text.rb +17 -0
  87. data/app/models/alchemy/ingredients/video.rb +33 -0
  88. data/app/models/alchemy/language.rb +0 -11
  89. data/app/models/alchemy/page.rb +76 -33
  90. data/app/models/alchemy/page/fixed_attributes.rb +53 -51
  91. data/app/models/alchemy/page/page_elements.rb +186 -205
  92. data/app/models/alchemy/page/page_naming.rb +66 -64
  93. data/app/models/alchemy/page/page_natures.rb +139 -142
  94. data/app/models/alchemy/page/page_scopes.rb +117 -102
  95. data/app/models/alchemy/page/publisher.rb +50 -0
  96. data/app/models/alchemy/page/url_path.rb +1 -1
  97. data/app/models/alchemy/page_version.rb +58 -0
  98. data/app/models/alchemy/picture.rb +18 -40
  99. data/app/models/alchemy/picture/calculations.rb +2 -8
  100. data/app/models/alchemy/picture/preprocessor.rb +2 -0
  101. data/app/models/alchemy/picture/transformations.rb +24 -96
  102. data/app/models/concerns/alchemy/picture_thumbnails.rb +181 -0
  103. data/app/models/concerns/alchemy/touch_elements.rb +2 -2
  104. data/app/presenters/alchemy/picture_view.rb +88 -0
  105. data/app/serializers/alchemy/element_serializer.rb +5 -0
  106. data/app/serializers/alchemy/page_tree_serializer.rb +3 -2
  107. data/app/services/alchemy/delete_elements.rb +44 -0
  108. data/app/services/alchemy/duplicate_element.rb +56 -0
  109. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +2 -3
  110. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +3 -3
  111. data/app/views/alchemy/admin/attachments/assign.js.erb +11 -0
  112. data/app/views/alchemy/admin/attachments/index.html.erb +2 -3
  113. data/app/views/alchemy/admin/crop.html.erb +36 -0
  114. data/app/views/alchemy/admin/elements/_element.html.erb +14 -10
  115. data/app/views/alchemy/admin/elements/{_element_footer.html.erb → _footer.html.erb} +0 -0
  116. data/app/views/alchemy/admin/elements/{_new_element_form.html.erb → _form.html.erb} +1 -1
  117. data/app/views/alchemy/admin/elements/{_element_header.html.erb → _header.html.erb} +1 -1
  118. data/app/views/alchemy/admin/elements/{_element_toolbar.html.erb → _toolbar.html.erb} +5 -6
  119. data/app/views/alchemy/admin/elements/create.js.erb +1 -1
  120. data/app/views/alchemy/admin/elements/{trash.js.erb → destroy.js.erb} +2 -6
  121. data/app/views/alchemy/admin/elements/fold.js.erb +2 -2
  122. data/app/views/alchemy/admin/elements/new.html.erb +3 -3
  123. data/app/views/alchemy/admin/elements/order.js.erb +0 -17
  124. data/app/views/alchemy/admin/elements/update.js.erb +3 -2
  125. data/app/views/alchemy/admin/essence_audios/edit.html.erb +7 -0
  126. data/app/views/alchemy/admin/essence_pictures/update.js.erb +0 -1
  127. data/app/views/alchemy/admin/essence_videos/edit.html.erb +11 -0
  128. data/app/views/alchemy/admin/ingredients/_audio_fields.html.erb +4 -0
  129. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +18 -0
  130. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +25 -0
  131. data/app/views/alchemy/admin/ingredients/_video_fields.html.erb +8 -0
  132. data/app/views/alchemy/admin/ingredients/edit.html.erb +4 -0
  133. data/app/views/alchemy/admin/layoutpages/edit.html.erb +0 -5
  134. data/app/views/alchemy/admin/nodes/_node.html.erb +2 -2
  135. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +1 -1
  136. data/app/views/alchemy/admin/pages/_external_link.html.erb +1 -1
  137. data/app/views/alchemy/admin/pages/_file_link.html.erb +1 -1
  138. data/app/views/alchemy/admin/pages/_form.html.erb +0 -6
  139. data/app/views/alchemy/admin/pages/_internal_link.html.erb +1 -1
  140. data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +5 -2
  141. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -1
  142. data/app/views/alchemy/admin/pages/edit.html.erb +36 -24
  143. data/app/views/alchemy/admin/pages/index.html.erb +2 -9
  144. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +2 -4
  145. data/app/views/alchemy/admin/partials/_routes.html.erb +7 -11
  146. data/app/views/alchemy/admin/partials/_search_form.html.erb +9 -0
  147. data/app/views/alchemy/admin/pictures/_archive.html.erb +1 -1
  148. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
  149. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +5 -7
  150. data/app/views/alchemy/admin/pictures/_infos.html.erb +0 -1
  151. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +4 -4
  152. data/app/views/alchemy/admin/pictures/assign.js.erb +10 -0
  153. data/app/views/alchemy/admin/pictures/index.html.erb +8 -3
  154. data/app/views/alchemy/admin/resources/_filter.html.erb +12 -0
  155. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +14 -17
  156. data/app/views/alchemy/admin/resources/_form.html.erb +3 -0
  157. data/app/views/alchemy/admin/resources/_table_header.html.erb +15 -0
  158. data/app/views/alchemy/admin/resources/index.html.erb +3 -11
  159. data/app/views/alchemy/essences/_essence_audio_editor.html.erb +4 -0
  160. data/app/views/alchemy/essences/_essence_audio_view.html.erb +15 -0
  161. data/app/views/alchemy/essences/_essence_file_editor.html.erb +15 -6
  162. data/app/views/alchemy/essences/_essence_headline_editor.html.erb +36 -0
  163. data/app/views/alchemy/essences/_essence_headline_view.html.erb +10 -0
  164. data/app/views/alchemy/essences/_essence_link_editor.html.erb +8 -4
  165. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +27 -12
  166. data/app/views/alchemy/essences/_essence_picture_view.html.erb +3 -3
  167. data/app/views/alchemy/essences/_essence_text_editor.html.erb +12 -4
  168. data/app/views/alchemy/essences/_essence_video_editor.html.erb +4 -0
  169. data/app/views/alchemy/essences/_essence_video_view.html.erb +18 -0
  170. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +21 -16
  171. data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +2 -2
  172. data/app/views/alchemy/ingredients/_audio_editor.html.erb +5 -0
  173. data/app/views/alchemy/ingredients/_audio_view.html.erb +14 -0
  174. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +11 -0
  175. data/app/views/alchemy/ingredients/_boolean_view.html.erb +1 -0
  176. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +17 -0
  177. data/app/views/alchemy/ingredients/_datetime_view.html.erb +9 -0
  178. data/app/views/alchemy/ingredients/_file_editor.html.erb +52 -0
  179. data/app/views/alchemy/ingredients/_file_view.html.erb +17 -0
  180. data/app/views/alchemy/ingredients/_headline_editor.html.erb +30 -0
  181. data/app/views/alchemy/ingredients/_headline_view.html.erb +9 -0
  182. data/app/views/alchemy/ingredients/_html_editor.html.erb +8 -0
  183. data/app/views/alchemy/ingredients/_html_view.html.erb +1 -0
  184. data/app/views/alchemy/ingredients/_link_editor.html.erb +24 -0
  185. data/app/views/alchemy/ingredients/_link_view.html.erb +9 -0
  186. data/app/views/alchemy/ingredients/_node_editor.html.erb +26 -0
  187. data/app/views/alchemy/ingredients/_node_view.html.erb +1 -0
  188. data/app/views/alchemy/ingredients/_page_editor.html.erb +25 -0
  189. data/app/views/alchemy/ingredients/_page_view.html.erb +4 -0
  190. data/app/views/alchemy/ingredients/_picture_editor.html.erb +60 -0
  191. data/app/views/alchemy/ingredients/_picture_view.html.erb +5 -0
  192. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +12 -0
  193. data/app/views/alchemy/ingredients/_richtext_view.html.erb +3 -0
  194. data/app/views/alchemy/ingredients/_select_editor.html.erb +30 -0
  195. data/app/views/alchemy/ingredients/_select_view.html.erb +1 -0
  196. data/app/views/alchemy/ingredients/_text_editor.html.erb +20 -0
  197. data/app/views/alchemy/ingredients/_text_view.html.erb +16 -0
  198. data/app/views/alchemy/ingredients/_video_editor.html.erb +5 -0
  199. data/app/views/alchemy/ingredients/_video_view.html.erb +17 -0
  200. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +20 -0
  201. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +57 -0
  202. data/config/brakeman.ignore +66 -159
  203. data/config/initializers/dragonfly.rb +10 -0
  204. data/config/locales/alchemy.en.yml +108 -64
  205. data/config/routes.rb +17 -22
  206. data/db/migrate/20201207131309_create_page_versions.rb +19 -0
  207. data/db/migrate/20201207135820_add_page_version_id_to_alchemy_elements.rb +76 -0
  208. data/db/migrate/20210205143548_rename_public_on_and_public_until_on_alchemy_pages.rb +10 -0
  209. data/db/migrate/20210326105046_add_sanitized_body_to_alchemy_essence_richtexts.rb +7 -0
  210. data/db/migrate/20210406093436_add_alchemy_essence_headlines.rb +12 -0
  211. data/db/migrate/20210506135919_create_essence_audios.rb +19 -0
  212. data/db/migrate/20210506140258_create_essence_videos.rb +23 -0
  213. data/db/migrate/20210508091432_create_alchemy_ingredients.rb +22 -0
  214. data/lib/alchemy/admin/preview_url.rb +2 -0
  215. data/lib/alchemy/deprecation.rb +1 -1
  216. data/lib/alchemy/dragonfly/processors/auto_orient.rb +18 -0
  217. data/lib/alchemy/dragonfly/processors/crop_resize.rb +35 -0
  218. data/lib/alchemy/elements_finder.rb +14 -60
  219. data/lib/alchemy/essence.rb +1 -2
  220. data/lib/alchemy/forms/builder.rb +21 -1
  221. data/lib/alchemy/hints.rb +8 -4
  222. data/lib/alchemy/page_layout.rb +0 -13
  223. data/lib/alchemy/permissions.rb +30 -29
  224. data/lib/alchemy/resource.rb +13 -3
  225. data/lib/alchemy/resource_filter.rb +40 -0
  226. data/lib/alchemy/resources_helper.rb +1 -16
  227. data/lib/alchemy/tasks/tidy.rb +29 -0
  228. data/lib/alchemy/test_support.rb +2 -11
  229. data/lib/alchemy/test_support/essence_shared_examples.rb +0 -1
  230. data/lib/alchemy/test_support/factories/element_factory.rb +8 -8
  231. data/lib/alchemy/test_support/factories/essence_audio_factory.rb +7 -0
  232. data/lib/alchemy/test_support/factories/essence_video_factory.rb +7 -0
  233. data/lib/alchemy/test_support/factories/ingredient_factory.rb +25 -0
  234. data/lib/alchemy/test_support/factories/page_factory.rb +20 -1
  235. data/lib/alchemy/test_support/factories/page_version_factory.rb +23 -0
  236. data/lib/alchemy/test_support/having_crop_action_examples.rb +170 -0
  237. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +646 -0
  238. data/lib/alchemy/test_support/shared_ingredient_editor_examples.rb +21 -0
  239. data/lib/alchemy/test_support/shared_ingredient_examples.rb +75 -0
  240. data/lib/alchemy/tinymce.rb +17 -0
  241. data/lib/alchemy/upgrader/six_point_zero.rb +21 -0
  242. data/lib/alchemy/upgrader/tasks/add_page_versions.rb +33 -0
  243. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +62 -0
  244. data/lib/alchemy/version.rb +1 -1
  245. data/lib/alchemy_cms.rb +1 -0
  246. data/lib/generators/alchemy/elements/elements_generator.rb +1 -0
  247. data/lib/generators/alchemy/elements/templates/view.html.erb +9 -0
  248. data/lib/generators/alchemy/elements/templates/view.html.haml +9 -0
  249. data/lib/generators/alchemy/elements/templates/view.html.slim +9 -0
  250. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +38 -0
  251. data/lib/generators/alchemy/ingredient/templates/editor.html.erb +14 -0
  252. data/lib/generators/alchemy/ingredient/templates/model.rb.tt +13 -0
  253. data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -0
  254. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +1 -1
  255. data/lib/generators/alchemy/menus/templates/node.html.erb +1 -1
  256. data/lib/generators/alchemy/menus/templates/node.html.haml +1 -1
  257. data/lib/generators/alchemy/menus/templates/node.html.slim +1 -1
  258. data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
  259. data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
  260. data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
  261. data/lib/tasks/alchemy/thumbnails.rake +4 -2
  262. data/lib/tasks/alchemy/tidy.rake +12 -0
  263. data/lib/tasks/alchemy/upgrade.rake +26 -0
  264. data/package.json +3 -2
  265. data/package/admin.js +11 -1
  266. data/package/src/__tests__/i18n.spec.js +23 -0
  267. data/package/src/file_editors.js +28 -0
  268. data/package/src/i18n.js +1 -3
  269. data/package/src/image_cropper.js +103 -0
  270. data/package/src/image_loader.js +58 -0
  271. data/package/src/node_tree.js +5 -5
  272. data/package/src/picture_editors.js +169 -0
  273. data/package/src/utils/__tests__/ajax.spec.js +20 -12
  274. data/package/src/utils/ajax.js +8 -3
  275. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +3 -18
  276. data/vendor/assets/stylesheets/jquery.Jcrop.min.scss +2 -28
  277. metadata +292 -55
  278. data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +0 -44
  279. data/app/assets/javascripts/alchemy/alchemy.trash_window.js.coffee +0 -30
  280. data/app/assets/stylesheets/alchemy/trash.scss +0 -8
  281. data/app/controllers/alchemy/admin/trash_controller.rb +0 -44
  282. data/app/views/alchemy/admin/attachments/_filter_bar.html.erb +0 -29
  283. data/app/views/alchemy/admin/essence_files/assign.js.erb +0 -3
  284. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -4
  285. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +0 -48
  286. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +0 -30
  287. data/app/views/alchemy/admin/trash/clear.js.erb +0 -4
  288. data/app/views/alchemy/admin/trash/index.html.erb +0 -31
  289. data/lib/alchemy/test_support/factories.rb +0 -16
@@ -0,0 +1,8 @@
1
+ img {
2
+ opacity: 1;
3
+ transition: opacity $transition-duration;
4
+
5
+ &.loading {
6
+ opacity: 0;
7
+ }
8
+ }
@@ -8,12 +8,13 @@
8
8
  .node-select--node {
9
9
  display: flex;
10
10
  align-items: center;
11
+ height: 21px;
11
12
 
12
13
  .icon {
13
14
  margin: 0 8px 0 4px;
14
15
 
15
16
  .select2-highlighted & {
16
- color: $white
17
+ color: $white;
17
18
  }
18
19
  }
19
20
  }
@@ -24,12 +25,12 @@
24
25
 
25
26
  .node-select--node-url {
26
27
  margin-left: auto;
27
- padding: $default-padding 2*$default-padding;
28
+ padding: $default-padding 2 * $default-padding;
28
29
  color: $dark-gray;
29
30
  font-size: $small-font-size;
30
31
 
31
32
  .select2-highlighted & {
32
- color: $white
33
+ color: $white;
33
34
  }
34
35
  }
35
36
 
@@ -1,4 +1,5 @@
1
1
  .page-select--page,
2
+ .page-select--page-name,
2
3
  .page-select--page-urlname {
3
4
  text-overflow: ellipsis;
4
5
  overflow: hidden;
@@ -8,6 +8,10 @@ module Alchemy
8
8
 
9
9
  helper "alchemy/admin/tags"
10
10
 
11
+ before_action(only: :assign) do
12
+ @attachment = Attachment.find(params[:id])
13
+ end
14
+
11
15
  def index
12
16
  @query = Attachment.ransack(search_filter_params[:q])
13
17
  @query.sorts = "name asc" if @query.sorts.empty?
@@ -17,8 +21,8 @@ module Alchemy
17
21
  @attachments = @attachments.tagged_with(search_filter_params[:tagged_with])
18
22
  end
19
23
 
20
- if search_filter_params[:file_type].present?
21
- @attachments = @attachments.with_file_type(search_filter_params[:file_type])
24
+ if search_filter_params[:filter].present?
25
+ @attachments = apply_filters(@attachments)
22
26
  end
23
27
 
24
28
  @attachments = @attachments
@@ -73,9 +77,9 @@ module Alchemy
73
77
  def search_filter_params
74
78
  @_search_filter_params ||= params.except(*COMMON_SEARCH_FILTER_EXCLUDES + [:attachment]).permit(
75
79
  *common_search_filter_includes + [
76
- :file_type,
80
+ :form_field_id,
77
81
  :content_id,
78
- ],
82
+ ]
79
83
  )
80
84
  end
81
85
 
@@ -8,7 +8,7 @@ module Alchemy
8
8
 
9
9
  before_action :load_locked_pages
10
10
 
11
- helper_method :clipboard_empty?, :trash_empty?, :get_clipboard, :is_admin?
11
+ helper_method :clipboard_empty?, :get_clipboard, :is_admin?
12
12
 
13
13
  check_authorization
14
14
 
@@ -54,7 +54,10 @@ module Alchemy
54
54
  if request.xhr?
55
55
  render action: "error_notice"
56
56
  else
57
- render "500", status: 500
57
+ respond_to do |format|
58
+ format.html { render "500", status: 500 }
59
+ format.json { render json: { message: @notice }, status: 500 }
60
+ end
58
61
  end
59
62
  end
60
63
 
@@ -69,11 +72,6 @@ module Alchemy
69
72
  get_clipboard(category).blank?
70
73
  end
71
74
 
72
- def trash_empty?(category)
73
- "alchemy/#{category.singularize}".classify.constantize.trashed.blank?
74
- end
75
- deprecate :trash_empty?, deprecator: Alchemy::Deprecation
76
-
77
75
  def set_stamper
78
76
  if Alchemy.user_class < ActiveRecord::Base
79
77
  Alchemy.user_class.stamper = current_alchemy_user
@@ -3,27 +3,31 @@
3
3
  module Alchemy
4
4
  module Admin
5
5
  class ElementsController < Alchemy::Admin::BaseController
6
- before_action :load_element, only: [:update, :trash, :fold, :publish]
6
+ before_action :load_element, only: [:update, :destroy, :fold, :publish]
7
7
  authorize_resource class: Alchemy::Element
8
8
 
9
9
  def index
10
- @page = Page.find(params[:page_id])
11
- @elements = @page.all_elements.not_nested.unfixed.not_trashed.includes(*element_includes)
12
- @fixed_elements = @page.all_elements.fixed.not_trashed.includes(*element_includes)
10
+ @page_version = PageVersion.find(params[:page_version_id])
11
+ @page = @page_version.page
12
+ elements = @page_version.elements.order(:position).includes(*element_includes)
13
+ @elements = elements.not_nested.unfixed
14
+ @fixed_elements = elements.not_nested.fixed
13
15
  end
14
16
 
15
17
  def new
16
- @page = Page.find(params[:page_id])
18
+ @page_version = PageVersion.find(params[:page_version_id])
19
+ @page = @page_version.page
17
20
  @parent_element = Element.find_by(id: params[:parent_element_id])
18
21
  @elements = @page.available_elements_within_current_scope(@parent_element)
19
- @element = @page.elements.build
22
+ @element = @page_version.elements.build
20
23
  @clipboard = get_clipboard("elements")
21
24
  @clipboard_items = Element.all_from_clipboard_for_page(@clipboard, @page)
22
25
  end
23
26
 
24
27
  # Creates a element as discribed in config/alchemy/elements.yml on page via AJAX.
25
28
  def create
26
- @page = Page.find(params[:element][:page_id])
29
+ @page_version = PageVersion.find(params[:element][:page_version_id])
30
+ @page = @page_version.page
27
31
  Element.transaction do
28
32
  if @paste_from_clipboard = params[:paste_from_clipboard].present?
29
33
  @element = paste_element_from_clipboard
@@ -38,7 +42,7 @@ module Alchemy
38
42
  if @element.valid?
39
43
  render :create
40
44
  else
41
- @element.page = @page
45
+ @element.page_version = @page_version
42
46
  @elements = @page.available_element_definitions
43
47
  @clipboard = get_clipboard("elements")
44
48
  @clipboard_items = Element.all_from_clipboard_for_page(@clipboard, @page)
@@ -51,40 +55,39 @@ module Alchemy
51
55
  # And update all contents in the elements by calling update_contents.
52
56
  #
53
57
  def update
54
- if @element.update_contents(contents_params)
55
- @page = @element.page
56
- @element_validated = @element.update(element_params)
58
+ @page = @element.page
59
+
60
+ if element_params.key?(:ingredients_attributes)
61
+ update_element_with_ingredients
57
62
  else
58
- @element_validated = false
59
- @notice = Alchemy.t("Validation failed")
60
- @error_message = "<h2>#{@notice}</h2><p>#{Alchemy.t(:content_validations_headline)}</p>".html_safe
63
+ update_element_with_contents
61
64
  end
62
65
  end
63
66
 
64
- def publish
65
- @element.update(public: !@element.public?)
67
+ def destroy
68
+ @richtext_ids = @element.richtext_contents_ids + @element.richtext_ingredients_ids
69
+ @element.destroy
70
+ @notice = Alchemy.t("Successfully deleted element") % { element: @element.display_name }
66
71
  end
67
72
 
68
- # Trashes the Element instead of deleting it.
69
- def trash
70
- @page = @element.page
71
- @element.trash!
73
+ def publish
74
+ @element.update(public: !@element.public?)
72
75
  end
73
76
 
74
77
  def order
75
- @trashed_element_ids = Element.trashed.where(id: params[:element_ids]).pluck(:id)
76
78
  @parent_element = Element.find_by(id: params[:parent_element_id])
77
79
  Element.transaction do
78
- params.fetch(:element_ids, []).each_with_index do |element_id, idx|
79
- # Ensure to set page_id and parent_element_id to the current
80
- # because of trashed elements could still have old values
81
- Element.where(id: element_id).update_all(
82
- page_id: params[:page_id],
80
+ params.fetch(:element_ids, []).each.with_index(1) do |element_id, position|
81
+ # We need to set the parent_element_id, because we might have dragged the
82
+ # element over from another nestable element
83
+ Element.find_by(id: element_id).update_columns(
83
84
  parent_element_id: params[:parent_element_id],
84
- position: idx + 1,
85
+ position: position,
85
86
  )
86
87
  end
87
- @parent_element.try!(:touch)
88
+ # Need to manually touch the parent because Rails does not do it
89
+ # with the update_columns above
90
+ @parent_element&.touch
88
91
  end
89
92
  end
90
93
 
@@ -102,6 +105,7 @@ module Alchemy
102
105
  contents: {
103
106
  essence: :ingredient_association,
104
107
  },
108
+ ingredients: :related_object,
105
109
  },
106
110
  :tags,
107
111
  {
@@ -110,6 +114,7 @@ module Alchemy
110
114
  contents: {
111
115
  essence: :ingredient_association,
112
116
  },
117
+ ingredients: :related_object,
113
118
  },
114
119
  :tags,
115
120
  ],
@@ -132,7 +137,7 @@ module Alchemy
132
137
  @source_element = Element.find(element_from_clipboard["id"])
133
138
  element = Element.copy(@source_element, {
134
139
  parent_element_id: create_element_params[:parent_element_id],
135
- page_id: @page.id,
140
+ page_version_id: @page_version.id,
136
141
  })
137
142
  if element_from_clipboard["action"] == "cut"
138
143
  @cut_element_id = @source_element.id
@@ -147,15 +152,35 @@ module Alchemy
147
152
  end
148
153
 
149
154
  def element_params
150
- if @element.taggable?
151
- params.fetch(:element, {}).permit(:tag_list)
155
+ params.fetch(:element, {}).permit(:tag_list, ingredients_attributes: {})
156
+ end
157
+
158
+ def create_element_params
159
+ params.require(:element).permit(:name, :page_version_id, :parent_element_id)
160
+ end
161
+
162
+ def update_element_with_ingredients
163
+ if @element.update(element_params)
164
+ @element_validated = true
152
165
  else
153
- params.fetch(:element, {})
166
+ element_update_error
167
+ @error_messages = @element.ingredient_error_messages
154
168
  end
155
169
  end
156
170
 
157
- def create_element_params
158
- params.require(:element).permit(:name, :page_id, :parent_element_id)
171
+ def update_element_with_contents
172
+ if @element.update_contents(contents_params)
173
+ @element_validated = @element.update(element_params)
174
+ else
175
+ element_update_error
176
+ @error_messages = @element.essence_error_messages
177
+ end
178
+ end
179
+
180
+ def element_update_error
181
+ @element_validated = false
182
+ @notice = Alchemy.t("Validation failed")
183
+ @error_message = "<h2>#{@notice}</h2><p>#{Alchemy.t(:content_validations_headline)}</p>".html_safe
159
184
  end
160
185
  end
161
186
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Admin
5
+ class EssenceAudiosController < Alchemy::Admin::BaseController
6
+ authorize_resource class: Alchemy::EssenceAudio
7
+ before_action :load_essence
8
+
9
+ def update
10
+ @essence_audio.update(essence_audio_params)
11
+ end
12
+
13
+ private
14
+
15
+ def load_essence
16
+ @essence_audio = EssenceAudio.find(params[:id])
17
+ end
18
+
19
+ def essence_audio_params
20
+ params.require(:essence_audio).permit(
21
+ :autoplay,
22
+ :controls,
23
+ :loop,
24
+ :muted,
25
+ :attachment_id
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -17,20 +17,6 @@ module Alchemy
17
17
  @essence_file.update(essence_file_params)
18
18
  end
19
19
 
20
- # Assigns file, but does not saves it.
21
- #
22
- # When the user saves the element the content gets updated as well.
23
- #
24
- def assign
25
- @content = Content.find_by(id: params[:content_id])
26
- @attachment = Attachment.find_by(id: params[:attachment_id])
27
- @content.essence.attachment = @attachment
28
-
29
- # We need to update timestamp here because we don't save yet,
30
- # but the cache needs to be get invalid.
31
- @content.touch
32
- end
33
-
34
20
  private
35
21
 
36
22
  def essence_file_params
@@ -3,11 +3,12 @@
3
3
  module Alchemy
4
4
  module Admin
5
5
  class EssencePicturesController < Alchemy::Admin::BaseController
6
- FLOAT_REGEX = /\A\d+(\.\d+)?\z/
6
+ include CropAction
7
+
7
8
  authorize_resource class: Alchemy::EssencePicture
8
9
 
9
- before_action :load_essence_picture, only: [:edit, :crop, :update]
10
- before_action :load_content, only: [:edit, :update, :assign]
10
+ before_action :load_essence_picture, only: [:edit, :update]
11
+ before_action :load_content, only: [:edit, :update]
11
12
 
12
13
  helper "alchemy/admin/contents"
13
14
  helper "alchemy/admin/essences"
@@ -16,94 +17,22 @@ module Alchemy
16
17
  def edit
17
18
  end
18
19
 
19
- def crop
20
- if @picture = @essence_picture.picture
21
- @content = @essence_picture.content
22
- @min_size = sizes_from_essence_or_params
23
- @ratio = ratio_from_size_or_settings
24
- infer_width_or_height_from_ratio
25
-
26
- @default_box = @essence_picture.default_mask(@min_size)
27
- @initial_box = @essence_picture.cropping_mask || @default_box
28
- else
29
- @no_image_notice = Alchemy.t(:no_image_for_cropper_found)
30
- end
31
- end
32
-
33
20
  def update
34
21
  @essence_picture.update(essence_picture_params)
35
22
  end
36
23
 
37
- # Assigns picture, but does not save it.
38
- #
39
- # When the user saves the element the content gets updated as well.
40
- #
41
- def assign
42
- @picture = Picture.find_by(id: params[:picture_id])
43
- @content.essence.picture = @picture
44
- @element = @content.element
45
-
46
- # We need to update timestamp here because we don't save yet,
47
- # but the cache needs to be get invalid.
48
- @content.touch
49
- end
50
-
51
- def destroy
52
- @content = Content.find_by(id: params[:id])
53
- @element = @content.element
54
- @content_id = @content.id
55
- @content.destroy
56
- @essence_pictures = @element.contents.essence_pictures
57
- end
58
-
59
24
  private
60
25
 
61
26
  def load_essence_picture
62
27
  @essence_picture = EssencePicture.find(params[:id])
63
28
  end
64
29
 
65
- def load_content
66
- @content = Content.find(params[:content_id])
30
+ def load_croppable_resource
31
+ @croppable_resource = EssencePicture.find(params[:id])
67
32
  end
68
33
 
69
- # Gets the minimum size of the image to be rendered.
70
- #
71
- # The +render_size+ attribute has preference over the contents +size+ setting.
72
- #
73
- def sizes_from_essence_or_params
74
- if @essence_picture.render_size?
75
- @essence_picture.sizes_from_string(@essence_picture.render_size)
76
- elsif @essence_picture.content.settings[:size]
77
- @essence_picture.sizes_from_string(@essence_picture.content.settings[:size])
78
- else
79
- { width: 0, height: 0 }
80
- end
81
- end
82
-
83
- # Infers the aspect ratio from size or contents settings. If you don't want a fixed
84
- # aspect ratio, don't specify a size or only width or height.
85
- #
86
- def ratio_from_size_or_settings
87
- if @min_size.value?(0) && @essence_picture.content.settings[:fixed_ratio].to_s =~ FLOAT_REGEX
88
- @essence_picture.content.settings[:fixed_ratio].to_f
89
- elsif !@min_size[:width].zero? && !@min_size[:height].zero?
90
- @min_size[:width].to_f / @min_size[:height]
91
- else
92
- false
93
- end
94
- end
95
-
96
- # Infers the minimum width or height
97
- # if the aspect ratio and one dimension is specified.
98
- #
99
- def infer_width_or_height_from_ratio
100
- return unless @ratio
101
-
102
- if @min_size[:height].zero?
103
- @min_size[:height] = (@min_size[:width] / @ratio).to_i
104
- else
105
- @min_size[:width] = (@min_size[:height] * @ratio).to_i
106
- end
34
+ def load_content
35
+ @content = Content.find(params[:content_id])
107
36
  end
108
37
 
109
38
  def essence_picture_params