alchemy_cms 5.2.4 → 6.0.0.b1

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 (269) 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 +80 -25
  7. data/Gemfile +4 -2
  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/admin.scss +1 -1
  23. data/app/assets/stylesheets/alchemy/archive.scss +4 -4
  24. data/app/assets/stylesheets/alchemy/buttons.scss +0 -4
  25. data/app/assets/stylesheets/alchemy/elements.scss +73 -61
  26. data/app/assets/stylesheets/alchemy/images.scss +8 -0
  27. data/app/assets/stylesheets/alchemy/node-select.scss +4 -3
  28. data/app/assets/stylesheets/alchemy/page-select.scss +1 -0
  29. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +6 -6
  30. data/app/controllers/alchemy/admin/attachments_controller.rb +6 -2
  31. data/app/controllers/alchemy/admin/base_controller.rb +5 -7
  32. data/app/controllers/alchemy/admin/elements_controller.rb +58 -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 +6 -13
  40. data/app/controllers/alchemy/admin/pictures_controller.rb +35 -9
  41. data/app/controllers/alchemy/api/elements_controller.rb +10 -5
  42. data/app/controllers/alchemy/api/pages_controller.rb +2 -4
  43. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +13 -3
  44. data/app/controllers/concerns/alchemy/admin/crop_action.rb +26 -0
  45. data/app/decorators/alchemy/element_editor.rb +23 -1
  46. data/app/decorators/alchemy/ingredient_editor.rb +154 -0
  47. data/app/helpers/alchemy/admin/elements_helper.rb +1 -0
  48. data/app/helpers/alchemy/admin/essences_helper.rb +1 -1
  49. data/app/helpers/alchemy/admin/ingredients_helper.rb +42 -0
  50. data/app/helpers/alchemy/elements_block_helper.rb +22 -7
  51. data/app/helpers/alchemy/elements_helper.rb +12 -5
  52. data/app/helpers/alchemy/pages_helper.rb +3 -11
  53. data/app/jobs/alchemy/base_job.rb +11 -0
  54. data/app/jobs/alchemy/publish_page_job.rb +11 -0
  55. data/app/models/alchemy/attachment.rb +1 -1
  56. data/app/models/alchemy/content/factory.rb +23 -27
  57. data/app/models/alchemy/content.rb +1 -6
  58. data/app/models/alchemy/element/definitions.rb +29 -27
  59. data/app/models/alchemy/element/element_contents.rb +131 -122
  60. data/app/models/alchemy/element/element_essences.rb +100 -98
  61. data/app/models/alchemy/element/element_ingredients.rb +176 -0
  62. data/app/models/alchemy/element/presenters.rb +89 -87
  63. data/app/models/alchemy/element.rb +40 -73
  64. data/app/models/alchemy/elements_repository.rb +126 -0
  65. data/app/models/alchemy/essence_audio.rb +12 -0
  66. data/app/models/alchemy/essence_headline.rb +40 -0
  67. data/app/models/alchemy/essence_picture.rb +4 -116
  68. data/app/models/alchemy/essence_richtext.rb +12 -0
  69. data/app/models/alchemy/essence_video.rb +12 -0
  70. data/app/models/alchemy/image_cropper_settings.rb +87 -0
  71. data/app/models/alchemy/ingredient.rb +219 -0
  72. data/app/models/alchemy/ingredient_validator.rb +97 -0
  73. data/app/models/alchemy/ingredients/audio.rb +29 -0
  74. data/app/models/alchemy/ingredients/boolean.rb +21 -0
  75. data/app/models/alchemy/ingredients/datetime.rb +20 -0
  76. data/app/models/alchemy/ingredients/file.rb +30 -0
  77. data/app/models/alchemy/ingredients/headline.rb +42 -0
  78. data/app/models/alchemy/ingredients/html.rb +19 -0
  79. data/app/models/alchemy/ingredients/link.rb +16 -0
  80. data/app/models/alchemy/ingredients/node.rb +23 -0
  81. data/app/models/alchemy/ingredients/page.rb +23 -0
  82. data/app/models/alchemy/ingredients/picture.rb +41 -0
  83. data/app/models/alchemy/ingredients/richtext.rb +57 -0
  84. data/app/models/alchemy/ingredients/select.rb +10 -0
  85. data/app/models/alchemy/ingredients/text.rb +17 -0
  86. data/app/models/alchemy/ingredients/video.rb +33 -0
  87. data/app/models/alchemy/language.rb +0 -11
  88. data/app/models/alchemy/node.rb +1 -1
  89. data/app/models/alchemy/page/fixed_attributes.rb +53 -51
  90. data/app/models/alchemy/page/page_elements.rb +186 -205
  91. data/app/models/alchemy/page/page_naming.rb +66 -64
  92. data/app/models/alchemy/page/page_natures.rb +139 -142
  93. data/app/models/alchemy/page/page_scopes.rb +113 -102
  94. data/app/models/alchemy/page/publisher.rb +50 -0
  95. data/app/models/alchemy/page/url_path.rb +1 -1
  96. data/app/models/alchemy/page.rb +67 -33
  97. data/app/models/alchemy/page_version.rb +58 -0
  98. data/app/models/alchemy/picture/calculations.rb +2 -8
  99. data/app/models/alchemy/picture/preprocessor.rb +2 -0
  100. data/app/models/alchemy/picture/transformations.rb +24 -96
  101. data/app/models/alchemy/picture.rb +4 -2
  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 +1 -2
  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/crop.html.erb +36 -0
  113. data/app/views/alchemy/admin/elements/_element.html.erb +14 -10
  114. data/app/views/alchemy/admin/elements/{_element_footer.html.erb → _footer.html.erb} +0 -0
  115. data/app/views/alchemy/admin/elements/{_new_element_form.html.erb → _form.html.erb} +1 -1
  116. data/app/views/alchemy/admin/elements/{_element_header.html.erb → _header.html.erb} +1 -1
  117. data/app/views/alchemy/admin/elements/{_element_toolbar.html.erb → _toolbar.html.erb} +5 -6
  118. data/app/views/alchemy/admin/elements/{trash.js.erb → destroy.js.erb} +1 -3
  119. data/app/views/alchemy/admin/elements/new.html.erb +3 -3
  120. data/app/views/alchemy/admin/elements/order.js.erb +0 -17
  121. data/app/views/alchemy/admin/elements/update.js.erb +3 -2
  122. data/app/views/alchemy/admin/essence_audios/edit.html.erb +7 -0
  123. data/app/views/alchemy/admin/essence_pictures/update.js.erb +0 -1
  124. data/app/views/alchemy/admin/essence_videos/edit.html.erb +11 -0
  125. data/app/views/alchemy/admin/ingredients/_audio_fields.html.erb +4 -0
  126. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +18 -0
  127. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +25 -0
  128. data/app/views/alchemy/admin/ingredients/_video_fields.html.erb +8 -0
  129. data/app/views/alchemy/admin/ingredients/edit.html.erb +4 -0
  130. data/app/views/alchemy/admin/layoutpages/edit.html.erb +0 -5
  131. data/app/views/alchemy/admin/nodes/_node.html.erb +2 -2
  132. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +1 -1
  133. data/app/views/alchemy/admin/pages/_external_link.html.erb +1 -1
  134. data/app/views/alchemy/admin/pages/_file_link.html.erb +1 -1
  135. data/app/views/alchemy/admin/pages/_form.html.erb +0 -6
  136. data/app/views/alchemy/admin/pages/_internal_link.html.erb +1 -1
  137. data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +5 -2
  138. data/app/views/alchemy/admin/pages/edit.html.erb +36 -24
  139. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +2 -4
  140. data/app/views/alchemy/admin/partials/_routes.html.erb +7 -11
  141. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +4 -8
  142. data/app/views/alchemy/admin/pictures/_infos.html.erb +0 -1
  143. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +4 -4
  144. data/app/views/alchemy/admin/pictures/assign.js.erb +10 -0
  145. data/app/views/alchemy/admin/resources/_form.html.erb +1 -0
  146. data/app/views/alchemy/essences/_essence_audio_editor.html.erb +4 -0
  147. data/app/views/alchemy/essences/_essence_audio_view.html.erb +15 -0
  148. data/app/views/alchemy/essences/_essence_file_editor.html.erb +15 -6
  149. data/app/views/alchemy/essences/_essence_headline_editor.html.erb +36 -0
  150. data/app/views/alchemy/essences/_essence_headline_view.html.erb +10 -0
  151. data/app/views/alchemy/essences/_essence_link_editor.html.erb +8 -4
  152. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +27 -12
  153. data/app/views/alchemy/essences/_essence_text_editor.html.erb +12 -4
  154. data/app/views/alchemy/essences/_essence_video_editor.html.erb +4 -0
  155. data/app/views/alchemy/essences/_essence_video_view.html.erb +18 -0
  156. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +21 -16
  157. data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +2 -2
  158. data/app/views/alchemy/ingredients/_audio_editor.html.erb +5 -0
  159. data/app/views/alchemy/ingredients/_audio_view.html.erb +14 -0
  160. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +11 -0
  161. data/app/views/alchemy/ingredients/_boolean_view.html.erb +1 -0
  162. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +17 -0
  163. data/app/views/alchemy/ingredients/_datetime_view.html.erb +9 -0
  164. data/app/views/alchemy/ingredients/_file_editor.html.erb +50 -0
  165. data/app/views/alchemy/ingredients/_file_view.html.erb +17 -0
  166. data/app/views/alchemy/ingredients/_headline_editor.html.erb +30 -0
  167. data/app/views/alchemy/ingredients/_headline_view.html.erb +9 -0
  168. data/app/views/alchemy/ingredients/_html_editor.html.erb +8 -0
  169. data/app/views/alchemy/ingredients/_html_view.html.erb +1 -0
  170. data/app/views/alchemy/ingredients/_link_editor.html.erb +24 -0
  171. data/app/views/alchemy/ingredients/_link_view.html.erb +9 -0
  172. data/app/views/alchemy/ingredients/_node_editor.html.erb +25 -0
  173. data/app/views/alchemy/ingredients/_node_view.html.erb +1 -0
  174. data/app/views/alchemy/ingredients/_page_editor.html.erb +24 -0
  175. data/app/views/alchemy/ingredients/_page_view.html.erb +4 -0
  176. data/app/views/alchemy/ingredients/_picture_editor.html.erb +59 -0
  177. data/app/views/alchemy/ingredients/_picture_view.html.erb +5 -0
  178. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +12 -0
  179. data/app/views/alchemy/ingredients/_richtext_view.html.erb +3 -0
  180. data/app/views/alchemy/ingredients/_select_editor.html.erb +29 -0
  181. data/app/views/alchemy/ingredients/_select_view.html.erb +1 -0
  182. data/app/views/alchemy/ingredients/_text_editor.html.erb +19 -0
  183. data/app/views/alchemy/ingredients/_text_view.html.erb +16 -0
  184. data/app/views/alchemy/ingredients/_video_editor.html.erb +5 -0
  185. data/app/views/alchemy/ingredients/_video_view.html.erb +17 -0
  186. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +20 -0
  187. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +57 -0
  188. data/config/brakeman.ignore +66 -159
  189. data/config/initializers/dragonfly.rb +10 -0
  190. data/config/locales/alchemy.en.yml +23 -15
  191. data/config/routes.rb +17 -22
  192. data/db/migrate/20201207131309_create_page_versions.rb +19 -0
  193. data/db/migrate/20201207135820_add_page_version_id_to_alchemy_elements.rb +76 -0
  194. data/db/migrate/20210205143548_rename_public_on_and_public_until_on_alchemy_pages.rb +10 -0
  195. data/db/migrate/20210326105046_add_sanitized_body_to_alchemy_essence_richtexts.rb +7 -0
  196. data/db/migrate/20210406093436_add_alchemy_essence_headlines.rb +12 -0
  197. data/db/migrate/20210506135919_create_essence_audios.rb +19 -0
  198. data/db/migrate/20210506140258_create_essence_videos.rb +23 -0
  199. data/db/migrate/20210508091432_create_alchemy_ingredients.rb +22 -0
  200. data/lib/alchemy/admin/preview_url.rb +2 -0
  201. data/lib/alchemy/deprecation.rb +1 -1
  202. data/lib/alchemy/dragonfly/processors/auto_orient.rb +18 -0
  203. data/lib/alchemy/dragonfly/processors/crop_resize.rb +35 -0
  204. data/lib/alchemy/elements_finder.rb +14 -60
  205. data/lib/alchemy/engine.rb +1 -1
  206. data/lib/alchemy/essence.rb +1 -2
  207. data/lib/alchemy/hints.rb +8 -4
  208. data/lib/alchemy/page_layout.rb +0 -13
  209. data/lib/alchemy/permissions.rb +30 -29
  210. data/lib/alchemy/resource.rb +13 -3
  211. data/lib/alchemy/tasks/tidy.rb +29 -0
  212. data/lib/alchemy/test_support/essence_shared_examples.rb +0 -1
  213. data/lib/alchemy/test_support/factories/element_factory.rb +8 -8
  214. data/lib/alchemy/test_support/factories/essence_audio_factory.rb +7 -0
  215. data/lib/alchemy/test_support/factories/essence_video_factory.rb +7 -0
  216. data/lib/alchemy/test_support/factories/ingredient_factory.rb +25 -0
  217. data/lib/alchemy/test_support/factories/page_factory.rb +20 -1
  218. data/lib/alchemy/test_support/factories/page_version_factory.rb +23 -0
  219. data/lib/alchemy/test_support/having_crop_action_examples.rb +170 -0
  220. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +646 -0
  221. data/lib/alchemy/test_support/shared_ingredient_editor_examples.rb +21 -0
  222. data/lib/alchemy/test_support/shared_ingredient_examples.rb +57 -0
  223. data/lib/alchemy/test_support.rb +2 -11
  224. data/lib/alchemy/tinymce.rb +17 -0
  225. data/lib/alchemy/upgrader/five_point_zero.rb +0 -32
  226. data/lib/alchemy/upgrader/six_point_zero.rb +21 -0
  227. data/lib/alchemy/upgrader/tasks/add_page_versions.rb +33 -0
  228. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +51 -0
  229. data/lib/alchemy/version.rb +1 -1
  230. data/lib/generators/alchemy/elements/elements_generator.rb +1 -0
  231. data/lib/generators/alchemy/elements/templates/view.html.erb +9 -0
  232. data/lib/generators/alchemy/elements/templates/view.html.haml +9 -0
  233. data/lib/generators/alchemy/elements/templates/view.html.slim +9 -0
  234. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +38 -0
  235. data/lib/generators/alchemy/ingredient/templates/editor.html.erb +14 -0
  236. data/lib/generators/alchemy/ingredient/templates/model.rb.tt +13 -0
  237. data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -0
  238. data/lib/generators/alchemy/install/install_generator.rb +1 -2
  239. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +1 -1
  240. data/lib/generators/alchemy/menus/templates/node.html.erb +1 -1
  241. data/lib/generators/alchemy/menus/templates/node.html.haml +1 -1
  242. data/lib/generators/alchemy/menus/templates/node.html.slim +1 -1
  243. data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
  244. data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
  245. data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
  246. data/lib/tasks/alchemy/tidy.rake +12 -0
  247. data/lib/tasks/alchemy/upgrade.rake +21 -15
  248. data/package/admin.js +9 -1
  249. data/package/src/file_editors.js +28 -0
  250. data/package/src/image_cropper.js +103 -0
  251. data/package/src/image_loader.js +58 -0
  252. data/package/src/node_tree.js +5 -5
  253. data/package/src/picture_editors.js +169 -0
  254. data/package/src/utils/__tests__/ajax.spec.js +20 -12
  255. data/package/src/utils/ajax.js +8 -3
  256. data/package.json +3 -2
  257. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +3 -18
  258. data/vendor/assets/stylesheets/jquery.Jcrop.min.scss +2 -28
  259. metadata +285 -56
  260. data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +0 -44
  261. data/app/assets/javascripts/alchemy/alchemy.trash_window.js.coffee +0 -30
  262. data/app/assets/stylesheets/alchemy/trash.scss +0 -8
  263. data/app/controllers/alchemy/admin/trash_controller.rb +0 -44
  264. data/app/views/alchemy/admin/essence_files/assign.js.erb +0 -3
  265. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -4
  266. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +0 -48
  267. data/app/views/alchemy/admin/trash/clear.js.erb +0 -4
  268. data/app/views/alchemy/admin/trash/index.html.erb +0 -31
  269. data/lib/alchemy/test_support/factories.rb +0 -20
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A text headline
6
+ #
7
+ class Headline < Alchemy::Ingredient
8
+ store_accessor :data,
9
+ :level,
10
+ :size
11
+
12
+ before_create :set_level_and_size
13
+
14
+ def preview_text(maxlength = 30)
15
+ "H#{level}: #{value}"[0..maxlength - 1]
16
+ end
17
+
18
+ def level_options
19
+ levels.map { |level| ["H#{level}", level] }
20
+ end
21
+
22
+ def size_options
23
+ sizes.map { |size| ["H#{size}", size] }
24
+ end
25
+
26
+ private
27
+
28
+ def levels
29
+ settings.fetch(:levels, (1..6))
30
+ end
31
+
32
+ def sizes
33
+ settings.fetch(:sizes, [])
34
+ end
35
+
36
+ def set_level_and_size
37
+ self.level ||= levels.first
38
+ self.size ||= sizes.first
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A HTML string
6
+ #
7
+ class Html < Alchemy::Ingredient
8
+ # The first 30 escaped characters from value
9
+ #
10
+ # Used by the Element#preview_text method.
11
+ #
12
+ # @param [Integer] max_length (30)
13
+ #
14
+ def preview_text(max_length = 30)
15
+ ::CGI.escapeHTML(value.to_s)[0..max_length - 1]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A URL
6
+ #
7
+ class Link < Alchemy::Ingredient
8
+ store_accessor :data,
9
+ :link_class_name,
10
+ :link_target,
11
+ :link_title
12
+
13
+ alias_method :link, :value
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A link to a menu node
6
+ #
7
+ # Assign Alchemy::Node to this ingredient
8
+ #
9
+ class Node < Alchemy::Ingredient
10
+ related_object_alias :node, class_name: "Alchemy::Node"
11
+
12
+ # The first 30 characters of node name
13
+ #
14
+ # Used by the Element#preview_text method.
15
+ #
16
+ # @param [Integer] max_length (30)
17
+ #
18
+ def preview_text(max_length = 30)
19
+ node&.name.to_s[0..max_length - 1]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A link to a page
6
+ #
7
+ # Assign Alchemy::Page to this ingredient
8
+ #
9
+ class Page < Alchemy::Ingredient
10
+ related_object_alias :page, class_name: "Alchemy::Page"
11
+
12
+ # The first 30 characters of page name
13
+ #
14
+ # Used by the Element#preview_text method.
15
+ #
16
+ # @param [Integer] max_length (30)
17
+ #
18
+ def preview_text(max_length = 30)
19
+ page&.name.to_s[0..max_length - 1]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A picture assignment
6
+ #
7
+ # Assign Alchemy::Picture to this ingredient
8
+ #
9
+ # Optionally you can add a link
10
+ # As well as set the alt tag, a caption and title
11
+ #
12
+ class Picture < Alchemy::Ingredient
13
+ include Alchemy::PictureThumbnails
14
+
15
+ store_accessor :data,
16
+ :alt_tag,
17
+ :caption,
18
+ :crop_from,
19
+ :crop_size,
20
+ :css_class,
21
+ :link_class_name,
22
+ :link_target,
23
+ :link_title,
24
+ :link,
25
+ :render_size,
26
+ :title
27
+
28
+ related_object_alias :picture, class_name: "Alchemy::Picture"
29
+
30
+ # The first 30 characters of the pictures name
31
+ #
32
+ # Used by the Element#preview_text method.
33
+ #
34
+ # @param [Integer] max_length (30)
35
+ #
36
+ def preview_text(max_length = 30)
37
+ picture&.name.to_s[0..max_length - 1]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A blob of richtext
6
+ #
7
+ class Richtext < Alchemy::Ingredient
8
+ store_accessor :data,
9
+ :stripped_body,
10
+ :sanitized_body
11
+
12
+ before_save :strip_content
13
+ before_save :sanitize_content
14
+
15
+ # The first 30 characters of the stripped_body
16
+ #
17
+ # Used by the Element#preview_text method.
18
+ #
19
+ # @param [Integer] max_length (30)
20
+ #
21
+ def preview_text(max_length = 30)
22
+ stripped_body.to_s[0..max_length - 1]
23
+ end
24
+
25
+ # Returns css class names for the editor textarea.
26
+ def tinymce_class_name
27
+ "has_tinymce#{has_custom_tinymce_config? ? " #{element.name}_#{role}" : ""}"
28
+ end
29
+
30
+ def has_tinymce?
31
+ true
32
+ end
33
+
34
+ private
35
+
36
+ def strip_content
37
+ self.stripped_body = Rails::Html::FullSanitizer.new.sanitize(value)
38
+ end
39
+
40
+ def sanitize_content
41
+ self.sanitized_body = Rails::Html::SafeListSanitizer.new.sanitize(
42
+ value,
43
+ sanitizer_settings
44
+ )
45
+ end
46
+
47
+ def sanitizer_settings
48
+ settings[:sanitizer] || {}
49
+ end
50
+
51
+ # Returns true if there is a tinymce setting defined that contains settings.
52
+ def has_custom_tinymce_config?
53
+ settings[:tinymce].is_a?(Hash)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A text value from a select box
6
+ #
7
+ class Select < Alchemy::Ingredient
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A simple line of text
6
+ #
7
+ # Optionally it can have a link
8
+ #
9
+ class Text < Alchemy::Ingredient
10
+ store_accessor :data,
11
+ :link,
12
+ :link_target,
13
+ :link_title,
14
+ :link_class_name
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ # A video attachment
6
+ #
7
+ class Video < Alchemy::Ingredient
8
+ store_accessor :data,
9
+ :allow_fullscreen,
10
+ :autoplay,
11
+ :controls,
12
+ :height,
13
+ :loop,
14
+ :muted,
15
+ :preload,
16
+ :width
17
+
18
+ related_object_alias :attachment, class_name: "Alchemy::Attachment"
19
+
20
+ delegate :name, to: :attachment, allow_nil: true
21
+
22
+ # The first 30 characters of the attachments name
23
+ #
24
+ # Used by the Element#preview_text method.
25
+ #
26
+ # @param [Integer] max_length (30)
27
+ #
28
+ def preview_text(max_length = 30)
29
+ name.to_s[0..max_length - 1]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -54,9 +54,6 @@ module Alchemy
54
54
  after_update :set_pages_language,
55
55
  if: :should_set_pages_language?
56
56
 
57
- after_update :unpublish_pages,
58
- if: :should_unpublish_pages?
59
-
60
57
  before_destroy if: -> { pages.any? } do
61
58
  errors.add(:pages, :still_present)
62
59
  throw(:abort)
@@ -170,13 +167,5 @@ module Alchemy
170
167
  def set_pages_language
171
168
  pages.update_all language_code: code
172
169
  end
173
-
174
- def should_unpublish_pages?
175
- saved_changes[:public] == [true, false]
176
- end
177
-
178
- def unpublish_pages
179
- pages.update_all(public_on: nil, public_until: nil)
180
- end
181
170
  end
182
171
  end
@@ -7,7 +7,7 @@ module Alchemy
7
7
  before_destroy :check_if_related_essence_nodes_present
8
8
 
9
9
  acts_as_nested_set scope: "language_id", touch: true
10
- stampable stamper_class_name: Alchemy.user_class.name
10
+ stampable stamper_class_name: Alchemy.user_class_name
11
11
 
12
12
  belongs_to :language, class_name: "Alchemy::Language"
13
13
  belongs_to :page, class_name: "Alchemy::Page", optional: true, inverse_of: :nodes
@@ -1,66 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- # = Fixed page attributes
5
- #
6
- # Fixed page attributes are not allowed to be changed by the user.
7
- #
8
- # Define fixed page attributes on the page layout definition of a page.
9
- #
10
- # == Example
11
- #
12
- # # page_layout.yml
13
- # - name: Index
14
- # unique: true
15
- # fixed_attributes:
16
- # - public_on: nil
17
- # - public_until: nil
18
- #
19
- class Page::FixedAttributes
20
- attr_reader :page
21
-
22
- def initialize(page)
23
- @page = page
24
- end
25
-
26
- # All fixed attributes defined on page
4
+ class Page < BaseRecord
5
+ # = Fixed page attributes
27
6
  #
28
- # Aliased as +#all+
7
+ # Fixed page attributes are not allowed to be changed by the user.
29
8
  #
30
- # @return Hash
9
+ # Define fixed page attributes on the page layout definition of a page.
31
10
  #
32
- def attributes
33
- @_attributes ||= page.definition.fetch("fixed_attributes", {}).symbolize_keys
34
- end
35
- alias_method :all, :attributes
36
-
37
- # True if fixed attributes are defined on page
38
- #
39
- # Aliased as +#present?+
11
+ # == Example
40
12
  #
41
- # @return Boolean
13
+ # # page_layout.yml
14
+ # - name: Index
15
+ # unique: true
16
+ # fixed_attributes:
17
+ # - public_on: nil
18
+ # - public_until: nil
42
19
  #
43
- def any?
44
- attributes.present?
45
- end
46
- alias_method :present?, :any?
20
+ class FixedAttributes
21
+ attr_reader :page
47
22
 
48
- # True if given attribute name is defined on page
49
- #
50
- # @return Boolean
51
- #
52
- def fixed?(name)
53
- return false if name.nil?
23
+ def initialize(page)
24
+ @page = page
25
+ end
54
26
 
55
- attributes.key?(name.to_sym)
56
- end
27
+ # All fixed attributes defined on page
28
+ #
29
+ # Aliased as +#all+
30
+ #
31
+ # @return Hash
32
+ #
33
+ def attributes
34
+ @_attributes ||= page.definition.fetch("fixed_attributes", {}).symbolize_keys
35
+ end
36
+ alias_method :all, :attributes
57
37
 
58
- # Returns the attribute by key
59
- #
60
- def [](name)
61
- return nil if name.nil?
38
+ # True if fixed attributes are defined on page
39
+ #
40
+ # Aliased as +#present?+
41
+ #
42
+ # @return Boolean
43
+ #
44
+ def any?
45
+ attributes.present?
46
+ end
47
+ alias_method :present?, :any?
48
+
49
+ # True if given attribute name is defined on page
50
+ #
51
+ # @return Boolean
52
+ #
53
+ def fixed?(name)
54
+ return false if name.nil?
55
+
56
+ attributes.key?(name.to_sym)
57
+ end
58
+
59
+ # Returns the attribute by key
60
+ #
61
+ def [](name)
62
+ return nil if name.nil?
62
63
 
63
- attributes[name.to_sym]
64
+ attributes[name.to_sym]
65
+ end
64
66
  end
65
67
  end
66
68
  end