diff --git a/blog/templatetags/blog_extras.py b/blog/templatetags/blog_extras.py
new file mode 100644
index 0000000000..8ad46f675a
--- /dev/null
+++ b/blog/templatetags/blog_extras.py
@@ -0,0 +1,48 @@
+from html.parser import HTMLParser
+
+from django import template
+from django.utils.html import format_html
+
+register = template.Library()
+
+
+class LazyLoadingHTMLParser(HTMLParser):
+ def __init__(self):
+ super().__init__()
+ self.result = []
+
+ def handle_starttag(self, tag, attrs):
+ if tag.lower() == "img":
+ attrs_dict = dict(attrs)
+ attrs_dict.setdefault("loading", "lazy")
+ attrs_dict.setdefault("decoding", "async")
+ attrs_str = " ".join(f'{k}="{v}"' for k, v in attrs_dict.items())
+ self.result.append(f"<{tag} {attrs_str}>")
+ else:
+ attrs_str = " ".join(f'{k}="{v}"' for k, v in attrs)
+ self.result.append(f"<{tag}{' ' + attrs_str if attrs_str else ''}>")
+
+ def handle_endtag(self, tag):
+ self.result.append(f"{tag}>")
+
+ def handle_data(self, data):
+ self.result.append(data)
+
+ def handle_startendtag(self, tag, attrs):
+ # For self-closing tags like
+ if tag.lower() == "img":
+ attrs_dict = dict(attrs)
+ attrs_dict.setdefault("loading", "lazy")
+ attrs_dict.setdefault("decoding", "async")
+ attrs_str = " ".join(f'{k}="{v}"' for k, v in attrs_dict.items())
+ self.result.append(f"<{tag} {attrs_str} />")
+ else:
+ attrs_str = " ".join(f'{k}="{v}"' for k, v in attrs)
+ self.result.append(f"<{tag}{' ' + attrs_str if attrs_str else ''} />")
+
+
+@register.filter
+def add_lazy_loading(html):
+ parser = LazyLoadingHTMLParser()
+ parser.feed(html)
+ return format_html("".join(parser.result))
diff --git a/blog/tests/test_lazy_loading.py b/blog/tests/test_lazy_loading.py
new file mode 100644
index 0000000000..e148805a3c
--- /dev/null
+++ b/blog/tests/test_lazy_loading.py
@@ -0,0 +1,28 @@
+from django.test import SimpleTestCase
+
+from blog.templatetags.blog_extras import add_lazy_loading
+
+
+class AddLazyLoadingFilterTests(SimpleTestCase):
+ def test_adds_attributes_to_img_without_them(self):
+ html = '
Example
No images here
" + result = add_lazy_loading(html) + self.assertEqual(result, html) diff --git a/djangoproject/settings/test.py b/djangoproject/settings/test.py new file mode 100644 index 0000000000..7aeed7efd3 --- /dev/null +++ b/djangoproject/settings/test.py @@ -0,0 +1,17 @@ +from .common import INSTALLED_APPS + +DEBUG = False +SECRET_KEY = "test-secret-key" + +INSTALLED_APPS = [app for app in INSTALLED_APPS if app != "foundation"] + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": ":memory:", + } +} + +PASSWORD_HASHERS = [ + "django.contrib.auth.hashers.MD5PasswordHasher", +] diff --git a/djangoproject/templates/blog/entry_detail.html b/djangoproject/templates/blog/entry_detail.html index c42f519693..d1ef6288fb 100644 --- a/djangoproject/templates/blog/entry_detail.html +++ b/djangoproject/templates/blog/entry_detail.html @@ -1,5 +1,6 @@ {% extends "base_weblog.html" %} {% load i18n %} +{% load blog_extras %} {# Load your custom filter #} {% block title %}{{ object.headline|escape }} | Weblog{% endblock %} @@ -17,5 +18,8 @@