Closes #20211: Use thumbnails for ImageAttachment hover previews to improve page load performance (#21386)
This commit is contained in:
parent
02ffdd9d5d
commit
23f1c86e9c
|
|
@ -39,9 +39,20 @@ __all__ = (
|
|||
)
|
||||
|
||||
IMAGEATTACHMENT_IMAGE = """
|
||||
{% load thumbnail %}
|
||||
{% if record.image %}
|
||||
<a href="{{ record.image.url }}" target="_blank" class="image-preview" data-bs-placement="top">
|
||||
<i class="mdi mdi-image"></i></a>
|
||||
{% thumbnail record.image "400x400" as tn %}
|
||||
<a href="{{ record.get_absolute_url }}"
|
||||
class="image-preview"
|
||||
data-preview-url="{{ tn.url }}"
|
||||
data-bs-placement="left"
|
||||
title="{{ record.filename }}"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
aria-label="{{ record.filename }}">
|
||||
<i class="mdi mdi-image"></i>
|
||||
</a>
|
||||
{% endthumbnail %}
|
||||
{% endif %}
|
||||
<a href="{{ record.get_absolute_url }}">{{ record.filename|truncate_middle:16 }}</a>
|
||||
"""
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -150,20 +150,22 @@ function initSidebarAccordions(): void {
|
|||
*/
|
||||
function initImagePreview(): void {
|
||||
for (const element of getElements<HTMLAnchorElement>('a.image-preview')) {
|
||||
// Generate a max-width that's a quarter of the screen's width (note - the actual element
|
||||
// width will be slightly larger due to the popover body's padding).
|
||||
const maxWidth = `${Math.round(window.innerWidth / 4)}px`;
|
||||
// Prefer a thumbnail URL for the popover (so we don't preload full-size images),
|
||||
// but fall back to the link target if no thumbnail was provided.
|
||||
const previewUrl = element.dataset.previewUrl ?? element.href;
|
||||
const image = createElement('img', { src: previewUrl });
|
||||
|
||||
// Create an image element that uses the linked image as its `src`.
|
||||
const image = createElement('img', { src: element.href });
|
||||
image.style.maxWidth = maxWidth;
|
||||
// Ensure lazy loading and async decoding
|
||||
image.loading = 'lazy';
|
||||
image.decoding = 'async';
|
||||
|
||||
// Create a container for the image.
|
||||
const content = createElement('div', null, null, [image]);
|
||||
|
||||
// Initialize the Bootstrap Popper instance.
|
||||
new Popover(element, {
|
||||
// Attach this custom class to the popover so that it styling can be controlled via CSS.
|
||||
// Attach this custom class to the popover so that its styling
|
||||
// can be controlled via CSS.
|
||||
customClass: 'image-preview-popover',
|
||||
trigger: 'hover',
|
||||
html: true,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,29 @@ img.plugin-icon {
|
|||
}
|
||||
}
|
||||
|
||||
// Image preview popover (rendered for <a.image-preview> by initImagePreview())
|
||||
.image-preview-popover {
|
||||
--bs-popover-max-width: clamp(240px, 25vw, 640px);
|
||||
|
||||
.popover-header {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.popover-body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: clamp(160px, 33vh, 640px);
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
body[data-bs-theme=dark] {
|
||||
// Assuming icon is black/white line art, invert it and tone down brightness
|
||||
img.plugin-icon {
|
||||
|
|
|
|||
Loading…
Reference in New Issue