alchemy_cms 8.4.3 → 8.4.4
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/admin.css +1 -1
- data/app/assets/builds/alchemy/preview.min.js +1 -1
- data/app/components/alchemy/ingredients/picture_view.rb +4 -2
- data/app/javascript/preview.js +6 -1
- data/app/jobs/alchemy/invalidate_elements_cache_job.rb +1 -0
- data/app/models/alchemy/page.rb +6 -3
- data/app/models/alchemy/storage_adapter/active_storage.rb +6 -0
- data/app/models/alchemy/storage_adapter/dragonfly.rb +6 -0
- data/app/models/alchemy/storage_adapter.rb +1 -0
- data/app/models/concerns/alchemy/picture_thumbnails.rb +7 -4
- data/app/stylesheets/alchemy/admin/forms.scss +1 -1
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +14 -2
- data/lib/alchemy/version.rb +1 -1
- metadata +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){"use strict";const e={outline:"","outline-offset":"",cursor:""},t={outline:"2px dashed #f0b437","outline-offset":"4px",cursor:"pointer"},n={outline:"2px dashed #90b9d0","outline-offset":"4px"};let o=[],s=null;function a(e){i(e),s=e,Object.assign(e.style,n),e.scrollIntoView({behavior:"smooth",block:"start"})}function i(t){o.forEach(n=>{n!==t&&Object.assign(n.style,e)}),s=null}function c(e){const t=(n=e.element_id,o.find(e=>e.dataset.alchemyElement===n.toString()));var n;t?a(t):console.warn("Could not focus element with id",e.element_id)}function l(n){n.addEventListener("mouseover",()=>{n!==s&&Object.assign(n.style,t)}),n.addEventListener("mouseout",()=>{n!==s&&Object.assign(n.style,e)})}function d(e){const t=e.target.closest("[data-alchemy-element]");return t&&(a(t),function(e){window.parent.postMessage({message:"Alchemy.focusElementEditor",element_id:e.dataset.alchemyElement},window.location.origin)}(t)),t}function r(e){(function(e){if(e.closest("a"))return!0;const t=e.closest("button, input");return Boolean(t?.form)&&["submit","image"].includes(t.type)})(e.target)&&d(e)
|
|
1
|
+
!function(){"use strict";const e={outline:"","outline-offset":"",cursor:""},t={outline:"2px dashed #f0b437","outline-offset":"4px",cursor:"pointer"},n={outline:"2px dashed #90b9d0","outline-offset":"4px"};let o=[],s=null;function a(e){i(e),s=e,Object.assign(e.style,n),e.scrollIntoView({behavior:"smooth",block:"start"})}function i(t){o.forEach(n=>{n!==t&&Object.assign(n.style,e)}),s=null}function c(e){const t=(n=e.element_id,o.find(e=>e.dataset.alchemyElement===n.toString()));var n;t?a(t):console.warn("Could not focus element with id",e.element_id)}function l(n){n.addEventListener("mouseover",()=>{n!==s&&Object.assign(n.style,t)}),n.addEventListener("mouseout",()=>{n!==s&&Object.assign(n.style,e)})}function d(e){const t=e.target.closest("[data-alchemy-element]");return t&&(a(t),function(e){window.parent.postMessage({message:"Alchemy.focusElementEditor",element_id:e.dataset.alchemyElement},window.location.origin)}(t)),t}function r(e){(function(e){if(e.closest("a"))return!0;const t=e.closest("button, input");return Boolean(t?.form)&&["submit","image"].includes(t.type)})(e.target)&&(d(e),e.stopPropagation(),e.preventDefault())}function u(){window.addEventListener("message",e=>{switch(e.data.message){case"Alchemy.blurElements":i();break;case"Alchemy.focusElement":c(e.data);break;default:console.info("Received unknown message!",e.data)}}),window.addEventListener("click",r,{capture:!0}),window.addEventListener("click",d),window.addEventListener("turbo:before-visit",e=>e.preventDefault()),o=Array.from(document.querySelectorAll("[data-alchemy-element]")),o.forEach(l),window.parent.postMessage({message:"Alchemy.previewReady"},window.location.origin)}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",u,{once:!0}):u()}();
|
|
@@ -43,7 +43,7 @@ module Alchemy
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def call
|
|
46
|
-
return if picture.blank?
|
|
46
|
+
return if picture.blank? || src.nil?
|
|
47
47
|
|
|
48
48
|
output = caption ? img_tag + caption : img_tag
|
|
49
49
|
|
|
@@ -72,7 +72,9 @@ module Alchemy
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def src
|
|
75
|
-
|
|
75
|
+
return @_src if defined?(@_src)
|
|
76
|
+
|
|
77
|
+
@_src = ingredient.picture_url(picture_options)
|
|
76
78
|
end
|
|
77
79
|
|
|
78
80
|
def img_tag
|
data/app/javascript/preview.js
CHANGED
|
@@ -101,7 +101,8 @@ function navigates(target) {
|
|
|
101
101
|
// Client side routers navigate from click handlers on the link itself, so
|
|
102
102
|
// navigating clicks have to be taken before the event reaches the page.
|
|
103
103
|
function onNavigatingClick(event) {
|
|
104
|
-
if (navigates(event.target)
|
|
104
|
+
if (navigates(event.target)) {
|
|
105
|
+
selectClickedElement(event)
|
|
105
106
|
event.stopPropagation()
|
|
106
107
|
event.preventDefault()
|
|
107
108
|
}
|
|
@@ -123,6 +124,10 @@ function init() {
|
|
|
123
124
|
|
|
124
125
|
window.addEventListener("click", onNavigatingClick, { capture: true })
|
|
125
126
|
window.addEventListener("click", selectClickedElement)
|
|
127
|
+
// Turbo.visit can be called from any click handler, not only from links.
|
|
128
|
+
window.addEventListener("turbo:before-visit", (event) =>
|
|
129
|
+
event.preventDefault()
|
|
130
|
+
)
|
|
126
131
|
|
|
127
132
|
elements = Array.from(document.querySelectorAll("[data-alchemy-element]"))
|
|
128
133
|
elements.forEach(observeElement)
|
|
@@ -11,6 +11,7 @@ module Alchemy
|
|
|
11
11
|
|
|
12
12
|
all_element_ids = get_all_element_ids(elements, element_ids)
|
|
13
13
|
Element.where(id: all_element_ids).touch_all
|
|
14
|
+
PageVersion.scheduled.where(id: elements.select(:page_version_id)).touch_all
|
|
14
15
|
|
|
15
16
|
page_ids = elements.joins(page_version: :page).distinct.pluck("alchemy_pages.id")
|
|
16
17
|
Page.where(id: page_ids).touch_all
|
data/app/models/alchemy/page.rb
CHANGED
|
@@ -453,14 +453,17 @@ module Alchemy
|
|
|
453
453
|
# Returns true if the draft version has changes not yet published.
|
|
454
454
|
#
|
|
455
455
|
# Compares the updated_at timestamp of the draft_version against the
|
|
456
|
-
#
|
|
457
|
-
#
|
|
456
|
+
# page's published_at timestamp. The public_version's updated_at is not
|
|
457
|
+
# used, because it gets touched to invalidate caches. It only serves as
|
|
458
|
+
# fallback for public versions created without publishing (via +public_on=+).
|
|
459
|
+
# If there's no public_version, the page has never been published and
|
|
460
|
+
# always has unpublished changes.
|
|
458
461
|
#
|
|
459
462
|
# @return [Boolean]
|
|
460
463
|
def has_unpublished_changes?
|
|
461
464
|
return true unless public_version
|
|
462
465
|
|
|
463
|
-
draft_version.updated_at > public_version.updated_at
|
|
466
|
+
draft_version.updated_at > (published_at || public_version.updated_at)
|
|
464
467
|
end
|
|
465
468
|
|
|
466
469
|
# Sets the public_on date on the published version
|
|
@@ -158,6 +158,12 @@ module Alchemy
|
|
|
158
158
|
picture.image_file&.variable?
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
+
# @param [String, Symbol] format file extension
|
|
162
|
+
# @return [TrueClass, FalseClass]
|
|
163
|
+
def can_convert_to?(format)
|
|
164
|
+
Marcel::MimeType.for(extension: format.to_s).in?(::ActiveStorage.variable_content_types)
|
|
165
|
+
end
|
|
166
|
+
|
|
161
167
|
# @param [Alchemy::Picture]
|
|
162
168
|
# @return [String]
|
|
163
169
|
def image_file_basename(picture)
|
|
@@ -164,6 +164,12 @@ module Alchemy
|
|
|
164
164
|
image_file_extension(picture).in?(CONVERTIBLE_FILE_FORMATS)
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
+
# @param [String, Symbol] format file extension
|
|
168
|
+
# @return [TrueClass, FalseClass]
|
|
169
|
+
def can_convert_to?(format)
|
|
170
|
+
format.to_s.in?(CONVERTIBLE_FILE_FORMATS)
|
|
171
|
+
end
|
|
172
|
+
|
|
167
173
|
# @param [Alchemy::Picture]
|
|
168
174
|
# @return [String]
|
|
169
175
|
def image_file_basename(picture)
|
|
@@ -33,11 +33,13 @@ module Alchemy
|
|
|
33
33
|
# @option options crop [Boolean]
|
|
34
34
|
# If set to true the picture will be cropped to fit the size value.
|
|
35
35
|
#
|
|
36
|
-
# @return [String]
|
|
36
|
+
# @return [String, nil] +nil+ if no picture is assigned or the url could not be generated
|
|
37
37
|
def picture_url(options = {})
|
|
38
38
|
return if picture.nil?
|
|
39
39
|
|
|
40
|
-
picture.url(picture_url_options(options))
|
|
40
|
+
url = picture.url(picture_url_options(options))
|
|
41
|
+
Logger.warn("Could not generate url for picture #{picture.id}") if url.nil?
|
|
42
|
+
url
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
# Picture rendering options
|
|
@@ -47,7 +49,7 @@ module Alchemy
|
|
|
47
49
|
#
|
|
48
50
|
# The render format is taken from the +format+ option, the +format+ setting
|
|
49
51
|
# of the ingredient definition or the +default_render_format+ of the picture.
|
|
50
|
-
# A format is only applied if the picture can be converted.
|
|
52
|
+
# A format is only applied if the picture can be converted into it.
|
|
51
53
|
#
|
|
52
54
|
# @param options [Hash] Options that override the defaults (i.e. +size+ or +format+ of a srcset entry)
|
|
53
55
|
#
|
|
@@ -157,7 +159,8 @@ module Alchemy
|
|
|
157
159
|
private
|
|
158
160
|
|
|
159
161
|
def picture_render_format(format)
|
|
160
|
-
if format.present? && picture.has_convertible_format?
|
|
162
|
+
if format.present? && picture.has_convertible_format? &&
|
|
163
|
+
Alchemy.storage_adapter.can_convert_to?(format)
|
|
161
164
|
format.to_s
|
|
162
165
|
else
|
|
163
166
|
picture.default_render_format
|
|
@@ -103,8 +103,9 @@ RSpec.shared_examples_for "having picture thumbnails" do
|
|
|
103
103
|
expect(picture).to receive(:url) { nil }
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
it "returns
|
|
107
|
-
|
|
106
|
+
it "returns nil and logs a warning" do
|
|
107
|
+
expect(Alchemy::Logger).to receive(:warn).with(/Could not generate url for picture/)
|
|
108
|
+
is_expected.to be_nil
|
|
108
109
|
end
|
|
109
110
|
end
|
|
110
111
|
end
|
|
@@ -204,6 +205,17 @@ RSpec.shared_examples_for "having picture thumbnails" do
|
|
|
204
205
|
expect(picture_url_options[:format]).to eq "png"
|
|
205
206
|
end
|
|
206
207
|
end
|
|
208
|
+
|
|
209
|
+
context "with format the picture can not be converted to" do
|
|
210
|
+
before do
|
|
211
|
+
allow(record).to receive(:settings) { {format: "svg"} }
|
|
212
|
+
allow(picture).to receive(:default_render_format) { "webp" }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "includes the pictures default render format" do
|
|
216
|
+
expect(picture_url_options[:format]).to eq "webp"
|
|
217
|
+
end
|
|
218
|
+
end
|
|
207
219
|
end
|
|
208
220
|
|
|
209
221
|
context "with picture not having a convertible format" do
|
data/lib/alchemy/version.rb
CHANGED