Skip to content

set sizes for picture-tags, fixes #179 #180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/179.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
set sizes attribute on picture-tags [MrTango]
2 changes: 2 additions & 0 deletions news/180.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
allow to set lazy to false, to suppress the loading="lazy" attribute
[MrTango]
32 changes: 19 additions & 13 deletions plone/namedfile/picture.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 576?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source_tag = soup.new_tag(
"source", srcset=",\n".join(source_srcset), sizes=sizes
)
if media:
source_tag["media"] = media
picture_tag.append(source_tag)
Expand All @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions plone/namedfile/scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,7 @@ def picture(
alt=None,
css_class=None,
title=_marker,
lazy=True,
**kwargs,
):
img2picturetag = Img2PictureTag()
Expand Down Expand Up @@ -737,6 +738,7 @@ def picture(
resolve_urls=True,
uid=scale.context.UID(),
fieldname=fieldname,
lazy=lazy,
).prettify()


Expand Down
82 changes: 77 additions & 5 deletions plone/namedfile/tests/test_scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
}
],
},
Expand Down Expand Up @@ -538,22 +539,93 @@ def testGetPictureTagByName(self, mock_uuid_to_object):
mock_uuid_to_object.return_value = self.item
tag = self.scaling.picture("image", picture_variant="medium")
expected = """<picture>
<source srcset="http://nohost/item/@@images/image-600-....png 600w,
<source...srcset="http://nohost/item/@@images/image-600-....png 600w,
http://nohost/item/@@images/image-400-....png 400w,
http://nohost/item/@@images/image-800-....png 800w,
http://nohost/item/@@images/image-1000-....png 1000w,
http://nohost/item/@@images/image-1200-....png 1200w"/>
http://nohost/item/@@images/image-1200-....png 1200w".../>
<img...src="http://nohost/item/@@images/image-600-....png".../>
</picture>"""
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 = """<picture>
<source...srcset="http://nohost/item/@@images/image-600-....png 600w,
http://nohost/item/@@images/image-400-....png 400w,
http://nohost/item/@@images/image-800-....png 800w,
http://nohost/item/@@images/image-1000-....png 1000w,
http://nohost/item/@@images/image-1200-....png 1200w".../>
<img...src="http://nohost/item/@@images/image-600-....png".../>
</picture>"""
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 = """<picture>
<source...srcset="http://nohost/item/@@images/image-400-....png 400w,
http://nohost/item/@@images/image-800-....png 800w,
http://nohost/item/@@images/image-1000-....png 1000w".../>
<img...src="http://nohost/item/@@images/image-400-....png".../>
</picture>"""
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) 350px, (min-width: 768px) 600px, 98vw"', tag
)

@patch.object(
plone.namedfile.scaling,
Expand All @@ -579,11 +651,11 @@ def testGetPictureTagWithAltAndTitle(self, mock_uuid_to_object):
)
base = self.item.absolute_url()
expected = f"""<picture>
<source srcset="{base}/@@images/image-600-....png 600w,
<source...srcset="{base}/@@images/image-600-....png 600w,
{base}/@@images/image-400-....png 400w,
{base}/@@images/image-800-....png 800w,
{base}/@@images/image-1000-....png 1000w,
{base}/@@images/image-1200-....png 1200w"/>
{base}/@@images/image-1200-....png 1200w".../>
<img...src="{base}/@@images/image-600-....png".../>
</picture>"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))
Expand Down