alchemy_cms 4.4.0 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
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