diff --git a/news/179.bugfix b/news/179.bugfix
new file mode 100644
index 0000000..31d6e75
--- /dev/null
+++ b/news/179.bugfix
@@ -0,0 +1 @@
+set sizes attribute on picture-tags [MrTango]
diff --git a/news/180.feature b/news/180.feature
new file mode 100644
index 0000000..b4138f5
--- /dev/null
+++ b/news/180.feature
@@ -0,0 +1,2 @@
+allow to set lazy to false, to suppress the loading="lazy" attribute
+[MrTango]
diff --git a/plone/namedfile/picture.py b/plone/namedfile/picture.py
index d9e4241..299eea1 100644
--- a/plone/namedfile/picture.py
+++ b/plone/namedfile/picture.py
@@ -47,11 +47,19 @@ def get_scale_width(self, scale):
return scale_info[0]
def create_picture_tag(
- self, sourceset, attributes, uid=None, fieldname=None, resolve_urls=False
+ self,
+ sourceset,
+ attributes,
+ uid=None,
+ fieldname=None,
+ resolve_urls=False,
+ lazy=True,
):
"""Converts the img tag to a picture tag with picture_variant definition"""
width = None
height = None
+ target_width = None
+ sizes = ""
src = attributes.get("src")
if not uid and not src:
raise TypeError("Either uid or attributes['src'] need to be given.")
@@ -68,6 +76,7 @@ def create_picture_tag(
for i, source in enumerate(sourceset):
target_scale = source["scale"]
media = source.get("media")
+ sizes = source.get("sizes")
additional_scales = source.get("additionalScales", None)
if additional_scales is None:
@@ -78,6 +87,8 @@ def create_picture_tag(
source_srcset = []
for scale in source_scales:
scale_width = self.get_scale_width(scale)
+ if scale == target_scale:
+ target_width = scale_width
if not scale_width:
logger.warning("No width found for scale %s.", scale)
continue
@@ -86,13 +97,13 @@ def create_picture_tag(
scale_obj = scale_view.scale(fieldname, scale, pre=True)
scale_url = scale_obj.url
else:
- # obj = self.resolve_uid_url(src)
- # scale_view = obj.unrestrictedTraverse("@@images", None)
- # scale_obj = scale_view.scale(fieldname, scale, pre=True)
- # scale_url = scale_obj.url
scale_url = self.update_src_scale(src=src, scale=scale)
source_srcset.append(f"{scale_url} {scale_width}w")
- source_tag = soup.new_tag("source", srcset=",\n".join(source_srcset))
+ if not sizes:
+ sizes = f"(min-width: 576px) {target_width}px, 98vw"
+ source_tag = soup.new_tag(
+ "source", srcset=",\n".join(source_srcset), sizes=sizes
+ )
if media:
source_tag["media"] = media
picture_tag.append(source_tag)
@@ -104,19 +115,14 @@ def create_picture_tag(
width = scale_obj.width
height = scale_obj.height
else:
- # obj = self.resolve_uid_url(src)
- # scale_view = obj.unrestrictedTraverse("@@images", None)
- # scale_obj = scale_view.scale(fieldname, target_scale, pre=True)
- # scale_url = scale_obj.url
- # width = scale_obj.width
- # height = scale_obj.height
scale_url = self.update_src_scale(src=src, scale=target_scale)
img_tag = soup.new_tag("img", src=scale_url)
for k, attr in attributes.items():
if k in ["src", "srcset"]:
continue
img_tag.attrs[k] = attr
- img_tag["loading"] = "lazy"
+ if lazy:
+ img_tag["loading"] = "lazy"
if width:
img_tag["width"] = width
if height:
diff --git a/plone/namedfile/scaling.py b/plone/namedfile/scaling.py
index f79fc6a..7294a03 100644
--- a/plone/namedfile/scaling.py
+++ b/plone/namedfile/scaling.py
@@ -691,6 +691,7 @@ def picture(
alt=None,
css_class=None,
title=_marker,
+ lazy=True,
**kwargs,
):
img2picturetag = Img2PictureTag()
@@ -737,6 +738,7 @@ def picture(
resolve_urls=True,
uid=scale.context.UID(),
fieldname=fieldname,
+ lazy=lazy,
).prettify()
diff --git a/plone/namedfile/tests/test_scaling.py b/plone/namedfile/tests/test_scaling.py
index aa34934..653678f 100644
--- a/plone/namedfile/tests/test_scaling.py
+++ b/plone/namedfile/tests/test_scaling.py
@@ -88,7 +88,8 @@ def patch_Img2PictureTag_picture_variants():
"sourceset": [
{
"scale": "preview",
- "additionalScales": ["preview", "large", "larger"],
+ "additionalScales": ["large", "larger"],
+ "sizes": "(min-width: 576px) 350px, (min-width: 768px) 600px, 98vw",
}
],
},
@@ -538,15 +539,83 @@ def testGetPictureTagByName(self, mock_uuid_to_object):
mock_uuid_to_object.return_value = self.item
tag = self.scaling.picture("image", picture_variant="medium")
expected = """
-
+http://nohost/item/@@images/image-1200-....png 1200w".../>
"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))
+ # The exact placement of the img tag attributes can differ, especially
+ # with different beautifulsoup versions.
+ # So check here that all attributes are present.
+ self.assertIn('height="200"', tag)
+ self.assertIn('loading="lazy"', tag)
+ self.assertIn('title="foo"', tag)
+ self.assertIn('width="200"', tag)
+ self.assertIn('sizes="(min-width: 576px) 600px, 98vw"', tag)
+
+ @patch.object(
+ plone.namedfile.scaling,
+ "get_picture_variants",
+ new=patch_Img2PictureTag_picture_variants,
+ spec=True,
+ )
+ @patch.object(
+ plone.namedfile.picture,
+ "get_allowed_scales",
+ new=patch_Img2PictureTag_allowed_scales,
+ spec=True,
+ )
+ @patch.object(plone.namedfile.picture, "uuidToObject", spec=True)
+ def testGetPictureTagByNameNotLazy(self, mock_uuid_to_object):
+ ImageScaling._sizes = patch_Img2PictureTag_allowed_scales()
+ mock_uuid_to_object.return_value = self.item
+ tag = self.scaling.picture("image", picture_variant="medium", lazy=False)
+ print(tag)
+ expected = """
+
+
+"""
+ self.assertTrue(_ellipsis_match(expected, tag.strip()))
+ # The exact placement of the img tag attributes can differ, especially
+ # with different beautifulsoup versions.
+ # So check here that all attributes are present.
+ self.assertIn('height="200"', tag)
+ self.assertNotIn('loading="lazy"', tag)
+ self.assertIn('title="foo"', tag)
+ self.assertIn('width="200"', tag)
+ self.assertIn('sizes="(min-width: 576px) 600px, 98vw"', tag)
+ @patch.object(
+ plone.namedfile.scaling,
+ "get_picture_variants",
+ new=patch_Img2PictureTag_picture_variants,
+ spec=True,
+ )
+ @patch.object(
+ plone.namedfile.picture,
+ "get_allowed_scales",
+ new=patch_Img2PictureTag_allowed_scales,
+ spec=True,
+ )
+ @patch.object(plone.namedfile.picture, "uuidToObject", spec=True)
+ def testGetPictureTagCustomSizes(self, mock_uuid_to_object):
+ ImageScaling._sizes = patch_Img2PictureTag_allowed_scales()
+ mock_uuid_to_object.return_value = self.item
+ tag = self.scaling.picture("image", picture_variant="small")
+ expected = """
+
+
+"""
+ self.assertTrue(_ellipsis_match(expected, tag.strip()))
# The exact placement of the img tag attributes can differ, especially
# with different beautifulsoup versions.
# So check here that all attributes are present.
@@ -554,6 +623,9 @@ def testGetPictureTagByName(self, mock_uuid_to_object):
self.assertIn('loading="lazy"', tag)
self.assertIn('title="foo"', tag)
self.assertIn('width="200"', tag)
+ self.assertIn(
+ 'sizes="(min-width: 576px) 350px, (min-width: 768px) 600px, 98vw"', tag
+ )
@patch.object(
plone.namedfile.scaling,
@@ -579,11 +651,11 @@ def testGetPictureTagWithAltAndTitle(self, mock_uuid_to_object):
)
base = self.item.absolute_url()
expected = f"""
-
+{base}/@@images/image-1200-....png 1200w".../>
"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))