alchemy_cms 8.4.1 → 8.4.2
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.
- checksums.yaml +4 -4
- data/app/assets/builds/alchemy/alchemy_admin.min.js +1 -1
- data/app/assets/builds/alchemy/alchemy_admin.min.js.map +1 -1
- data/app/components/alchemy/admin/main_navigation/menu.rb +19 -2
- data/app/javascript/alchemy_admin/components/elements_window.js +2 -0
- data/app/javascript/alchemy_admin/components/preview_window.js +8 -1
- data/lib/alchemy/configurations/menu_item.rb +29 -5
- data/lib/alchemy/upgrader/eight_four.rb +6 -3
- data/lib/alchemy/upgrader/register_module_rewriter.rb +24 -7
- data/lib/alchemy/version.rb +1 -1
- metadata +1 -1
|
@@ -11,9 +11,26 @@ module Alchemy
|
|
|
11
11
|
</div>
|
|
12
12
|
ERB
|
|
13
13
|
|
|
14
|
+
# Entries without a position that were inserted between Alchemy's own
|
|
15
|
+
# entries are listed after the positioned entry preceding them, so
|
|
16
|
+
# +Alchemy.config.menu.insert+ can replace the deprecated position.
|
|
17
|
+
# Appended entries without a position are listed last.
|
|
14
18
|
def items
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
menu = Alchemy.config.menu.to_a
|
|
20
|
+
core_names = Alchemy::Configurations::Menu::DEFAULT.map { |entry| entry[:name] }
|
|
21
|
+
last_core_index = menu.rindex { |item| core_names.include?(item.name) } || -1
|
|
22
|
+
preceding_position = 0
|
|
23
|
+
menu.each_with_index.map do |item, index|
|
|
24
|
+
preceding_position = item.position if item.position
|
|
25
|
+
key = if item.position
|
|
26
|
+
[item.position, 0, index]
|
|
27
|
+
elsif index < last_core_index
|
|
28
|
+
[preceding_position, 1, index]
|
|
29
|
+
else
|
|
30
|
+
[Float::INFINITY, 0, index]
|
|
31
|
+
end
|
|
32
|
+
[item, key]
|
|
33
|
+
end.sort_by(&:last).map(&:first)
|
|
17
34
|
end
|
|
18
35
|
end
|
|
19
36
|
end
|
|
@@ -32,6 +32,8 @@ class ElementsWindow extends HTMLElement {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
#onWindowMessage = (event) => {
|
|
35
|
+
if (event.source !== this.previewWindow?.contentWindow) return
|
|
36
|
+
|
|
35
37
|
const data = event.data
|
|
36
38
|
if (data?.message == "Alchemy.focusElementEditor") {
|
|
37
39
|
const element = document.getElementById(`element_${data.element_id}`)
|
|
@@ -5,6 +5,7 @@ class PreviewWindow extends HTMLIFrameElement {
|
|
|
5
5
|
#afterLoad
|
|
6
6
|
#reloadIcon
|
|
7
7
|
#loadTimeout
|
|
8
|
+
#previewOrigin = null
|
|
8
9
|
|
|
9
10
|
handleEvent(evt) {
|
|
10
11
|
if (evt.type === "load") {
|
|
@@ -15,7 +16,10 @@ class PreviewWindow extends HTMLIFrameElement {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
#onPreviewReady = (event) => {
|
|
19
|
+
if (event.source !== this.contentWindow) return
|
|
20
|
+
|
|
18
21
|
if (event.data.message === "Alchemy.previewReady") {
|
|
22
|
+
this.#previewOrigin = event.origin
|
|
19
23
|
this.#clearLoadTimeout()
|
|
20
24
|
this.#stopSpinner()
|
|
21
25
|
// Deliberately does not resolve #afterLoad: previewReady fires before the
|
|
@@ -47,7 +51,9 @@ class PreviewWindow extends HTMLIFrameElement {
|
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
postMessage(data) {
|
|
50
|
-
this
|
|
54
|
+
if (this.#previewOrigin) {
|
|
55
|
+
this.contentWindow.postMessage(data, this.#previewOrigin)
|
|
56
|
+
}
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
resize(width) {
|
|
@@ -55,6 +61,7 @@ class PreviewWindow extends HTMLIFrameElement {
|
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
refresh(url) {
|
|
64
|
+
this.#previewOrigin = null
|
|
58
65
|
this.#startSpinner()
|
|
59
66
|
|
|
60
67
|
if (url) {
|
|
@@ -24,14 +24,38 @@ module Alchemy
|
|
|
24
24
|
option :nested_actions, :collection, item_type: :string
|
|
25
25
|
option :nested, :collection, item_type: :configuration, config_class: MenuItem
|
|
26
26
|
|
|
27
|
+
alias_method :set_position, :position=
|
|
28
|
+
private :set_position
|
|
29
|
+
|
|
30
|
+
# Alchemy's own entries still need their positions for sorting,
|
|
31
|
+
# so only positions of other entries are deprecated.
|
|
32
|
+
def position=(value)
|
|
33
|
+
if value && Menu::DEFAULT.none? { |entry| entry[:name] == name }
|
|
34
|
+
Alchemy::Deprecation.warn(
|
|
35
|
+
"The `position` of menu entries is deprecated and will be removed in Alchemy 9.0, " \
|
|
36
|
+
"which lists the entries in the order of `Alchemy.config.menu`. " \
|
|
37
|
+
"Use `Alchemy.config.menu.insert` to place the #{name.inspect} entry instead."
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
set_position(value)
|
|
41
|
+
end
|
|
42
|
+
|
|
27
43
|
def self.from_legacy_hash(hash)
|
|
28
44
|
hash = hash.to_h.deep_stringify_keys
|
|
29
|
-
new(
|
|
45
|
+
item = new(
|
|
30
46
|
from_legacy_navigation(hash["navigation"] || {}, engine_name: hash["engine_name"]).merge(
|
|
31
|
-
"name" => hash["name"]
|
|
32
|
-
"position" => hash["position"]
|
|
47
|
+
"name" => hash["name"]
|
|
33
48
|
).compact
|
|
34
49
|
)
|
|
50
|
+
# +register_module+ is deprecated already
|
|
51
|
+
item.send(:set_position, hash["position"]) if hash["position"]
|
|
52
|
+
item
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Positions sort entries around the default menu's entries, which use
|
|
56
|
+
# the positions 1 to 7, so +4.1+ maps to the index before Sites.
|
|
57
|
+
def self.index_for_legacy_position(position)
|
|
58
|
+
[position.ceil - 1, 0].max
|
|
35
59
|
end
|
|
36
60
|
|
|
37
61
|
def self.from_legacy_navigation(navigation, engine_name:)
|
|
@@ -82,8 +106,8 @@ module Alchemy
|
|
|
82
106
|
current_path = view_context.request.path
|
|
83
107
|
path_matches = if match_path
|
|
84
108
|
match_path.match?(current_path)
|
|
85
|
-
elsif (own_path = local_path(view_context))
|
|
86
|
-
current_path == own_path || current_path.start_with?("#{own_path
|
|
109
|
+
elsif (own_path = local_path(view_context)&.chomp("/"))
|
|
110
|
+
current_path.chomp("/") == own_path || current_path.start_with?("#{own_path}/")
|
|
87
111
|
end
|
|
88
112
|
|
|
89
113
|
path_matches || [self, *nested].any? do |entry|
|
|
@@ -169,10 +169,11 @@ module Alchemy
|
|
|
169
169
|
list = ->(files) { files.map { |file| " - #{Pathname.new(file).relative_path_from(Rails.root)}" }.join("\n") }
|
|
170
170
|
|
|
171
171
|
if rewritten.any?
|
|
172
|
-
todo(<<~TODO.strip, "`register_module` calls were rewritten to `Alchemy.config.menu
|
|
172
|
+
todo(<<~TODO.strip, "`register_module` calls were rewritten to `Alchemy.config.menu`")
|
|
173
173
|
`Alchemy::Modules.register_module` is deprecated and will be removed in
|
|
174
174
|
Alchemy 9.0. We rewrote its calls in the following initializers to
|
|
175
|
-
`Alchemy.config.menu.add
|
|
175
|
+
`Alchemy.config.menu.add`, or to `Alchemy.config.menu.insert` if they
|
|
176
|
+
had a position between Alchemy's own entries:
|
|
176
177
|
|
|
177
178
|
#{list.call(rewritten)}
|
|
178
179
|
|
|
@@ -212,7 +213,9 @@ module Alchemy
|
|
|
212
213
|
the former `navigation` hash now live on the entry itself, its `name`
|
|
213
214
|
is now `title`, `sub_navigation` is now `children`, `icon-style` is now
|
|
214
215
|
`icon_style`, `data: {turbo: false}` is now `turbo: false`, and `params`
|
|
215
|
-
is no longer supported.
|
|
216
|
+
is no longer supported. Instead of a `position`, use
|
|
217
|
+
`config.menu.insert(index, ...)` to place an entry between Alchemy's
|
|
218
|
+
own entries, e.g. `4` to place it between Languages and Sites.
|
|
216
219
|
|
|
217
220
|
Call `config.menu.add` once at boot and not inside `to_prepare`, as it
|
|
218
221
|
does not skip entries that are already present like `register_module`
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
module Alchemy
|
|
4
4
|
class Upgrader
|
|
5
5
|
# Rewrites +Alchemy::Modules.register_module+ calls with a static literal
|
|
6
|
-
# argument into +Alchemy.config.menu.add+ calls.
|
|
6
|
+
# argument into +Alchemy.config.menu.add+ calls, or +Alchemy.config.menu.insert+
|
|
7
|
+
# calls if they have a position within the default menu.
|
|
7
8
|
#
|
|
8
9
|
# Calls inside a +to_prepare+ block are guarded by the entry's name, because
|
|
9
10
|
# +Alchemy.config.menu.add+ does not skip entries that are already present.
|
|
@@ -15,7 +16,7 @@ module Alchemy
|
|
|
15
16
|
RECEIVERS = ["Alchemy::Modules", "::Alchemy::Modules"].freeze
|
|
16
17
|
|
|
17
18
|
KEYS = %w[
|
|
18
|
-
name title engine_name
|
|
19
|
+
name title engine_name icon icon_style image inline_image turbo
|
|
19
20
|
controller action nested_controllers nested_actions children nested
|
|
20
21
|
].freeze
|
|
21
22
|
|
|
@@ -70,24 +71,36 @@ module Alchemy
|
|
|
70
71
|
return unless arguments.first.is_a?(Prism::HashNode) || arguments.first.is_a?(Prism::KeywordHashNode)
|
|
71
72
|
return unless heredocs_inside?(arguments.first, call, source)
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
definition = literal(arguments.first)
|
|
75
|
+
item = Alchemy::Configurations::MenuItem.from_legacy_hash(definition)
|
|
74
76
|
return if in_to_prepare && item.name.blank?
|
|
75
77
|
|
|
78
|
+
index = menu_index(definition["position"])
|
|
79
|
+
|
|
76
80
|
indent = " " * call.location.start_column
|
|
77
81
|
if in_to_prepare
|
|
78
82
|
<<~RUBY.chomp
|
|
79
83
|
unless Alchemy.config.menu.any? { |item| item.name == #{item.name.inspect} }
|
|
80
|
-
#{indent} #{menu_add(item, "#{indent} ")}
|
|
84
|
+
#{indent} #{menu_add(item, "#{indent} ", index)}
|
|
81
85
|
#{indent}end
|
|
82
86
|
RUBY
|
|
83
87
|
else
|
|
84
|
-
menu_add(item, indent)
|
|
88
|
+
menu_add(item, indent, index)
|
|
85
89
|
end
|
|
86
90
|
rescue NonLiteralError, Alchemy::Configuration::ConfigurationError
|
|
87
91
|
nil
|
|
88
92
|
end
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
# @return [Integer, nil] The index to insert the entry at or +nil+ to append it
|
|
95
|
+
def menu_index(position)
|
|
96
|
+
return if position.nil?
|
|
97
|
+
raise NonLiteralError unless position.is_a?(Numeric)
|
|
98
|
+
|
|
99
|
+
index = Alchemy::Configurations::MenuItem.index_for_legacy_position(position)
|
|
100
|
+
index if index < Alchemy::Configurations::Menu::DEFAULT.size
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def menu_add(item, indent, index)
|
|
91
104
|
pairs = attributes(item).map do |key, value|
|
|
92
105
|
if key == "children" || key == "nested"
|
|
93
106
|
entries = value.map { |entry| "#{indent} #{inline_hash(entry)}" }
|
|
@@ -96,7 +109,11 @@ module Alchemy
|
|
|
96
109
|
"#{indent} #{key}: #{value.inspect}"
|
|
97
110
|
end
|
|
98
111
|
end
|
|
99
|
-
|
|
112
|
+
if index
|
|
113
|
+
"Alchemy.config.menu.insert(\n#{indent} #{index},\n#{pairs.join(",\n")}\n#{indent})"
|
|
114
|
+
else
|
|
115
|
+
"Alchemy.config.menu.add(\n#{pairs.join(",\n")}\n#{indent})"
|
|
116
|
+
end
|
|
100
117
|
end
|
|
101
118
|
|
|
102
119
|
def inline_hash(item)
|
data/lib/alchemy/version.rb
CHANGED