kopia lustrzana https://github.com/wagtail/wagtail
Adopt lazy image loading throughout admin
This improves page responsiveness on first load, especially on pages with many images (eg images list in Wagtail admin) * Lazy load thumbnails on modeladmin lists * Update oembed photos to use lazy loading * Use lazy loading for `MediaBlock`, the avatar in the sidebar and comments * Just decode chooser images asyncpull/9061/head
rodzic
5108b5f82a
commit
efe8f17280
|
@ -7,6 +7,7 @@ Changelog
|
|||
|
||||
* Add basic keyboard control and screen reader support for page listing re-ordering (Paarth Agarwal, Thomas van der Hoeven)
|
||||
* Add `PageQuerySet.private` method as an alias of `not_public` (Mehrdad Moradizadeh)
|
||||
* Most images in the admin will now only load once they are visible on screen (Jake Howard)
|
||||
* Allow setting default attributes on image tags (Jake Howard)
|
||||
* Fix: Prevent `PageQuerySet.not_public` from returning all pages when no page restrictions exist (Mehrdad Moradizadeh)
|
||||
|
||||
|
|
|
@ -151,7 +151,13 @@ export const CommentHeader: FunctionComponent<CommentHeaderProps> = ({
|
|||
)}
|
||||
</div>
|
||||
{author && author.avatarUrl && (
|
||||
<img className="comment-header__avatar" src={author.avatarUrl} alt="" />
|
||||
<img
|
||||
className="comment-header__avatar"
|
||||
src={author.avatarUrl}
|
||||
alt=""
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
<span id={descriptionId}>
|
||||
<p className="comment-header__author">{author ? author.name : ''}</p>
|
||||
|
|
|
@ -117,7 +117,14 @@ class MediaBlock extends Component {
|
|||
<span className="MediaBlock__icon-wrapper" aria-hidden>
|
||||
<Icon icon={entityType.icon} className="MediaBlock__icon" />
|
||||
</span>
|
||||
<img className="MediaBlock__img" src={src} alt={alt} width="256" />
|
||||
<img
|
||||
className="MediaBlock__img"
|
||||
src={src}
|
||||
alt={alt}
|
||||
width="256"
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
/>
|
||||
|
||||
{src ? null : (
|
||||
<span className="MediaBlock__fallback">{fallbackText}</span>
|
||||
|
|
|
@ -20,6 +20,8 @@ exports[`MediaBlock no data, no fallback 1`] = `
|
|||
<img
|
||||
alt=""
|
||||
className="MediaBlock__img"
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
src=""
|
||||
width="256"
|
||||
/>
|
||||
|
@ -49,6 +51,8 @@ exports[`MediaBlock no data, with fallback 1`] = `
|
|||
<img
|
||||
alt=""
|
||||
className="MediaBlock__img"
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
src=""
|
||||
width="256"
|
||||
/>
|
||||
|
@ -100,6 +104,8 @@ exports[`MediaBlock renders 1`] = `
|
|||
<img
|
||||
alt=""
|
||||
className="MediaBlock__img"
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
src="example.png"
|
||||
width="256"
|
||||
/>
|
||||
|
|
|
@ -239,7 +239,12 @@ export const Menu: React.FunctionComponent<MenuProps> = ({
|
|||
type="button"
|
||||
>
|
||||
<div className="avatar avatar-on-dark w-flex-shrink-0 !w-w-[28px] !w-h-[28px]">
|
||||
<img src={user.avatarUrl} alt="" />
|
||||
<img
|
||||
src={user.avatarUrl}
|
||||
alt=""
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div className="sidebar-footer__account-toggle">
|
||||
<div className="sidebar-footer__account-label w-label-3">
|
||||
|
|
|
@ -46,6 +46,8 @@ exports[`Menu should render with the minimum required props 1`] = `
|
|||
>
|
||||
<img
|
||||
alt=""
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
src="https://gravatar/profile"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -15,7 +15,7 @@ Wagtail 4.1 is designated a Long Term Support (LTS) release. Long Term Support r
|
|||
|
||||
* Add basic keyboard control and screen reader support for page listing re-ordering (Paarth Agarwal, Thomas van der Hoeven)
|
||||
* Add `PageQuerySet.private` method as an alias of `not_public` (Mehrdad Moradizadeh)
|
||||
|
||||
* Most images in the admin will now only load once they are visible on screen (Jake Howard)
|
||||
* Allow setting default attributes on image tags [](adding_default_attributes_to_images) (Jake Howard)
|
||||
|
||||
### Bug fixes
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<p>
|
||||
{% blocktrans trimmed with modified_by=workflow_state.requested_by|user_display_name %}Requested by <b>{{ modified_by }}</b>{% endblocktrans %}
|
||||
<span class="avatar small"><img src="{% avatar_url workflow_state.requested_by size=25 %}" alt="" /></span>
|
||||
<span class="avatar small"><img src="{% avatar_url workflow_state.requested_by size=25 %}" alt="" decoding="async" loading="lazy"/></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% load wagtailadmin_tags %}
|
||||
|
||||
<span class="avatar small">
|
||||
<img src="{% avatar_url user size=25 %}" alt="" />
|
||||
<img src="{% avatar_url user size=25 %}" alt="" decoding="async" loading="lazy"/>
|
||||
</span>
|
||||
|
||||
{% if not username %}{{ user }}{% else %}{{ username }}{% endif %}
|
||||
|
|
|
@ -41,6 +41,8 @@ class ThumbnailMixin:
|
|||
"src": self.thumb_default,
|
||||
"width": self.thumb_image_width,
|
||||
"class": self.thumb_classname,
|
||||
"decoding": "async",
|
||||
"loading": "lazy",
|
||||
}
|
||||
if not image:
|
||||
if self.thumb_default:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% if latest_log_entry %}
|
||||
<ul>
|
||||
<li>
|
||||
<span class="avatar small" data-wagtail-tooltip="{{ latest_log_entry.user_display_name }}"><img src="{% avatar_url latest_log_entry.user size=25 %}" alt="" /></span>
|
||||
<span class="avatar small" data-wagtail-tooltip="{{ latest_log_entry.user_display_name }}"><img src="{% avatar_url latest_log_entry.user size=25 %}" alt="" decoding="async" loading="async" /></span>
|
||||
{% trans "Last updated" %}
|
||||
{% include "wagtailadmin/shared/last_updated.html" with last_updated=latest_log_entry.timestamp time_prefix="at" %}
|
||||
</li>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.utils.html import format_html
|
||||
|
||||
from wagtail.embeds.exceptions import EmbedException, EmbedNotFoundException
|
||||
|
||||
from .base import EmbedFinder
|
||||
|
@ -52,7 +54,7 @@ class EmbedlyFinder(EmbedFinder):
|
|||
|
||||
# Convert photos into HTML
|
||||
if oembed["type"] == "photo":
|
||||
html = '<img src="%s" alt="">' % (oembed["url"],)
|
||||
html = format_html('<img src="{}" alt="">', oembed["url"])
|
||||
else:
|
||||
html = oembed.get("html")
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
data-focal-point-height="{{ image.focal_point_height|default_if_none:'' }}"
|
||||
data-focal-input-label="{% trans 'Image focal point' %}"
|
||||
>
|
||||
<img {{ rendition.attrs }} data-original-width="{{ image.width|unlocalize }}" data-original-height="{{ image.height|unlocalize }}" class="show-transparency">
|
||||
<img {{ rendition.attrs }} decoding="async" data-original-width="{{ image.width|unlocalize }}" data-original-height="{{ image.height|unlocalize }}" class="show-transparency">
|
||||
<div class="current-focal-point-indicator{% if not image.has_focal_point %} hidden{% endif %}"></div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
{% block chosen_icon %}
|
||||
{# Empty alt because the chosen item’s title is already displayed next to the image. #}
|
||||
<img class="chooser__image" data-chooser-image alt="" class="show-transparency" height="{{ preview.height }}" src="{{ preview.url }}" width="{{ preview.width }}">
|
||||
<img class="chooser__image" data-chooser-image alt="" class="show-transparency" decoding="async" height="{{ preview.height }}" src="{{ preview.url }}" width="{{ preview.width }}">
|
||||
{% endblock chosen_icon %}
|
||||
|
|
|
@ -211,7 +211,8 @@ class TestMissingImage(TestCase):
|
|||
response = self.client.get("/events/christmas/")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<img src="/media/not-found" width="0" height="0" alt="A missing image" class="feed-image">',
|
||||
'<img src="/media/not-found" width="0" height="0" alt="A missing image" \
|
||||
class="feed-image">',
|
||||
html=True,
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<div class="row last-updated">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="avatar small" data-wagtail-tooltip="{{ latest_log_entry.user_display_name }}"><img src="{% avatar_url latest_log_entry.user size=25 %}" alt="" /></span>
|
||||
<span class="avatar small" data-wagtail-tooltip="{{ latest_log_entry.user_display_name }}"><img src="{% avatar_url latest_log_entry.user size=25 %}" alt="" decoding="async" loading="lazy"/></span>
|
||||
{% trans "Last updated" %}
|
||||
{% include "wagtailadmin/shared/last_updated.html" with last_updated=latest_log_entry.timestamp time_prefix="at" %}
|
||||
</li>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
{% include "wagtailadmin/bulk_actions/listing_checkbox_cell.html" with obj_type="user" obj=user aria_labelledby_prefix="user_" aria_labelledby=user.pk|unlocalize aria_labelledby_suffix="_title" %}
|
||||
<td id="user_{{ user.pk|unlocalize }}_title" class="title" valign="top">
|
||||
<div class="title-wrapper">
|
||||
<span class="avatar small"><img src="{% avatar_url user size=25 %}" alt="" /></span>
|
||||
<span class="avatar small"><img src="{% avatar_url user size=25 %}" alt="" decoding="async" loading="lazy"/></span>
|
||||
<a href="{% url 'wagtailusers_users:edit' user.pk %}">{{ user|user_display_name }}</a>
|
||||
</div>
|
||||
<ul class="actions">
|
||||
|
|
Ładowanie…
Reference in New Issue