alchemy_cms 4.3.2 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +92 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +59 -2
  5. data/Gemfile +6 -5
  6. data/README.md +7 -6
  7. data/alchemy_cms.gemspec +4 -2
  8. data/app/assets/config/alchemy_manifest.js +15 -0
  9. data/app/assets/javascripts/alchemy/admin.js +1 -0
  10. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +1 -13
  11. data/app/assets/javascripts/alchemy/alchemy.i18n.js.coffee +1 -1
  12. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +84 -87
  13. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +0 -4
  14. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +1 -1
  15. data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +2 -2
  16. data/app/assets/javascripts/alchemy/page_select.js +41 -0
  17. data/app/assets/javascripts/alchemy/templates/index.js +1 -0
  18. data/app/assets/javascripts/alchemy/templates/page.hbs +9 -0
  19. data/app/assets/stylesheets/alchemy/_mixins.scss +11 -1
  20. data/app/assets/stylesheets/alchemy/admin.scss +3 -0
  21. data/app/assets/stylesheets/alchemy/elements.scss +1 -0
  22. data/app/assets/stylesheets/alchemy/forms.scss +6 -5
  23. data/app/assets/stylesheets/alchemy/labels.scss +6 -0
  24. data/app/assets/stylesheets/alchemy/nodes.scss +154 -0
  25. data/app/assets/stylesheets/alchemy/page-select.scss +30 -0
  26. data/app/assets/stylesheets/alchemy/selects.scss +39 -22
  27. data/app/assets/stylesheets/alchemy/sitemap.scss +0 -33
  28. data/app/assets/stylesheets/alchemy/tags.scss +0 -3
  29. data/app/controllers/alchemy/admin/base_controller.rb +1 -0
  30. data/app/controllers/alchemy/admin/elements_controller.rb +24 -11
  31. data/app/controllers/alchemy/admin/languages_controller.rb +5 -0
  32. data/app/controllers/alchemy/admin/nodes_controller.rb +43 -0
  33. data/app/controllers/alchemy/admin/pages_controller.rb +1 -21
  34. data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
  35. data/app/controllers/alchemy/admin/tags_controller.rb +1 -2
  36. data/app/controllers/alchemy/api/contents_controller.rb +17 -2
  37. data/app/controllers/alchemy/api/elements_controller.rb +26 -1
  38. data/app/controllers/alchemy/api/pages_controller.rb +78 -7
  39. data/app/controllers/alchemy/messages_controller.rb +23 -8
  40. data/app/helpers/alchemy/admin/contents_helper.rb +1 -1
  41. data/app/helpers/alchemy/admin/elements_helper.rb +6 -0
  42. data/app/helpers/alchemy/admin/essences_helper.rb +23 -4
  43. data/app/helpers/alchemy/elements_block_helper.rb +11 -3
  44. data/app/helpers/alchemy/elements_helper.rb +3 -3
  45. data/app/helpers/alchemy/essences_helper.rb +36 -9
  46. data/app/helpers/alchemy/pages_helper.rb +29 -0
  47. data/app/models/alchemy/content.rb +1 -1
  48. data/app/models/alchemy/element.rb +20 -8
  49. data/app/models/alchemy/element/element_contents.rb +6 -4
  50. data/app/models/alchemy/element/presenters.rb +2 -2
  51. data/app/models/alchemy/essence_page.rb +29 -0
  52. data/app/models/alchemy/essence_picture.rb +8 -3
  53. data/app/models/alchemy/language.rb +10 -2
  54. data/app/models/alchemy/node.rb +48 -0
  55. data/app/models/alchemy/page.rb +74 -3
  56. data/app/models/alchemy/page/page_elements.rb +12 -4
  57. data/app/models/alchemy/page/page_natures.rb +6 -0
  58. data/app/models/alchemy/page/page_scopes.rb +1 -1
  59. data/app/models/alchemy/picture.rb +5 -1
  60. data/app/models/concerns/alchemy/content_touching.rb +1 -1
  61. data/app/serializers/alchemy/element_serializer.rb +7 -1
  62. data/app/serializers/alchemy/page_serializer.rb +0 -4
  63. data/app/views/alchemy/_menubar.html.erb +1 -1
  64. data/app/views/alchemy/admin/elements/_element.html.erb +18 -2
  65. data/app/views/alchemy/admin/leave.html.erb +1 -1
  66. data/app/views/alchemy/admin/nodes/_form.html.erb +39 -0
  67. data/app/views/alchemy/admin/nodes/_node.html.erb +87 -0
  68. data/app/views/alchemy/admin/nodes/edit.html.erb +1 -0
  69. data/app/views/alchemy/admin/nodes/index.html.erb +58 -0
  70. data/app/views/alchemy/admin/nodes/new.html.erb +1 -0
  71. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +22 -0
  72. data/app/views/alchemy/admin/pages/_form.html.erb +1 -1
  73. data/app/views/alchemy/admin/pages/_internal_link.html.erb +7 -11
  74. data/app/views/alchemy/admin/pages/_menu_fields.html.erb +33 -0
  75. data/app/views/alchemy/admin/pages/_sitemap.html.erb +0 -7
  76. data/app/views/alchemy/admin/pages/link.html.erb +4 -0
  77. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +7 -3
  78. data/app/views/alchemy/admin/partials/_routes.html.erb +3 -3
  79. data/app/views/alchemy/essences/_essence_boolean_view.html.erb +1 -0
  80. data/app/views/alchemy/essences/_essence_date_view.html.erb +1 -0
  81. data/app/views/alchemy/essences/_essence_file_view.html.erb +1 -0
  82. data/app/views/alchemy/essences/_essence_html_view.html.erb +1 -0
  83. data/app/views/alchemy/essences/_essence_link_view.html.erb +1 -0
  84. data/app/views/alchemy/essences/_essence_page_editor.html.erb +23 -0
  85. data/app/views/alchemy/essences/_essence_page_view.html.erb +5 -0
  86. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +2 -0
  87. data/app/views/alchemy/essences/_essence_picture_view.html.erb +1 -0
  88. data/app/views/alchemy/essences/_essence_richtext_view.html.erb +1 -0
  89. data/app/views/alchemy/essences/_essence_select_editor.html.erb +1 -0
  90. data/app/views/alchemy/essences/_essence_select_view.html.erb +1 -0
  91. data/app/views/alchemy/essences/_essence_text_editor.html.erb +3 -0
  92. data/app/views/alchemy/essences/_essence_text_view.html.erb +1 -0
  93. data/config/alchemy/modules.yml +13 -4
  94. data/config/initializers/assets.rb +1 -13
  95. data/config/locales/alchemy.en.yml +27 -9
  96. data/config/routes.rb +11 -3
  97. data/db/migrate/20191016073858_create_alchemy_essence_pages.rb +8 -0
  98. data/db/migrate/20191029212236_create_alchemy_nodes.rb +24 -0
  99. data/lib/alchemy/admin/locale.rb +1 -1
  100. data/lib/alchemy/auth_accessors.rb +8 -2
  101. data/lib/alchemy/cache_digests/template_tracker.rb +8 -5
  102. data/lib/alchemy/elements_finder.rb +17 -14
  103. data/lib/alchemy/engine.rb +4 -0
  104. data/lib/alchemy/essence.rb +40 -2
  105. data/lib/alchemy/permissions.rb +2 -0
  106. data/lib/alchemy/tasks/tidy.rb +1 -1
  107. data/lib/alchemy/test_support/essence_shared_examples.rb +25 -8
  108. data/lib/alchemy/test_support/factories/essence_page_factory.rb +10 -0
  109. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +5 -0
  110. data/lib/alchemy/test_support/factories/node_factory.rb +21 -0
  111. data/lib/alchemy/version.rb +1 -1
  112. data/lib/rails/generators/alchemy/elements/elements_generator.rb +0 -1
  113. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +3 -3
  114. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +3 -3
  115. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +3 -3
  116. data/lib/rails/generators/alchemy/install/files/{_article_view.html.erb → _article.html.erb} +2 -2
  117. data/lib/rails/generators/alchemy/install/files/application.html.erb +13 -10
  118. data/lib/rails/generators/alchemy/install/install_generator.rb +2 -11
  119. data/lib/rails/generators/alchemy/menus/menus_generator.rb +24 -0
  120. data/lib/rails/generators/alchemy/menus/templates/node.html.erb +19 -0
  121. data/lib/rails/generators/alchemy/menus/templates/node.html.haml +16 -0
  122. data/lib/rails/generators/alchemy/menus/templates/node.html.slim +16 -0
  123. data/lib/rails/generators/alchemy/menus/templates/wrapper.html.erb +8 -0
  124. data/lib/rails/generators/alchemy/menus/templates/wrapper.html.haml +6 -0
  125. data/lib/rails/generators/alchemy/menus/templates/wrapper.html.slim +6 -0
  126. data/lib/rails/generators/alchemy/views/views_generator.rb +1 -1
  127. data/lib/tasks/alchemy/convert.rake +60 -0
  128. metadata +79 -20
  129. data/.rspec +0 -1
  130. data/.travis.yml +0 -28
  131. data/app/models/alchemy/page/page_users.rb +0 -60
  132. data/app/views/alchemy/admin/elements/list.html.erb +0 -16
  133. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +0 -53
  134. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +0 -9
  135. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +0 -8
  136. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +0 -8
  137. data/lib/rails/generators/alchemy/install/files/_article_editor.html.erb +0 -5
  138. data/lib/rails/generators/alchemy/install/files/alchemy.de.yml +0 -31
  139. data/lib/rails/generators/alchemy/install/files/alchemy.es.yml +0 -31
@@ -38,7 +38,7 @@ module Alchemy
38
38
 
39
39
  # Renders the label and a remove link for a content.
40
40
  def content_label(content)
41
- content_tag :label do
41
+ content_tag :label, for: content.form_field_id do
42
42
  [render_hint_for(content), render_content_name(content)].compact.join(' ').html_safe
43
43
  end
44
44
  end
@@ -48,12 +48,18 @@ module Alchemy
48
48
  # @note If the partial is not found
49
49
  # <tt>alchemy/elements/_editor_not_found.html.erb</tt> gets rendered.
50
50
  #
51
+ # @deprecated Using element editor partials is deprecated and will be removed in Alchemy 5.0
51
52
  def render_editor(element)
52
53
  if element.nil?
53
54
  warning('Element is nil')
54
55
  render "alchemy/elements/editor_not_found", {name: 'nil'}
55
56
  return
56
57
  end
58
+ Alchemy::Deprecation.warn <<~WARN
59
+ Using element editor partials is deprecated and will be removed in Alchemy 5.0.
60
+ You can delete the `app/views/alchemy/elements/_#{element.name}_editor` partial
61
+ and Alchemy will render the content editors for you.
62
+ WARN
57
63
 
58
64
  render "alchemy/elements/#{element.name}_editor", element: element
59
65
  rescue ActionView::MissingTemplate => e
@@ -8,9 +8,23 @@ module Alchemy
8
8
 
9
9
  # Renders the Content editor partial from the given Content.
10
10
  # For options see -> render_essence
11
+ # @deprecated
11
12
  def render_essence_editor(content, options = {}, html_options = {})
13
+ if !options.empty?
14
+ Alchemy::Deprecation.warn <<~WARN
15
+ Passing options to `render_essence_editor` is deprecated and will be removed from Alchemy 5.0.
16
+ Add your static `#{options.keys}` options to the `#{content.name}` content definitions `settings` of `#{content.element&.name}` element.
17
+ For dynamic options consider adding your own essence class.
18
+ WARN
19
+ end
20
+ if !html_options.empty?
21
+ Alchemy::Deprecation.warn <<~WARN
22
+ Passing html_options to `render_essence_editor` is deprecated and will be removed in Alchemy 5.0 without replacement.
23
+ WARN
24
+ end
12
25
  render_essence(content, :editor, {for_editor: options}, html_options)
13
26
  end
27
+ deprecate :render_essence_editor, deprecator: Alchemy::Deprecation
14
28
 
15
29
  # Renders the Content editor partial found in views/contents/ for the content with name inside the passed Element.
16
30
  # For options see -> render_essence
@@ -18,7 +32,7 @@ module Alchemy
18
32
  # Content creation on the fly:
19
33
  #
20
34
  # If you update the elements.yml file after creating an element this helper displays a error message with an option to create the content.
21
- #
35
+ # @deprecated
22
36
  def render_essence_editor_by_name(element, name, options = {}, html_options = {})
23
37
  if element.blank?
24
38
  return warning('Element is nil', Alchemy.t(:no_element_given))
@@ -30,6 +44,7 @@ module Alchemy
30
44
  render_essence_editor(content, options, html_options)
31
45
  end
32
46
  end
47
+ deprecate :render_essence_editor_by_name, deprecator: Alchemy::Deprecation
33
48
 
34
49
  # Returns all public pages from current language as an option tags string suitable or the Rails +select_tag+ helper.
35
50
  #
@@ -41,7 +56,7 @@ module Alchemy
41
56
  # Used as prompt message in the select tag
42
57
  # @param [Symbol]
43
58
  # Method that is called on the page object to get the value that is passed with the params of the form.
44
- #
59
+ # @deprecated
45
60
  def pages_for_select(pages = nil, selected = nil, prompt = "Choose page", page_attribute = :id)
46
61
  values = [[Alchemy.t(prompt), ""]]
47
62
  pages ||= begin
@@ -51,12 +66,14 @@ module Alchemy
51
66
  values += pages_attributes_for_select(pages, page_attribute, nested)
52
67
  options_for_select(values, selected.to_s)
53
68
  end
69
+ deprecate :pages_for_select, deprecator: Alchemy::Deprecation
54
70
 
55
71
  # Renders the missing content partial
56
- #
72
+ # @deprecated
57
73
  def render_missing_content(element, name, options)
58
74
  render 'alchemy/admin/contents/missing', {element: element, name: name, options: options}
59
75
  end
76
+ deprecate :render_missing_content, deprecator: Alchemy::Deprecation
60
77
 
61
78
  # Renders a thumbnail for given EssencePicture content with correct cropping and size
62
79
  def essence_picture_thumbnail(content, options = {})
@@ -101,6 +118,7 @@ module Alchemy
101
118
  ]
102
119
  end
103
120
  end
121
+ deprecate :pages_attributes_for_select, deprecator: Alchemy::Deprecation
104
122
 
105
123
  # Returns the page name for pages_for_select helper
106
124
  #
@@ -111,11 +129,12 @@ module Alchemy
111
129
  #
112
130
  def page_name_attribute_for_select(page, indent = false)
113
131
  if indent
114
- ("&nbsp;&nbsp;" * (page.level - 1) + page.name).html_safe
132
+ ("&nbsp;&nbsp;" * (page.depth - 1) + page.name).html_safe
115
133
  else
116
134
  page.name
117
135
  end
118
136
  end
137
+ deprecate :page_name_attribute_for_select, deprecator: Alchemy::Deprecation
119
138
  end
120
139
  end
121
140
  end
@@ -26,8 +26,15 @@ module Alchemy
26
26
  class ElementViewHelper < BlockHelper
27
27
  # Renders one of the element's contents.
28
28
  #
29
- def render(name, *args)
30
- helpers.render_essence_view_by_name(element, name.to_s, *args)
29
+ def render(name, options = {}, html_options = {})
30
+ content = element.content_by_name(name)
31
+ return if content.nil?
32
+
33
+ helpers.render(content, {
34
+ content: content,
35
+ options: options,
36
+ html_options: html_options
37
+ })
31
38
  end
32
39
 
33
40
  # Returns one of the element's contents (ie. essence instances).
@@ -56,11 +63,12 @@ module Alchemy
56
63
  end
57
64
 
58
65
  # Block-level helper class for element editors.
59
- #
66
+ # @deprecated
60
67
  class ElementEditorHelper < BlockHelper
61
68
  def edit(name, *args)
62
69
  helpers.render_essence_editor_by_name(element, name.to_s, *args)
63
70
  end
71
+ deprecate :edit, deprecator: Alchemy::Deprecation
64
72
  end
65
73
 
66
74
  # Block-level helper for element views. Constructs a DOM element wrapping
@@ -123,7 +123,7 @@ module Alchemy
123
123
  #
124
124
  # == View partial naming
125
125
  #
126
- # The partial has to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with <tt>_view</tt>.
126
+ # The partial has to be named after the name of the element as defined in the <tt>elements.yml</tt> file.
127
127
  #
128
128
  # === Example
129
129
  #
@@ -137,7 +137,7 @@ module Alchemy
137
137
  #
138
138
  # Then your element view partial has to be named like:
139
139
  #
140
- # app/views/alchemy/elements/_headline_view.html.{erb|haml|slim}
140
+ # app/views/alchemy/elements/_headline.html.{erb|haml|slim}
141
141
  #
142
142
  # === Element partials generator
143
143
  #
@@ -147,7 +147,7 @@ module Alchemy
147
147
  #
148
148
  # == Usage
149
149
  #
150
- # <%= render_element(Alchemy::Element.published.named(:headline).first) %>
150
+ # <%= render_element(Alchemy::Element.available.named(:headline).first) %>
151
151
  #
152
152
  # @param [Alchemy::Element] element
153
153
  # The element you want to render the view for
@@ -27,6 +27,7 @@ module Alchemy
27
27
  #
28
28
  # And the +render_essence_editor_by_name+ helper for Alchemy backend views.
29
29
  #
30
+ # @deprecated Use Rails' `render(content)` method directly instead
30
31
  module EssencesHelper
31
32
  # Renders the +Essence+ view partial from +Element+ by name.
32
33
  #
@@ -38,14 +39,22 @@ module Alchemy
38
39
  #
39
40
  # <%= render_essence_view_by_name(element, "intro") %>
40
41
  #
42
+ # @deprecated Use Rails' `render(content)` method directly instead
41
43
  def render_essence_view_by_name(element, name, options = {}, html_options = {})
42
44
  if element.blank?
43
- warning('Element is nil')
44
- return ""
45
+ warning('Element is nil') && return
45
46
  end
46
47
  content = element.content_by_name(name)
47
- render_essence_view(content, options, html_options)
48
+ return if content.nil?
49
+
50
+ render content, {
51
+ content: content,
52
+ options: options,
53
+ html_options: html_options
54
+ }
48
55
  end
56
+ deprecate render_essence_view_by_name: "Use Rails' `render(content)` method directly instead",
57
+ deprecator: Alchemy::Deprecation
49
58
 
50
59
  # Renders the +Esssence+ partial for given +Content+.
51
60
  #
@@ -62,6 +71,7 @@ module Alchemy
62
71
  # for_view: {}
63
72
  # for_editor: {}
64
73
  #
74
+ # @deprecated Use Rails' `render(content)` method directly instead
65
75
  def render_essence(content, part = :view, options = {}, html_options = {})
66
76
  options = {for_view: {}, for_editor: {}}.update(options)
67
77
  if content.nil?
@@ -69,12 +79,22 @@ module Alchemy
69
79
  elsif content.essence.nil?
70
80
  return part == :view ? "" : warning('Essence is nil', Alchemy.t(:content_essence_not_found))
71
81
  end
72
- render partial: "alchemy/essences/#{content.essence_partial_name}_#{part}", locals: {
73
- content: content,
74
- options: options["for_#{part}".to_sym],
75
- html_options: html_options
76
- }
82
+ if part == :view
83
+ render content, {
84
+ content: content,
85
+ options: options[:for_view],
86
+ html_options: html_options
87
+ }
88
+ else
89
+ render "alchemy/essences/#{content.essence_partial_name}_editor", {
90
+ content: content,
91
+ options: options,
92
+ html_options: html_options
93
+ }
94
+ end
77
95
  end
96
+ deprecate render_essence: "Use Rails' `render(content)` method directly instead",
97
+ deprecator: Alchemy::Deprecation
78
98
 
79
99
  # Renders the +Esssence+ view partial for given +Content+.
80
100
  #
@@ -85,8 +105,15 @@ module Alchemy
85
105
  # :show_caption => false # Pass Boolean to show/hide the caption of an EssencePicture. [Default true]
86
106
  # :disable_link => true # You can surpress the link of an EssencePicture. Default false
87
107
  #
108
+ # @deprecated Use Rails' `render(content)` method directly instead
88
109
  def render_essence_view(content, options = {}, html_options = {})
89
- render_essence(content, :view, {for_view: options}, html_options)
110
+ render content, {
111
+ content: content,
112
+ options: options,
113
+ html_options: html_options
114
+ }
90
115
  end
116
+ deprecate render_essence_view: "Use Rails' `render(content)` method directly instead",
117
+ deprecator: Alchemy::Deprecation
91
118
  end
92
119
  end
@@ -73,6 +73,7 @@ module Alchemy
73
73
  end
74
74
 
75
75
  # Renders the navigation.
76
+ # @deprecated
76
77
  #
77
78
  # It produces a html <ul><li></li></ul> structure with all necessary classes so you can produce every navigation the web uses today.
78
79
  # I.E. dropdown-navigations, simple mainnavigations or even complex nested ones.
@@ -177,6 +178,33 @@ module Alchemy
177
178
  pages: pages,
178
179
  html_options: html_options
179
180
  end
181
+ deprecate render_navigation: 'Create a menu and use render_menu instead', deprecator: Alchemy::Deprecation
182
+
183
+ # Renders a menu partial
184
+ #
185
+ # Menu partials are placed in the `app/views/alchemy/menus` folder
186
+ # Use the `rails g alchemy:menus` generator to create the partials
187
+ #
188
+ # @param [String] - Name of the menu
189
+ # @param [Hash] - A set of options available in your menu partials
190
+ def render_menu(name, options = {})
191
+ root_node = Alchemy::Node.roots.find_by(name: name)
192
+ if root_node.nil?
193
+ warning("Menu with name #{name} not found!")
194
+ return
195
+ end
196
+
197
+ options = {
198
+ node_partial_name: "#{root_node.view_folder_name}/node"
199
+ }.merge(options)
200
+
201
+ render(root_node, menu: root_node, node: root_node, options: options)
202
+ rescue ActionView::MissingTemplate => e
203
+ warning <<~WARN
204
+ Menu partial not found for #{name}.
205
+ #{e}
206
+ WARN
207
+ end
180
208
 
181
209
  # Renders navigation the children and all siblings of the given page (standard is the current page).
182
210
  #
@@ -206,6 +234,7 @@ module Alchemy
206
234
  return nil
207
235
  end
208
236
  end
237
+ deprecate :render_subnavigation, deprecator: Alchemy::Deprecation
209
238
 
210
239
  # Returns true if page is in the active branch
211
240
  def page_active?(page)
@@ -24,7 +24,7 @@ module Alchemy
24
24
  # Concerns
25
25
  include Alchemy::Content::Factory
26
26
 
27
- belongs_to :essence, polymorphic: true, dependent: :destroy
27
+ belongs_to :essence, polymorphic: true, dependent: :destroy, inverse_of: :content
28
28
  belongs_to :element, touch: true, inverse_of: :contents
29
29
  has_one :page, through: :element
30
30
 
@@ -33,7 +33,8 @@ module Alchemy
33
33
  "contents",
34
34
  "hint",
35
35
  "taggable",
36
- "compact"
36
+ "compact",
37
+ "message"
37
38
  ].freeze
38
39
 
39
40
  SKIPPED_ATTRIBUTES_ON_COPY = [
@@ -61,10 +62,10 @@ module Alchemy
61
62
 
62
63
  # Content positions are scoped by their essence_type, so positions can be the same for different contents.
63
64
  # In order to get contents in creation order we also order them by id.
64
- has_many :contents, -> { order(:position, :id) }, dependent: :destroy
65
+ has_many :contents, -> { order(:position, :id) }, dependent: :destroy, inverse_of: :element
65
66
 
66
67
  has_many :all_nested_elements,
67
- -> { order(:position) },
68
+ -> { order(:position).not_trashed },
68
69
  class_name: 'Alchemy::Element',
69
70
  foreign_key: :parent_element_id,
70
71
  dependent: :destroy
@@ -73,15 +74,17 @@ module Alchemy
73
74
  -> { order(:position).available },
74
75
  class_name: 'Alchemy::Element',
75
76
  foreign_key: :parent_element_id,
76
- dependent: :destroy
77
+ dependent: :destroy,
78
+ inverse_of: :parent_element
77
79
 
78
- belongs_to :page, touch: true, inverse_of: :all_elements
80
+ belongs_to :page, touch: true, inverse_of: :elements
79
81
 
80
82
  # A nested element belongs to a parent element.
81
83
  belongs_to :parent_element,
82
84
  class_name: 'Alchemy::Element',
83
85
  optional: true,
84
- touch: true
86
+ touch: true,
87
+ inverse_of: :nested_elements
85
88
 
86
89
  has_and_belongs_to_many :touchable_pages, -> { distinct },
87
90
  class_name: 'Alchemy::Page',
@@ -216,7 +219,6 @@ module Alchemy
216
219
  return true if page.nil?
217
220
  unless touchable_pages.include? page
218
221
  touchable_pages << page
219
- save
220
222
  end
221
223
  end
222
224
 
@@ -261,7 +263,17 @@ module Alchemy
261
263
  # Element partials live in +app/views/alchemy/elements+
262
264
  #
263
265
  def to_partial_path
264
- "alchemy/elements/#{name}_view"
266
+ if Alchemy::LOOKUP_CONTEXT.exists?("#{name}_view", ["elements"], true)
267
+ Alchemy::Deprecation.warn <<~WARN
268
+ Having the `_view` suffix on your element view partials is deprecated
269
+ and will not be supported in Alchemy 5.0 anymore. You can safely remove the suffix now.
270
+
271
+ Please also rename the local `element` or `#{name}_view` variable into `#{name}`.
272
+ WARN
273
+ "alchemy/elements/#{name}_view"
274
+ else
275
+ "alchemy/elements/#{name}"
276
+ end
265
277
  end
266
278
 
267
279
  # Returns the key that's taken for cache path.
@@ -16,13 +16,15 @@ module Alchemy
16
16
 
17
17
  # All contents from element by given name.
18
18
  def contents_by_name(name)
19
- contents.where(name: name)
19
+ contents.select { |content| content.name == name.to_s }
20
20
  end
21
21
  alias_method :all_contents_by_name, :contents_by_name
22
22
 
23
23
  # All contents from element by given essence type.
24
24
  def contents_by_type(essence_type)
25
- contents.where(essence_type: Content.normalize_essence_type(essence_type))
25
+ contents.select do |content|
26
+ content.essence_type == Content.normalize_essence_type(essence_type)
27
+ end
26
28
  end
27
29
  alias_method :all_contents_by_type, :contents_by_type
28
30
 
@@ -99,7 +101,7 @@ module Alchemy
99
101
  log_warning "Element #{name} is missing the content definition for #{content_name}"
100
102
  nil
101
103
  else
102
- content_definitions.detect { |d| d['name'] == content_name }
104
+ content_definitions.detect { |d| d['name'] == content_name.to_s }
103
105
  end
104
106
  end
105
107
 
@@ -134,7 +136,7 @@ module Alchemy
134
136
  def content_for_rss_meta(type)
135
137
  definition = content_definitions.detect { |c| c["rss_#{type}"] }
136
138
  return if definition.blank?
137
- contents.find_by(name: definition['name'])
139
+ contents.detect { |content| content.name == definition['name'] }
138
140
  end
139
141
 
140
142
  # creates the contents for this element as described in the elements.yml
@@ -96,8 +96,8 @@ module Alchemy
96
96
  private
97
97
 
98
98
  def preview_text_from_nested_elements(maxlength)
99
- return unless nested_elements.present?
100
- nested_elements.first.preview_text(maxlength)
99
+ return if all_nested_elements.empty?
100
+ all_nested_elements.first.preview_text(maxlength)
101
101
  end
102
102
 
103
103
  def preview_text_from_preview_content(maxlength)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class EssencePage < BaseRecord
5
+ PAGE_ID = /\A\d+\z/
6
+
7
+ acts_as_essence(
8
+ ingredient_column: :page,
9
+ preview_text_method: :name,
10
+ belongs_to: {
11
+ class_name: 'Alchemy::Page',
12
+ foreign_key: :page_id,
13
+ inverse_of: :essence_pages,
14
+ optional: true
15
+ }
16
+ )
17
+
18
+ def ingredient=(page)
19
+ case page
20
+ when PAGE_ID
21
+ self.page = Alchemy::Page.new(id: page)
22
+ when Alchemy::Page
23
+ self.page = page
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
29
+ end