alchemy_cms 4.4.0 → 4.4.1

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3627c5787085ffff82e37a3d35ca2ca42cc58c5ec8f44e10fa6ba91e4fbd4095
4
- data.tar.gz: d2e1d6dbbae695b9a6e29df44d0ed8850952550e610fdfda6a156d519d19f3b6
3
+ metadata.gz: cfa2cfba392b4282fab17dcd0baf419c2ad6204a4a62eb542fa589a5047cc518
4
+ data.tar.gz: bc7456380f3bb098ea641066c58afaf2d7d38afea8d7278dcbbdee7c66d10cdb
5
5
  SHA512:
6
- metadata.gz: 72f44c680caaa741f59b3b33940a654774f53c94f8e3ce66d164135d52999007fe2d3b4ca0af80ee490f09366d758118d50498a5d22539662a5f81ba4379d52b
7
- data.tar.gz: 1dd6222e477cffd173025f52b973d5f55f3f844f9f1731cfc2745b40b84a96622d51b74f331bb3d092462dbe20036622b14d802c64a0ee1e4f5552e37d19359d
6
+ metadata.gz: 67f12a17d5b5a483d2054934f2dbc4808748dfa0a437ebb93048fcbecd6af35dc76c657198d0072728afeb7b5c87df84cdec2c1ba1dc48b2056c999251003741
7
+ data.tar.gz: 77760e2ffc8287532502ad93e55e738fcaddf67e09d4f7ffbf7405648e0d265be8f6dc1ad29a90ec40361a8cdceec17033a436e405f14b923422cf5d3a5f3066
@@ -1,3 +1,13 @@
1
+ ## 5.0.0 (unreleased)
2
+
3
+ ## 4.4.1 (2020-01-08)
4
+
5
+ - Fix updating page preview after element create/save [#1710](https://github.com/AlchemyCMS/alchemy_cms/pull/1710) ([tvdeyen](https://github.com/tvdeyen))
6
+ - Element editor layout changes [#1709](https://github.com/AlchemyCMS/alchemy_cms/pull/1709) ([tvdeyen](https://github.com/tvdeyen))
7
+ - Add Alchemy.user_class_primary_key setting [#1708](https://github.com/AlchemyCMS/alchemy_cms/pull/1708) ([tvdeyen](https://github.com/tvdeyen))
8
+ - Add Element views upgrade tasks [#1707](https://github.com/AlchemyCMS/alchemy_cms/pull/1707) ([tvdeyen](https://github.com/tvdeyen))
9
+ - Use postMessage to send messages between preview and element windows [#1704](https://github.com/AlchemyCMS/alchemy_cms/pull/1704) ([tvdeyen](https://github.com/tvdeyen))
10
+
1
11
  ## 4.4.0 (2020-01-06)
2
12
 
3
13
  - Use contents settings for size in EssencePicture#picture_url [#1703](https://github.com/AlchemyCMS/alchemy_cms/pull/1703) ([tvdeyen](https://github.com/tvdeyen))
@@ -36,20 +36,21 @@ Alchemy.ElementEditors =
36
36
  # Binds the custom SaveElement event
37
37
  @element_area.on "SaveElement.Alchemy", '.element-editor', (e, data) =>
38
38
  @onSaveElement(e, data)
39
+ # Listen to postMessage messages from the preview frame
40
+ window.addEventListener 'message', (e) =>
41
+ if e.origin == window.location.origin
42
+ @onMessage(e.data)
43
+ else
44
+ console.warn 'Unsafe message origin!', e.origin
45
+ true
39
46
  return
40
47
 
41
48
  # Selects and scrolls to element with given id in the preview window.
42
49
  #
43
- selectElementInPreview: (element_id) ->
44
- previewElements = document
45
- .getElementById('alchemy_preview_window')
46
- .contentDocument
47
- .querySelectorAll('[data-alchemy-element]')
48
- previewElement = Array.from(previewElements).find (element) ->
49
- element.getAttribute('data-alchemy-element') == element_id
50
- if previewElement
51
- event = new Event('SelectPreviewElement.Alchemy')
52
- previewElement.dispatchEvent(event)
50
+ focusElementPreview: (element_id) ->
51
+ Alchemy.PreviewWindow.postMessage
52
+ message: 'Alchemy.focusElement'
53
+ element_id: element_id
53
54
  return
54
55
 
55
56
  # Selects element
@@ -60,6 +61,7 @@ Alchemy.ElementEditors =
60
61
  # Used by the elements on click events in the preview frame.
61
62
  focusElement: ($element) ->
62
63
  element_id = $element.attr('id').replace(/\D/g, "")
64
+ Alchemy.ElementsWindow.show()
63
65
  @selectTabForElement($element)
64
66
  # If we have folded parents we need to unfold each of them
65
67
  # and then finally scroll to or unfold ourself
@@ -173,25 +175,31 @@ Alchemy.ElementEditors =
173
175
 
174
176
  # Event handlers
175
177
 
178
+ onMessage: (data) ->
179
+ if data.message == 'Alchemy.focusElementEditor'
180
+ $element = $("#element_#{data.element_id}")
181
+ Alchemy.ElementEditors.focusElement($element)
182
+ else
183
+ console.warn 'Unknown message received!', data
184
+
176
185
  onClickBody: (e) ->
177
- frameWindow = $('#alchemy_preview_window')[0].contentWindow
178
186
  element = $(e.target).parents('.element-editor')[0]
179
187
  $('#element_area .element-editor').not(element).removeClass('selected')
180
188
  unless element
181
- frameWindow.postMessage('blurAlchemyElements', window.location.origin)
189
+ Alchemy.PreviewWindow.postMessage(message: 'Alchemy.blurElements')
182
190
  return
183
191
 
184
192
  # Click event handler for element body.
185
193
  #
186
194
  # - Focuses the element
187
- # - Triggers custom 'SelectPreviewElement.Alchemy' event on target element in preview frame.
195
+ # - Sends 'Alchemy.focusElement' message to preview frame.
188
196
  #
189
197
  onClickElement: (e) ->
190
198
  $target = $(e.target)
191
199
  $element = $target.closest(".element-editor")
192
200
  element_id = $element.attr("id").replace(/\D/g, "")
193
201
  @selectElement($element)
194
- @selectElementInPreview(element_id)
202
+ @focusElementPreview(element_id)
195
203
  return
196
204
 
197
205
  # Double click event handler for element head.
@@ -21,11 +21,16 @@ Alchemy.initAlchemyPreviewMode = ->
21
21
  "outline-offset": "4px"
22
22
 
23
23
  init: ->
24
- window.addEventListener "message", (message) =>
25
- if message.data == "blurAlchemyElements"
26
- @blurElements()
27
- , false
28
- @elements = document.querySelectorAll("[data-alchemy-element]")
24
+ window.addEventListener "message", (event) =>
25
+ if event.origin != window.location.origin
26
+ console.warn 'Unsafe message origin!', event.origin
27
+ return
28
+ switch event.data.message
29
+ when "Alchemy.blurElements" then @blurElements()
30
+ when "Alchemy.focusElement" then @focusElement(event.data)
31
+ else console.info("Received unknown message!", event.data)
32
+ return
33
+ @elements = Array.from document.querySelectorAll("[data-alchemy-element]")
29
34
  @elements.forEach (element) =>
30
35
  element.addEventListener 'mouseover', =>
31
36
  unless element.classList.contains('selected')
@@ -35,10 +40,6 @@ Alchemy.initAlchemyPreviewMode = ->
35
40
  unless element.classList.contains('selected')
36
41
  Object.assign element.style, @getStyle('reset')
37
42
  return
38
- element.addEventListener 'SelectPreviewElement.Alchemy', =>
39
- @selectElement(element)
40
- return
41
- , false
42
43
  element.addEventListener 'click', (e) =>
43
44
  e.stopPropagation()
44
45
  e.preventDefault()
@@ -66,14 +67,25 @@ Alchemy.initAlchemyPreviewMode = ->
66
67
  return
67
68
  return
68
69
 
70
+ # Focus the element in the Alchemy preview window.
71
+ focusElement: (data) ->
72
+ element = @getElement(data.element_id)
73
+ if element
74
+ @selectElement(element)
75
+ else
76
+ console.warn('Could not focus element with id', data.element_id)
77
+
78
+ getElement: (element_id) ->
79
+ @elements.find (element) ->
80
+ element.dataset.alchemyElement == element_id.toString()
81
+
69
82
  # Focus the element editor in the Alchemy element window.
70
83
  focusElementEditor: (element) ->
71
- alchemy_window = window.parent
72
- target_id = element.getAttribute('data-alchemy-element')
73
- $element_editor = alchemy_window.$("#element_#{target_id}")
74
- elements_window = alchemy_window.Alchemy.ElementsWindow
75
- $element_editor.trigger("FocusElementEditor.Alchemy", target_id)
76
- elements_window.show() if elements_window.hidden
84
+ element_id = element.getAttribute('data-alchemy-element')
85
+ window.parent.postMessage
86
+ message: 'Alchemy.focusElementEditor'
87
+ element_id: element_id
88
+ , window.location.origin
77
89
  return
78
90
 
79
91
  getStyle: (state) ->
@@ -32,6 +32,10 @@ Alchemy.PreviewWindow =
32
32
  $iframe.attr 'src', $iframe.attr('src')
33
33
  true
34
34
 
35
+ postMessage: (data) ->
36
+ frameWindow = @currentWindow[0].contentWindow
37
+ frameWindow.postMessage(data, window.location.origin)
38
+
35
39
  _showSpinner: ->
36
40
  @reload = $('#reload_preview_button')
37
41
  @spinner = new Alchemy.Spinner('small')
@@ -155,6 +155,22 @@
155
155
  }
156
156
  }
157
157
 
158
+ &.expanded {
159
+ &.not-fixed {
160
+ .nestable-elements {
161
+ box-shadow: inset 0 4px 8px -2px darken($medium-gray, 15%);
162
+ background-color: $medium-gray;
163
+ padding: 8px 4px 4px;
164
+
165
+ .add-nestable-element-button {
166
+ width: calc(50% - 8px);
167
+ margin: 4px;
168
+ text-align: center;
169
+ }
170
+ }
171
+ }
172
+ }
173
+
158
174
  &.dragged {
159
175
  border-style: dotted;
160
176
  overflow: hidden;
@@ -165,15 +181,6 @@
165
181
  }
166
182
  }
167
183
 
168
- &.with-contents,
169
- &.without-contents.not-nestable {
170
-
171
- .element-content {
172
- padding: 2*$default-padding 2*$default-padding 0;
173
- border-top: 1px solid $medium-gray;
174
- }
175
- }
176
-
177
184
  &.compact {
178
185
  .element-toolbar {
179
186
  visibility: hidden;
@@ -194,7 +201,6 @@
194
201
  }
195
202
 
196
203
  .element-footer {
197
- margin-top: 0;
198
204
  padding-top: 0;
199
205
  border-top: 0;
200
206
 
@@ -223,7 +229,7 @@
223
229
  }
224
230
 
225
231
  .element-content {
226
- padding: 4px 8px;
232
+ margin: 4px 8px;
227
233
  }
228
234
 
229
235
  .button_with_label {
@@ -253,8 +259,8 @@
253
259
  }
254
260
  }
255
261
 
256
- form {
257
- margin: 0;
262
+ .element-content {
263
+ margin: 2*$default-padding;
258
264
  }
259
265
 
260
266
  .validation_notice {
@@ -266,8 +272,7 @@
266
272
  }
267
273
 
268
274
  .message {
269
- width: 100%;
270
- margin: 2*$default-margin 0;
275
+ margin: 2*$default-margin;
271
276
  }
272
277
 
273
278
  .foot_note {
@@ -332,6 +337,7 @@
332
337
  .element-toolbar {
333
338
  padding: $default-padding 0;
334
339
  height: $element-toolbar-height;
340
+ border-bottom: 1px solid $medium-gray;
335
341
 
336
342
  .element_tools {
337
343
  float: left;
@@ -341,7 +347,6 @@
341
347
 
342
348
  .element-footer {
343
349
  border-top: 1px solid $medium-gray;
344
- margin: 8px 0 0 0;
345
350
  padding: 2*$default-padding;
346
351
  text-align: right;
347
352
 
@@ -762,21 +767,6 @@ textarea.has_tinymce {
762
767
  top: -1px;
763
768
  }
764
769
 
765
- .not-fixed .nestable-elements {
766
- box-shadow: inset 0 4px 8px -2px darken($medium-gray, 15%);
767
- background-color: $medium-gray;
768
-
769
- .expanded.element-editor>& {
770
- padding: 8px 4px 4px;
771
- }
772
-
773
- .add-nestable-element-button {
774
- width: calc(50% - 8px);
775
- margin: 4px;
776
- text-align: center;
777
- }
778
- }
779
-
780
770
  .is-fixed {
781
771
  &.with-contents {
782
772
  >.element-footer {
@@ -101,14 +101,10 @@ module Alchemy
101
101
  ].join(' ')
102
102
  end
103
103
 
104
- # Tells us, if we should show the element footer.
105
- def show_element_footer?(element, with_nestable_elements = nil)
104
+ # Tells us, if we should show the element footer and form inputs.
105
+ def element_editable?(element)
106
106
  return false if element.folded?
107
- if with_nestable_elements
108
- element.content_definitions.present? || element.taggable?
109
- else
110
- element.nestable_elements.empty?
111
- end
107
+ element.content_definitions.present? || element.taggable?
112
108
  end
113
109
  end
114
110
  end
@@ -90,19 +90,19 @@ module Alchemy
90
90
  belongs_to :language, optional: true
91
91
 
92
92
  belongs_to :creator,
93
- primary_key: Alchemy.user_class.primary_key,
93
+ primary_key: Alchemy.user_class_primary_key,
94
94
  class_name: Alchemy.user_class_name,
95
95
  foreign_key: :creator_id,
96
96
  optional: true
97
97
 
98
98
  belongs_to :updater,
99
- primary_key: Alchemy.user_class.primary_key,
99
+ primary_key: Alchemy.user_class_primary_key,
100
100
  class_name: Alchemy.user_class_name,
101
101
  foreign_key: :updater_id,
102
102
  optional: true
103
103
 
104
104
  belongs_to :locker,
105
- primary_key: Alchemy.user_class.primary_key,
105
+ primary_key: Alchemy.user_class_primary_key,
106
106
  class_name: Alchemy.user_class_name,
107
107
  foreign_key: :locked_by,
108
108
  optional: true
@@ -10,44 +10,47 @@
10
10
  <% if element.expanded? || element.fixed? %>
11
11
  <%= render 'alchemy/admin/elements/element_toolbar', element: element %>
12
12
 
13
- <%= form_for [alchemy, :admin, element], remote: true,
14
- html: {id: "element_#{element.id}_form".html_safe, class: 'element-content'} do |f| %>
13
+ <% element.definition[:message].tap do |message| %>
14
+ <%= render_message(:info, sanitize(message)) if message %>
15
+ <% end %>
15
16
 
16
- <div id="element_<%= element.id %>_errors" class="element_errors"></div>
17
+ <% element.definition[:warning].tap do |warning| %>
18
+ <%= render_message(:warning, sanitize(warning)) if warning %>
19
+ <% end %>
17
20
 
18
- <div id="element_<%= element.id %>_content" class="element-content-editors">
19
- <% element.definition[:message].tap do |message| %>
20
- <%= render_message(:info, sanitize(message)) if message %>
21
- <% end %>
22
- <% element.definition[:warning].tap do |warning| %>
23
- <%= render_message(:warning, sanitize(warning)) if warning %>
24
- <% end %>
25
- <% if lookup_context.exists?("#{element.name}_editor", ["alchemy/elements"], true) %>
26
- <%= render_editor(element) %>
27
- <% else %>
28
- <%= element_editor_for(element) do %>
29
- <% element.contents.each do |content| %>
30
- <%= render "alchemy/essences/#{content.essence_partial_name}_editor", {
31
- content: content
32
- } %>
21
+ <% if element_editable?(element) %>
22
+ <%= form_for [alchemy, :admin, element], remote: true,
23
+ html: {id: "element_#{element.id}_form".html_safe, class: 'element-content'} do |f| %>
24
+
25
+ <div id="element_<%= element.id %>_errors" class="element_errors"></div>
26
+
27
+ <div id="element_<%= element.id %>_content" class="element-content-editors">
28
+ <% if lookup_context.exists?("#{element.name}_editor", ["alchemy/elements"], true) %>
29
+ <%= render_editor(element) %>
30
+ <% else %>
31
+ <%= element_editor_for(element) do %>
32
+ <% element.contents.each do |content| %>
33
+ <%= render "alchemy/essences/#{content.essence_partial_name}_editor", {
34
+ content: content
35
+ } %>
36
+ <% end %>
33
37
  <% end %>
34
38
  <% end %>
35
- <% end %>
36
- </div>
37
-
38
- <% if element.taggable? %>
39
- <div class="autocomplete_tag_list">
40
- <%= f.label :tag_list %>
41
- <%= render 'alchemy/admin/partials/autocomplete_tag_list', f: f %>
42
39
  </div>
40
+
41
+ <% if element.taggable? %>
42
+ <div class="autocomplete_tag_list">
43
+ <%= f.label :tag_list %>
44
+ <%= render 'alchemy/admin/partials/autocomplete_tag_list', f: f %>
45
+ </div>
46
+ <% end %>
43
47
  <% end %>
48
+
49
+ <%= render 'alchemy/admin/elements/element_footer', element: element %>
44
50
  <% end %>
45
51
  <% end %>
46
52
 
47
53
  <% if element.nestable_elements.any? %>
48
- <% if show_element_footer?(element, :with_nestable_elements) %>
49
- <%= render 'alchemy/admin/elements/element_footer', element: element %>
50
- <% end %>
51
54
  <div class="nestable-elements">
52
55
  <%= content_tag :div,
53
56
  class: "nested-elements", data: {
@@ -82,8 +85,4 @@
82
85
  <% end %>
83
86
  </div>
84
87
  <% end %>
85
-
86
- <% if show_element_footer?(element) %>
87
- <%= render 'alchemy/admin/elements/element_footer', element: element %>
88
- <% end %>
89
88
  <% end %>
@@ -36,7 +36,7 @@
36
36
  Alchemy.closeCurrentDialog();
37
37
  Alchemy.Tinymce.init(<%= @element.richtext_contents_ids.to_json %>);
38
38
  Alchemy.PreviewWindow.refresh(function() {
39
- Alchemy.ElementEditors.selectElementInPreview(<%= @element.id %>);
39
+ Alchemy.ElementEditors.focusElementPreview(<%= @element.id %>);
40
40
  });
41
41
 
42
42
  $el = $('#element_<%= @element.id %>');
@@ -9,7 +9,7 @@
9
9
  $el.trigger('SaveElement.Alchemy', {previewText: '<%= j sanitize(@element.preview_text) %>'});
10
10
  Alchemy.growl('<%= Alchemy.t(:element_saved) %>');
11
11
  Alchemy.PreviewWindow.refresh(function() {
12
- Alchemy.ElementEditors.selectElementInPreview(<%= @element.id %>);
12
+ Alchemy.ElementEditors.focusElementPreview(<%= @element.id %>);
13
13
  });
14
14
 
15
15
  <%- else -%>
@@ -5,6 +5,7 @@
5
5
  # Alchemy has some defaults for user model name and login logout path names:
6
6
  #
7
7
  # +Alchemy.user_class_name+ defaults to +'User'+
8
+ # +Alchemy.user_class_primary_key+ defaults to +:id+
8
9
  # +Alchemy.current_user_method defaults to +'current_user'+
9
10
  # +Alchemy.signup_path defaults to +'/signup'+
10
11
  # +Alchemy.login_path defaults to +'/login'+
@@ -14,17 +15,19 @@
14
15
  # Anyway, you can tell Alchemy about your authentication model configuration:
15
16
  #
16
17
  # 1. Your user class name - @see: Alchemy.user_class
17
- # 2. A method on your ApplicationController to get current user -
18
+ # 2. Your users table primary key - @see: Alchemy.user_class_primary_key
19
+ # 3. A method on your ApplicationController to get current user -
18
20
  # @see: Alchemy.current_user_method
19
- # 3. The path to the signup form - @see: Alchemy.signup_path
20
- # 4. The path to the login form - @see: Alchemy.login_path
21
- # 5. The path to the logout method - @see: Alchemy.logout_path
22
- # 6. The http verb for the logout method - @see: Alchemy.logout_method
21
+ # 4. The path to the signup form - @see: Alchemy.signup_path
22
+ # 5. The path to the login form - @see: Alchemy.login_path
23
+ # 6. The path to the logout method - @see: Alchemy.logout_path
24
+ # 7. The http verb for the logout method - @see: Alchemy.logout_method
23
25
  #
24
26
  # == Example
25
27
  #
26
28
  # # config/initializers/alchemy.rb
27
29
  # Alchemy.user_class_name = 'Admin'
30
+ # Alchemy.user_class_primary_key = :user_id
28
31
  # Alchemy.current_user_method = 'current_admin'
29
32
  # Alchemy.signup_path = '/auth/signup'
30
33
  # Alchemy.login_path = '/auth/login'
@@ -42,6 +45,7 @@
42
45
  #
43
46
  module Alchemy
44
47
  mattr_accessor :user_class_name,
48
+ :user_class_primary_key,
45
49
  :current_user_method,
46
50
  :signup_path,
47
51
  :login_path,
@@ -51,6 +55,7 @@ module Alchemy
51
55
  # Defaults
52
56
  #
53
57
  @@user_class_name = 'User'
58
+ @@user_class_primary_key = :id
54
59
  @@current_user_method = 'current_user'
55
60
  @@signup_path = '/signup'
56
61
  @@login_path = '/login'
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'tasks/element_views_updater'
4
+
5
+ module Alchemy
6
+ class Upgrader::FourPointFour < Upgrader
7
+ class << self
8
+ def rename_element_views
9
+ desc "Remove '_view' suffix from element views."
10
+ Alchemy::Upgrader::Tasks::ElementViewsUpdater.new.rename_element_views
11
+ end
12
+
13
+ def update_local_variable
14
+ desc 'Update element views local variable to element name.'
15
+ Alchemy::Upgrader::Tasks::ElementViewsUpdater.new.update_local_variable
16
+ end
17
+
18
+ def alchemy_4_4_todos
19
+ notice = <<-NOTE.strip_heredoc
20
+
21
+ ℹ️ Element editor partials are deprecated
22
+ -----------------------------------------
23
+
24
+ The element editor partials are not needed anymore. They still work, but in order to
25
+ prepare the Alchemy 5 upgrade your should consider removing them now.
26
+
27
+ In order to update check if you have any messages in your editor partials and move them
28
+ to either a `warning` or `message` in your element definition.
29
+
30
+ Also check if you pass any values to EssenceSelects `select_values`. Move static values
31
+ to the `settings` of your content definition and either use EssencePage for referencing
32
+ pages or create a custom essence for other dynamic values.
33
+
34
+
35
+ ℹ️ The `_view` suffix of Element view partials is deprecated
36
+ -----------------------------------------------------------
37
+
38
+ The element view partials do not need the `_view` suffix anymore. Your files have been
39
+ renamed.
40
+
41
+ The local variable in your element views has been replaced by a variable named after the
42
+ element itself. A "article" element has a "_article.html.erb" partial and therefore
43
+ a `article` local variable now.
44
+
45
+ The former `element` variable is still present, though.
46
+
47
+ NOTE
48
+ todo notice, 'Alchemy v4.4 TODO'
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'alchemy/upgrader'
4
+
5
+ module Alchemy::Upgrader::Tasks
6
+ class ElementViewsUpdater < Thor
7
+ include Thor::Actions
8
+
9
+ no_tasks do
10
+ def rename_element_views
11
+ puts "-- Removing '_view' suffix from element views"
12
+
13
+ Dir.glob("#{elements_view_folder}/*_view.*").each do |file|
14
+ FileUtils.mv(file, file.to_s.sub(/_view/, ''))
15
+ end
16
+ end
17
+
18
+ def update_local_variable
19
+ puts "-- Updating element views local variable to element name"
20
+
21
+ Alchemy::Element.definitions.map { |e| e['name'] }.each do |name|
22
+ view = Dir.glob("#{elements_view_folder}/_#{name}.*").last
23
+ gsub_file(view, /\b#{name}_view\b/, name)
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def elements_view_folder
31
+ Rails.root.join('app', 'views', 'alchemy', 'elements')
32
+ end
33
+ end
34
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "4.4.0"
4
+ VERSION = "4.4.1"
5
5
 
6
6
  def self.version
7
7
  VERSION
@@ -34,5 +34,32 @@ namespace :alchemy do
34
34
  task remove_orphaned_contents: [:environment] do
35
35
  Alchemy::Tidy.remove_orphaned_contents
36
36
  end
37
+
38
+ desc "List Alchemy elements usage"
39
+ task elements_usage: :environment do
40
+ puts "\n"
41
+ removable_elements = []
42
+ names = Alchemy::Element.definitions.map { |e| e['name'] }
43
+ longest_name = names.max_by { |name| name.to_s.length }.length + 1
44
+ names.sort.each do |name|
45
+ names = Alchemy::Element.where(name: name)
46
+ count = names.count
47
+ page_count = Alchemy::Page.where(id: names.pluck(:page_id)).published.count
48
+ if count.zero?
49
+ removable_elements.push(name)
50
+ else
51
+ spacer = ' ' * (longest_name - name.length)
52
+ puts "#{name}#{spacer}is used\t#{count}\ttime(s) on\t#{page_count}\tpublic page(s)"
53
+ end
54
+ end
55
+ if removable_elements.many?
56
+ puts "\n"
57
+ puts "These elements can probably be removed. They are not used anywhere:"
58
+ puts "\n"
59
+ removable_elements.each do |name|
60
+ puts name
61
+ end
62
+ end
63
+ end
37
64
  end
38
65
  end
@@ -6,7 +6,8 @@ namespace :alchemy do
6
6
  task upgrade: [
7
7
  'alchemy:upgrade:prepare',
8
8
  'alchemy:upgrade:4.1:run', 'alchemy:upgrade:4.1:todo',
9
- 'alchemy:upgrade:4.2:run', 'alchemy:upgrade:4.2:todo'
9
+ 'alchemy:upgrade:4.2:run', 'alchemy:upgrade:4.2:todo',
10
+ 'alchemy:upgrade:4.4:run', 'alchemy:upgrade:4.4:todo'
10
11
  ] do
11
12
  Alchemy::Upgrader.display_todos
12
13
  end
@@ -105,5 +106,35 @@ namespace :alchemy do
105
106
  Alchemy::Upgrader::FourPointTwo.alchemy_4_2_todos
106
107
  end
107
108
  end
109
+
110
+ desc 'Upgrade Alchemy to v4.4'
111
+ task '4.4' => [
112
+ 'alchemy:upgrade:prepare',
113
+ 'alchemy:upgrade:4.4:run',
114
+ 'alchemy:upgrade:4.4:todo'
115
+ ] do
116
+ Alchemy::Upgrader.display_todos
117
+ end
118
+
119
+ namespace '4.4' do
120
+ task run: [
121
+ 'alchemy:upgrade:4.4:rename_element_views',
122
+ 'alchemy:upgrade:4.4:update_local_variable'
123
+ ]
124
+
125
+ desc "Remove '_view' suffix from element views."
126
+ task rename_element_views: [:environment] do
127
+ Alchemy::Upgrader::FourPointFour.rename_element_views
128
+ end
129
+
130
+ desc 'Update element views local variable to element name.'
131
+ task update_local_variable: [:environment] do
132
+ Alchemy::Upgrader::FourPointFour.update_local_variable
133
+ end
134
+
135
+ task :todo do
136
+ Alchemy::Upgrader::FourPointFour.alchemy_4_4_todos
137
+ end
138
+ end
108
139
  end
109
140
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.0
4
+ version: 4.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2020-01-06 00:00:00.000000000 Z
16
+ date: 2020-01-08 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: active_model_serializers
@@ -1051,11 +1051,13 @@ files:
1051
1051
  - lib/alchemy/test_support/shared_uploader_examples.rb
1052
1052
  - lib/alchemy/tinymce.rb
1053
1053
  - lib/alchemy/upgrader.rb
1054
+ - lib/alchemy/upgrader/four_point_four.rb
1054
1055
  - lib/alchemy/upgrader/four_point_one.rb
1055
1056
  - lib/alchemy/upgrader/four_point_two.rb
1056
1057
  - lib/alchemy/upgrader/tasks/cells_migration.rb
1057
1058
  - lib/alchemy/upgrader/tasks/cells_upgrader.rb
1058
1059
  - lib/alchemy/upgrader/tasks/element_partial_name_variable_updater.rb
1060
+ - lib/alchemy/upgrader/tasks/element_views_updater.rb
1059
1061
  - lib/alchemy/upgrader/tasks/harden_acts_as_taggable_on_migrations.rb
1060
1062
  - lib/alchemy/upgrader/tasks/picture_gallery_migration.rb
1061
1063
  - lib/alchemy/upgrader/tasks/picture_gallery_upgrader.rb
@@ -1188,7 +1190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1188
1190
  version: '0'
1189
1191
  requirements:
1190
1192
  - ImageMagick (libmagick), v6.6 or greater.
1191
- rubygems_version: 3.1.2
1193
+ rubygems_version: 3.0.3
1192
1194
  signing_key:
1193
1195
  specification_version: 4
1194
1196
  summary: A powerful, userfriendly and flexible CMS for Rails 5