alchemy_cms 4.1.2 → 4.2.0.rc1

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/Bug_report.md +0 -5
  3. data/.rubocop.yml +4 -1
  4. data/.travis.yml +3 -3
  5. data/CHANGELOG.md +29 -10
  6. data/Gemfile +5 -7
  7. data/README.md +114 -62
  8. data/Rakefile +2 -2
  9. data/alchemy_cms.gemspec +5 -5
  10. data/app/assets/images/alchemy/icon.svg +1 -1
  11. data/app/assets/javascripts/alchemy/admin.js +2 -0
  12. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -24
  13. data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +11 -9
  14. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +7 -24
  15. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +9 -8
  16. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +38 -0
  17. data/app/assets/javascripts/alchemy/alchemy.sitemap.js.coffee +2 -4
  18. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +1 -1
  19. data/app/assets/stylesheets/alchemy/_mixins.scss +2 -1
  20. data/app/assets/stylesheets/alchemy/_variables.scss +7 -2
  21. data/app/assets/stylesheets/alchemy/admin.scss +2 -1
  22. data/app/assets/stylesheets/alchemy/archive.scss +18 -4
  23. data/app/assets/stylesheets/alchemy/buttons.scss +1 -1
  24. data/app/assets/stylesheets/alchemy/dialogs.scss +1 -1
  25. data/app/assets/stylesheets/alchemy/elements.scss +154 -90
  26. data/app/assets/stylesheets/alchemy/filter_field.scss +30 -0
  27. data/app/assets/stylesheets/alchemy/flatpickr.scss +839 -0
  28. data/app/assets/stylesheets/alchemy/forms.scss +5 -1
  29. data/app/assets/stylesheets/alchemy/frame.scss +6 -14
  30. data/app/assets/stylesheets/alchemy/navigation.scss +109 -98
  31. data/app/assets/stylesheets/alchemy/search.scss +11 -29
  32. data/app/assets/stylesheets/alchemy/tables.scss +0 -23
  33. data/app/assets/stylesheets/alchemy/tags.scss +4 -27
  34. data/app/assets/stylesheets/alchemy/toolbar.scss +12 -2
  35. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +4 -33
  36. data/app/controllers/alchemy/admin/attachments_controller.rb +1 -12
  37. data/app/controllers/alchemy/admin/contents_controller.rb +2 -24
  38. data/app/controllers/alchemy/admin/elements_controller.rb +11 -49
  39. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  40. data/app/controllers/alchemy/admin/pictures_controller.rb +1 -14
  41. data/app/controllers/alchemy/api/contents_controller.rb +1 -1
  42. data/app/controllers/alchemy/api/elements_controller.rb +1 -1
  43. data/app/controllers/alchemy/api/pages_controller.rb +1 -1
  44. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +20 -0
  45. data/app/helpers/alchemy/admin/base_helper.rb +8 -18
  46. data/app/helpers/alchemy/admin/elements_helper.rb +55 -85
  47. data/app/helpers/alchemy/admin/pictures_helper.rb +0 -23
  48. data/app/helpers/alchemy/elements_helper.rb +80 -120
  49. data/app/helpers/alchemy/pages_helper.rb +5 -24
  50. data/app/models/alchemy/content.rb +0 -1
  51. data/app/models/alchemy/content/factory.rb +33 -57
  52. data/app/models/alchemy/element.rb +46 -66
  53. data/app/models/alchemy/element/element_contents.rb +2 -2
  54. data/app/models/alchemy/page.rb +34 -4
  55. data/app/models/alchemy/page/page_elements.rb +30 -122
  56. data/app/serializers/alchemy/attachment_serializer.rb +0 -2
  57. data/app/serializers/alchemy/content_serializer.rb +0 -2
  58. data/app/serializers/alchemy/element_serializer.rb +0 -3
  59. data/app/serializers/alchemy/essence_boolean_serializer.rb +0 -2
  60. data/app/serializers/alchemy/essence_date_serializer.rb +0 -2
  61. data/app/serializers/alchemy/essence_file_serializer.rb +0 -2
  62. data/app/serializers/alchemy/essence_html_serializer.rb +0 -2
  63. data/app/serializers/alchemy/essence_link_serializer.rb +0 -2
  64. data/app/serializers/alchemy/essence_picture_serializer.rb +0 -2
  65. data/app/serializers/alchemy/essence_richtext_serializer.rb +0 -2
  66. data/app/serializers/alchemy/essence_select_serializer.rb +0 -2
  67. data/app/serializers/alchemy/essence_text_serializer.rb +0 -2
  68. data/app/serializers/alchemy/legacy_element_serializer.rb +0 -3
  69. data/app/serializers/alchemy/page_serializer.rb +2 -8
  70. data/app/serializers/alchemy/page_tree_serializer.rb +1 -1
  71. data/app/serializers/alchemy/picture_serializer.rb +0 -2
  72. data/app/views/alchemy/admin/clipboard/index.html.erb +2 -2
  73. data/app/views/alchemy/admin/clipboard/insert.js.erb +9 -12
  74. data/app/views/alchemy/admin/contents/create.js.erb +4 -30
  75. data/app/views/alchemy/admin/elements/_element.html.erb +27 -12
  76. data/app/views/alchemy/admin/elements/_element_toolbar.html.erb +1 -1
  77. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +0 -10
  78. data/app/views/alchemy/admin/elements/create.js.erb +12 -12
  79. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  80. data/app/views/alchemy/admin/elements/index.html.erb +20 -19
  81. data/app/views/alchemy/admin/elements/publish.js.erb +5 -0
  82. data/app/views/alchemy/admin/elements/trash.js.erb +4 -1
  83. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -7
  84. data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +0 -22
  85. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +2 -4
  86. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  87. data/app/views/alchemy/admin/pages/index.html.erb +14 -10
  88. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  89. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +1 -1
  90. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +7 -5
  91. data/app/views/alchemy/admin/partials/_routes.html.erb +0 -1
  92. data/app/views/alchemy/admin/partials/_search_form.html.erb +6 -4
  93. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +6 -3
  94. data/app/views/alchemy/admin/pictures/index.html.erb +1 -1
  95. data/app/views/alchemy/admin/trash/index.html.erb +8 -7
  96. data/app/views/alchemy/elements/_editor_not_found.html.erb +1 -1
  97. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +4 -19
  98. data/app/views/layouts/alchemy/admin.html.erb +1 -0
  99. data/bin/rspec +0 -5
  100. data/config/alchemy/config.yml +3 -0
  101. data/config/brakeman.ignore +1 -1
  102. data/config/locales/alchemy.en.yml +6 -12
  103. data/config/routes.rb +1 -5
  104. data/db/migrate/20180226123013_alchemy_four_point_zero.rb +0 -29
  105. data/db/migrate/20180519204655_add_fixed_to_alchemy_elements.rb +6 -0
  106. data/lib/alchemy/admin/locale.rb +1 -1
  107. data/lib/alchemy/cache_digests/template_tracker.rb +4 -27
  108. data/lib/alchemy/elements_finder.rb +111 -0
  109. data/lib/alchemy/errors.rb +0 -4
  110. data/lib/alchemy/modules.rb +49 -18
  111. data/lib/alchemy/tasks/tidy.rb +3 -40
  112. data/lib/alchemy/test_support/controller_requests.rb +1 -1
  113. data/lib/alchemy/test_support/essence_shared_examples.rb +1 -1
  114. data/lib/alchemy/test_support/factories/attachment_factory.rb +5 -3
  115. data/lib/alchemy/test_support/factories/content_factory.rb +4 -4
  116. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +5 -5
  117. data/lib/alchemy/test_support/factories/element_factory.rb +12 -7
  118. data/lib/alchemy/test_support/factories/essence_text_factory.rb +1 -1
  119. data/lib/alchemy/test_support/factories/language_factory.rb +13 -13
  120. data/lib/alchemy/test_support/factories/page_factory.rb +18 -17
  121. data/lib/alchemy/test_support/factories/picture_factory.rb +6 -4
  122. data/lib/alchemy/test_support/factories/site_factory.rb +6 -6
  123. data/lib/alchemy/tinymce.rb +1 -1
  124. data/lib/alchemy/upgrader/four_point_two.rb +68 -0
  125. data/lib/alchemy/upgrader/tasks/cells_migration.rb +41 -0
  126. data/lib/alchemy/upgrader/tasks/cells_upgrader.rb +146 -0
  127. data/lib/alchemy/upgrader/tasks/picture_gallery_migration.rb +65 -0
  128. data/lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb +195 -0
  129. data/lib/alchemy/version.rb +1 -1
  130. data/lib/alchemy_cms.rb +1 -0
  131. data/lib/rails/generators/alchemy/elements/elements_generator.rb +1 -0
  132. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +0 -3
  133. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +0 -3
  134. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +0 -3
  135. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +3 -14
  136. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +3 -10
  137. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +3 -10
  138. data/lib/tasks/alchemy/tidy.rake +1 -23
  139. data/lib/tasks/alchemy/upgrade.rake +44 -1
  140. data/vendor/assets/javascripts/flatpickr/flatpickr.min.js +2 -0
  141. data/vendor/assets/javascripts/tinymce/license.txt +0 -0
  142. data/vendor/assets/javascripts/tinymce/tinymce.min.js +2 -2
  143. metadata +25 -31
  144. data/app/assets/stylesheets/alchemy/jquery.datetimepicker.scss +0 -478
  145. data/app/models/alchemy/cell.rb +0 -95
  146. data/app/models/alchemy/page/page_cells.rb +0 -69
  147. data/app/serializers/alchemy/cell_serializer.rb +0 -19
  148. data/app/views/alchemy/admin/contents/new.html.erb +0 -11
  149. data/app/views/alchemy/admin/contents/order.js.erb +0 -3
  150. data/app/views/alchemy/admin/elements/_add_picture.html.erb +0 -14
  151. data/app/views/alchemy/admin/elements/_picture_gallery_editor.html.erb +0 -24
  152. data/bin/spring +0 -16
  153. data/lib/alchemy/test_support/factories/cell_factory.rb +0 -9
  154. data/vendor/assets/javascripts/date-formatter.js +0 -161
  155. data/vendor/assets/javascripts/jquery_plugins/jquery.datetimepicker.full.min.js +0 -2
@@ -3,29 +3,6 @@
3
3
  module Alchemy
4
4
  module Admin
5
5
  module PicturesHelper
6
- def create_or_assign_url(picture_to_assign, options)
7
- if @content.nil?
8
- {
9
- controller: :contents,
10
- action: :create,
11
- picture_id: picture_to_assign.id,
12
- content: {
13
- essence_type: "Alchemy::EssencePicture",
14
- element_id: @element.id
15
- },
16
- options: options
17
- }
18
- else
19
- {
20
- controller: :essence_pictures,
21
- action: :assign,
22
- picture_id: picture_to_assign.id,
23
- content_id: @content.id,
24
- options: options
25
- }
26
- end
27
- end
28
-
29
6
  def preview_size(size)
30
7
  case size
31
8
  when 'small' then '80x60'
@@ -10,7 +10,7 @@ module Alchemy
10
10
  include Alchemy::UrlHelper
11
11
  include Alchemy::ElementsBlockHelper
12
12
 
13
- # Renders all elements from current page
13
+ # Renders elements from given page
14
14
  #
15
15
  # == Examples:
16
16
  #
@@ -29,12 +29,6 @@ module Alchemy
29
29
  # <%= render_elements from_page: 'footer' %>
30
30
  # </footer>
31
31
  #
32
- # === Render elements from cell:
33
- #
34
- # <aside>
35
- # <%= render_elements from_cell: 'sidebar' %>
36
- # </aside>
37
- #
38
32
  # === Fallback to elements from global page:
39
33
  #
40
34
  # You can use the fallback option as an override for elements that are stored on another page.
@@ -51,69 +45,85 @@ module Alchemy
51
45
  # with: 'contact_teaser'
52
46
  # }) %>
53
47
  #
54
- # @param [Hash] options
55
- # Additional options.
48
+ # === Custom elements finder:
49
+ #
50
+ # Having a custom element finder class:
51
+ #
52
+ # class MyCustomNewsArchive
53
+ # def elements(page:)
54
+ # news_page.elements.available.named('news').order(created_at: :desc)
55
+ # end
56
+ #
57
+ # private
58
+ #
59
+ # def news_page
60
+ # Alchemy::Page.where(page_layout: 'news-archive')
61
+ # end
62
+ # end
56
63
  #
64
+ # In your view:
65
+ #
66
+ # <div class="news-archive">
67
+ # <%= render_elements finder: MyCustomNewsArchive.new %>
68
+ # </div>
69
+ #
70
+ # @option options [Alchemy::Page|String] :from_page (@page)
71
+ # The page the elements are rendered from. You can pass a page_layout String or a {Alchemy::Page} object.
72
+ # @option options [Array<String>|String] :only
73
+ # A list of element names only to be rendered.
74
+ # @option options [Array<String>|String] :except
75
+ # A list of element names not to be rendered.
57
76
  # @option options [Number] :count
58
77
  # The amount of elements to be rendered (begins with first element found)
59
- # @option options [Array or String] :except ([])
60
- # A list of element names not to be rendered.
78
+ # @option options [Number] :offset
79
+ # The offset to begin loading elements from
61
80
  # @option options [Hash] :fallback
62
81
  # Define elements that are rendered from another page.
63
- # @option options [Alchemy::Cell or String] :from_cell
64
- # The cell the elements are rendered from. You can pass a {Alchemy::Cell} name String or a {Alchemy::Cell} object.
65
- # @option options [Alchemy::Page or String] :from_page (@page)
66
- # The page the elements are rendered from. You can pass a page_layout String or a {Alchemy::Page} object.
67
- # @option options [Array or String] :only ([])
68
- # A list of element names only to be rendered.
69
- # @option options [Boolean] :random
82
+ # @option options [Boolean] :random (false)
70
83
  # Randomize the output of elements
71
- # @option options [Boolean] :reverse
84
+ # @option options [Boolean] :reverse (false)
72
85
  # Reverse the rendering order
73
- # @option options [String] :sort_by
74
- # The name of a {Alchemy::Content} to sort the elements by
75
86
  # @option options [String] :separator
76
- # A string that will be used to join the element partials. Default nil
87
+ # A string that will be used to join the element partials.
88
+ # @option options [Class] :finder (Alchemy::ElementsFinder)
89
+ # A class instance that will return elements that get rendered.
90
+ # Use this for your custom element loading logic in views.
77
91
  #
78
92
  def render_elements(options = {})
79
93
  options = {
80
94
  from_page: @page,
81
- render_format: 'html',
82
- reverse: false
95
+ render_format: 'html'
83
96
  }.update(options)
84
97
 
85
- pages = pages_holding_elements(options.delete(:from_page))
98
+ if options[:sort_by]
99
+ Alchemy::Deprecation.warn "options[:sort_by] has been removed without replacement. " \
100
+ "Please implement your own element sorting by passing a custom finder instance to options[:finder]."
101
+ end
86
102
 
87
- if pages.blank?
88
- warning('No page to get elements from was found')
89
- return
103
+ if options[:from_cell]
104
+ Alchemy::Deprecation.warn "options[:from_cell] has been removed without replacement. " \
105
+ "Please `render element.nested_elements.available` instead."
90
106
  end
91
107
 
92
- elements = collect_elements_from_pages(pages, options)
108
+ finder = options[:finder] || Alchemy::ElementsFinder.new(options)
109
+ elements = finder.elements(page: options[:from_page])
93
110
 
94
- if options[:sort_by].present?
95
- elements = sort_elements_by_content(
96
- elements,
97
- options.delete(:sort_by),
98
- options[:reverse]
99
- )
111
+ buff = []
112
+ elements.each_with_index do |element, i|
113
+ buff << render_element(element, options, i + 1)
100
114
  end
101
-
102
- render_element_view_partials(elements, options)
115
+ buff.join(options[:separator]).html_safe
103
116
  end
104
117
 
105
- # This helper renders a {Alchemy::Element} partial.
106
- #
107
- # A element has always two partials:
118
+ # This helper renders a {Alchemy::Element} view partial.
108
119
  #
109
- # 1. A view partial (This is the view presented to the website visitor)
110
- # 2. A editor partial (This is the form presented to the website editor while in page edit mode)
120
+ # A element view partial is the html snippet presented to the website visitor.
111
121
  #
112
- # The partials are located in <tt>app/views/alchemy/elements</tt>.
122
+ # The partial is located in <tt>app/views/alchemy/elements</tt>.
113
123
  #
114
124
  # == View partial naming
115
125
  #
116
- # The partials have to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with the partial part.
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>.
117
127
  #
118
128
  # === Example
119
129
  #
@@ -125,10 +135,9 @@ module Alchemy
125
135
  # - name: text
126
136
  # type: EssenceText
127
137
  #
128
- # Then your element view partials has to be named like:
138
+ # Then your element view partial has to be named like:
129
139
  #
130
- # app/views/alchemy/elements/_headline_editor.html.erb
131
- # app/views/alchemy/elements/_headline_view.html.erb
140
+ # app/views/alchemy/elements/_headline_view.html.{erb|haml|slim}
132
141
  #
133
142
  # === Element partials generator
134
143
  #
@@ -142,41 +151,45 @@ module Alchemy
142
151
  #
143
152
  # @param [Alchemy::Element] element
144
153
  # The element you want to render the view for
145
- # @param [Symbol] part
146
- # The type of element partial (<tt>:editor</tt> or <tt>:view</tt>) you want to render
147
154
  # @param [Hash] options
148
155
  # Additional options
149
156
  # @param [Number] counter
150
157
  # a counter
151
158
  #
152
- # @note If the view partial is not found <tt>alchemy/elements/_view_not_found.html.erb</tt>
153
- # or <tt>alchemy/elements/_editor_not_found.html.erb</tt> gets rendered.
159
+ # @note If the view partial is not found
160
+ # <tt>alchemy/elements/_view_not_found.html.erb</tt> gets rendered.
154
161
  #
155
- def render_element(element, part = :view, options = {}, counter = 1)
162
+ def render_element(*args)
163
+ if args.length == 4
164
+ element, _part, options, counter = *args
165
+ Alchemy::Deprecation.warn "passing a `part` parameter as second argument to `render_element` has been removed without replacement. " \
166
+ "You can safely remove it."
167
+ else
168
+ element, options, counter = *args
169
+ end
170
+
171
+ options ||= {}
172
+ counter ||= 1
173
+
156
174
  if element.nil?
157
175
  warning('Element is nil')
158
- render "alchemy/elements/#{part}_not_found", {name: 'nil'}
176
+ render "alchemy/elements/view_not_found", {name: 'nil'}
159
177
  return
160
178
  end
161
179
 
162
- options = {
180
+ element.store_page(@page)
181
+
182
+ render element, {
163
183
  element: element,
164
184
  counter: counter,
165
- options: options,
166
- locals: options.delete(:locals) || {}
167
- }
168
-
169
- element.store_page(@page) if part.to_sym == :view
170
- render "alchemy/elements/#{element.name}_#{part}", options
185
+ options: options
186
+ }.merge(options.delete(:locals) || {})
171
187
  rescue ActionView::MissingTemplate => e
172
188
  warning(%(
173
- Element #{part} partial not found for #{element.name}.\n
189
+ Element view partial not found for #{element.name}.\n
174
190
  #{e}
175
191
  ))
176
- render "alchemy/elements/#{part}_not_found", {
177
- name: element.name,
178
- error: "Element #{part} partial not found.<br>Use <code>rails generate alchemy:elements</code> to generate it."
179
- }
192
+ render "alchemy/elements/view_not_found", name: element.name
180
193
  end
181
194
 
182
195
  # Returns a string for the id attribute of a html element for the given element
@@ -239,14 +252,14 @@ module Alchemy
239
252
  end
240
253
 
241
254
  # Sort given elements by content.
242
- #
255
+ # @deprecated
243
256
  # @param [Array] elements - The elements you want to sort
244
257
  # @param [String] content_name - The name of the content you want to sort by
245
258
  # @param [Boolean] reverse - Reverse the sorted elements order
246
259
  #
247
260
  # @return [Array]
248
- #
249
261
  def sort_elements_by_content(elements, content_name, reverse = false)
262
+ Alchemy::Deprecation.warn "options[:sort_by] is deprecated. Please implement your own element sorting."
250
263
  sorted_elements = elements.sort_by do |element|
251
264
  content = element.content_by_name(content_name)
252
265
  content ? content.ingredient.to_s : ''
@@ -254,58 +267,5 @@ module Alchemy
254
267
 
255
268
  reverse ? sorted_elements.reverse : sorted_elements
256
269
  end
257
-
258
- private
259
-
260
- def pages_holding_elements(page)
261
- case page
262
- when String
263
- Language.current.pages.where(
264
- page_layout: page,
265
- restricted: false
266
- ).to_a
267
- when Page
268
- page
269
- end
270
- end
271
-
272
- def collect_elements_from_pages(page, options)
273
- if page.is_a? Array
274
- elements = page.collect { |p| p.find_elements(options) }.flatten
275
- else
276
- elements = page.find_elements(options)
277
- end
278
- if fallback_required?(elements, options)
279
- elements += fallback_elements(options)
280
- end
281
- elements
282
- end
283
-
284
- def fallback_required?(elements, options)
285
- options[:fallback] && elements.detect { |e| e.name == options[:fallback][:for] }.nil?
286
- end
287
-
288
- def fallback_elements(options)
289
- fallback_options = options.delete(:fallback)
290
- case fallback_options[:from]
291
- when String
292
- page = Language.current.pages.find_by(
293
- page_layout: fallback_options[:from],
294
- restricted: false
295
- )
296
- when Page
297
- page = fallback_options[:from]
298
- end
299
- return [] if page.blank?
300
- page.elements.not_trashed.named(fallback_options[:with].presence || fallback_options[:for])
301
- end
302
-
303
- def render_element_view_partials(elements, options = {})
304
- buff = []
305
- elements.each_with_index do |element, i|
306
- buff << render_element(element, :view, options, i + 1)
307
- end
308
- buff.join(options[:separator]).html_safe
309
- end
310
270
  end
311
271
  end
@@ -294,30 +294,11 @@ module Alchemy
294
294
  "#{@page.robot_index? ? '' : 'no'}index, #{@page.robot_follow? ? '' : 'no'}follow"
295
295
  end
296
296
 
297
- # Renders the partial for the cell with the given name of the current page.
298
- # Cell partials are located in +app/views/cells/+ of your project.
299
- #
300
- # === Options are:
301
- #
302
- # from_page: Alchemy::Page # Alchemy::Page object from which the elements are rendered from.
303
- # locals: Hash # Hash of variables that will be available in the partial. Example: {user: var1, product: var2}
304
- #
305
- def render_cell(name, options = {})
306
- default_options = {
307
- from_page: @page,
308
- locals: {}
309
- }
310
- options = default_options.merge(options)
311
- cell = options[:from_page].cells.find_by_name(name)
312
- return "" if cell.blank?
313
- render partial: "alchemy/cells/#{name}", locals: {cell: cell}.merge(options[:locals])
314
- end
315
-
316
- # Returns true or false if no elements are in the cell found by name.
317
- def cell_empty?(name)
318
- cell = @page.cells.find_by_name(name)
319
- return true if cell.blank?
320
- cell.elements.not_trashed.empty?
297
+ # @deprecated
298
+ def render_cell(name, _options = {})
299
+ render_elements(only: name, fixed: true)
321
300
  end
301
+ deprecate render_cell: 'Use render_elements(only: <cell-name>, fixed: true) instead',
302
+ deprecator: Alchemy::Deprecation
322
303
  end
323
304
  end
@@ -45,7 +45,6 @@ module Alchemy
45
45
  scope :essence_htmls, -> { where(essence_type: "Alchemy::EssenceHtml") }
46
46
  scope :essence_links, -> { where(essence_type: "Alchemy::EssenceLink") }
47
47
  scope :essence_pictures, -> { where(essence_type: "Alchemy::EssencePicture") }
48
- scope :gallery_pictures, -> { essence_pictures.where("#{table_name}.name LIKE 'essence_picture_%'") }
49
48
  scope :essence_richtexts, -> { where(essence_type: "Alchemy::EssenceRichtext") }
50
49
  scope :essence_selects, -> { where(essence_type: "Alchemy::EssenceSelect") }
51
50
  scope :essence_texts, -> { where(essence_type: "Alchemy::EssenceText") }
@@ -11,19 +11,21 @@ module Alchemy
11
11
 
12
12
  # Builds a new content as descriped in the elements.yml file.
13
13
  #
14
- # @param [Alchemy::Element]
15
- # The element the content is for
16
14
  # @param [Hash]
17
15
  # The content definition used for finding the content in +elements.yml+ file
18
16
  #
19
- def build(element, essence_hash)
20
- definition = content_definition(element, essence_hash)
17
+ def new(attributes = {})
18
+ element = attributes[:element] || Element.find_by(id: attributes[:element_id])
19
+ return super if attributes.empty? || element.nil?
20
+
21
+ definition = element.content_definition_for(attributes[:name])
21
22
  if definition.blank?
22
- raise ContentDefinitionError, "No definition found in elements.yml for #{essence_hash.inspect} and #{element.inspect}"
23
- else
24
- new(name: definition['name'], element_id: element.id)
23
+ raise ContentDefinitionError, "No definition found in elements.yml for #{attributes.inspect} and #{element.inspect}"
25
24
  end
25
+ super(name: definition['name'], element_id: element.id)
26
26
  end
27
+ alias_method :build, :new
28
+ deprecate build: :new, deprecator: Alchemy::Deprecation
27
29
 
28
30
  # Creates a new content from elements definition in the +elements.yml+ file.
29
31
  #
@@ -32,12 +34,20 @@ module Alchemy
32
34
  #
33
35
  # @return [Alchemy::Content]
34
36
  #
35
- def create_from_scratch(element, essence_hash)
36
- if content = build(element, essence_hash)
37
- content.create_essence!(essence_hash[:essence_type])
37
+ def create(*args)
38
+ attributes = args.last || {}
39
+ if args.length > 1
40
+ Alchemy::Deprecation.warn 'Passing an element as first argument to Alchemy::Content.create is deprecated! Pass an attribute hash with element inside instead.'
41
+ element = args.first
42
+ else
43
+ element = attributes[:element]
44
+ end
45
+ new(attributes.merge(element: element)).tap do |content|
46
+ content.create_essence!(attributes[:essence_type])
38
47
  end
39
- content
40
48
  end
49
+ alias_method :create_from_scratch, :create
50
+ deprecate create_from_scratch: :create, deprecator: Alchemy::Deprecation
41
51
 
42
52
  # Creates a copy of source and also copies the associated essence.
43
53
  #
@@ -50,60 +60,26 @@ module Alchemy
50
60
  #
51
61
  def copy(source, differences = {})
52
62
  new_content = Content.new(
53
- source.attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY).merge(differences)
63
+ source.attributes.
64
+ except(*SKIPPED_ATTRIBUTES_ON_COPY).
65
+ merge(differences.with_indifferent_access)
54
66
  )
55
-
56
- new_essence = new_content.essence.class.create!(
57
- new_content.essence.attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY)
67
+ new_essence = source.essence.class.create!(
68
+ source.essence.attributes.
69
+ except(*SKIPPED_ATTRIBUTES_ON_COPY)
58
70
  )
59
-
60
- new_content.update!(essence_id: new_essence.id)
61
- new_content
62
- end
63
-
64
- # Returns the content definition for building a content.
65
- #
66
- # 1. It looks in the element's contents definition
67
- # 2. It builds a definition hash from essence type, if the the name key is not present
68
- #
69
- def content_definition(element, essence_hash)
70
- # No name given. We build the content from essence type.
71
- if essence_hash[:name].blank? && essence_hash[:essence_type].present?
72
- content_definition_from_essence_type(element, essence_hash[:essence_type])
73
- else
74
- element.content_definition_for(essence_hash[:name])
71
+ new_content.tap do |content|
72
+ content.essence = new_essence
73
+ content.save
75
74
  end
76
75
  end
77
76
 
78
- # Returns a hash for building a content from essence type.
79
- #
80
- # @param [Alchemy::Element]
81
- # The element the content is for.
82
- # @param [String]
83
- # The essence type the content is from
84
- #
85
- def content_definition_from_essence_type(element, essence_type)
86
- {
87
- 'type' => essence_type,
88
- 'name' => content_name_from_element_and_essence_type(element, essence_type)
89
- }
90
- end
91
-
92
- # A name for content from its essence type and amount of same essences in element.
93
- #
94
- # Example:
95
- #
96
- # essence_picture_1
97
- #
98
- def content_name_from_element_and_essence_type(element, essence_type)
99
- essences_of_same_type = element.contents.where(essence_type: normalize_essence_type(essence_type))
100
- "#{essence_type.classify.demodulize.underscore}_#{essences_of_same_type.count + 1}"
101
- end
102
-
103
77
  # Returns all content definitions from elements.yml
104
78
  #
105
79
  def definitions
106
- Element.definitions.collect { |e| e['contents'] }.flatten.compact
80
+ definitions = Element.definitions.flat_map { |e| e['contents'] }
81
+ definitions.compact!
82
+ definitions
107
83
  end
108
84
 
109
85
  # Returns a normalized Essence type