Skip to content

Commit

Permalink
Implement preserveSvg flag for srcSet() (#370)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Morega <[email protected]>
  • Loading branch information
mgax and mgax authored Sep 27, 2023
1 parent cff065c commit 9693007
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/general-usage/graphql-types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ the root query type like so:
srcSet(
sizes: [Int]
format: String
preserveSvg: Boolean
): String
isSvg: Boolean!

Expand Down
29 changes: 25 additions & 4 deletions grapple/types/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,24 @@ def get_rendition_field_kwargs() -> dict[str, graphene.Scalar]:
return kwargs


def get_src_set_field_kwargs() -> dict[str, graphene.Scalar]:
"""
Returns a list of kwargs for the srcSet field.
Extracted for convenience, to accommodate for the conditional logic needed for various Wagtail versions.
"""
kwargs = {
"sizes": graphene.List(graphene.Int),
"format": graphene.String(),
}
if WAGTAIL_VERSION > (5, 0):
kwargs["preserve_svg"] = graphene.Boolean(
description="Prevents raster image operations (e.g. `format-webp`, `bgcolor`, etc.) being applied to SVGs. "
"More info: https://docs.wagtail.org/en/stable/topics/images.html#svg-images"
)

return kwargs


def rendition_allowed(filter_specs: str) -> bool:
"""Checks a given rendition filter is allowed"""
allowed_filters = grapple_settings.ALLOWED_IMAGE_FILTERS
Expand Down Expand Up @@ -110,9 +128,7 @@ class ImageObjectType(DjangoObjectType):
collection = graphene.Field(lambda: CollectionObjectType, required=True)
tags = graphene.List(graphene.NonNull(lambda: TagObjectType), required=True)
rendition = graphene.Field(get_rendition_type, **get_rendition_field_kwargs())
src_set = graphene.String(
sizes=graphene.List(graphene.Int), format=graphene.String()
)
src_set = graphene.String(**get_src_set_field_kwargs())
if WAGTAIL_VERSION > (5, 0):
is_svg = graphene.Boolean(required=True)

Expand Down Expand Up @@ -181,6 +197,7 @@ def resolve_src_set(
info: GraphQLResolveInfo,
sizes: list[int],
format: str | None = None,
preserve_svg: bool = False,
**kwargs,
) -> str:
"""
Expand All @@ -191,7 +208,11 @@ def resolve_src_set(
if instance.file.name is not None:
rendition_list = [
ImageObjectType.resolve_rendition(
instance, info, width=width, **format_kwarg
instance,
info,
width=width,
preserve_svg=preserve_svg,
**format_kwarg,
)
for width in sizes
if rendition_allowed(f"width-{width}{filter_suffix}")
Expand Down
44 changes: 44 additions & 0 deletions tests/test_image_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,11 @@ def test_schema_for_svg_related_fields_and_arguments(self):
field["name"]: field for field in results["data"]["__type"]["fields"]
}
rendition_args = {arg["name"]: arg for arg in mapping["rendition"]["args"]}
src_set_args = {arg["name"]: arg for arg in mapping["srcSet"]["args"]}

self.assertNotIn("isSvg", mapping)
self.assertNotIn("preserveSvg", rendition_args)
self.assertNotIn("preserveSvg", src_set_args)


if WAGTAIL_VERSION >= (5, 0):
Expand Down Expand Up @@ -262,6 +264,7 @@ def test_schema_for_svg_related_fields_and_arguments(self):
field["name"]: field for field in results["data"]["__type"]["fields"]
}
rendition_args = {arg["name"]: arg for arg in mapping["rendition"]["args"]}
src_set_args = {arg["name"]: arg for arg in mapping["srcSet"]["args"]}

self.assertIn("isSvg", mapping)
self.assertEqual(mapping["isSvg"]["type"]["kind"], "NON_NULL")
Expand All @@ -271,6 +274,12 @@ def test_schema_for_svg_related_fields_and_arguments(self):
"Prevents raster image operations (e.g. `format-webp`, `bgcolor`, etc.) being applied to SVGs. "
"More info: https://docs.wagtail.org/en/stable/topics/images.html#svg-images",
)
self.assertEqual(src_set_args["preserveSvg"]["type"]["name"], "Boolean")
self.assertEqual(
src_set_args["preserveSvg"]["description"],
"Prevents raster image operations (e.g. `format-webp`, `bgcolor`, etc.) being applied to SVGs. "
"More info: https://docs.wagtail.org/en/stable/topics/images.html#svg-images",
)

def test_svg_rendition(self):
query = """
Expand Down Expand Up @@ -310,6 +319,24 @@ def test_svg_rendition_with_raster_format_with_preserve_svg(self):
)
)

def test_svg_src_set_with_raster_format_with_preserve_svg(self):
query = """
query ($id: ID!) {
image(id: $id) {
srcSet(sizes: [100], format: "webp", preserveSvg: true)
}
}
"""

results = self.client.execute(
query, variables={"id": self.example_svg_image.id}
)
self.assertTrue(
results["data"]["image"]["srcSet"]
.split()[0]
.endswith("test.width-100.svg")
)

def test_svg_rendition_with_raster_format_without_preserve_svg(self):
query = """
query ($id: ID!) {
Expand All @@ -329,6 +356,23 @@ def test_svg_rendition_with_raster_format_without_preserve_svg(self):
"'SvgImage' object has no attribute 'save_as_webp'",
)

def test_svg_src_set_with_raster_format_without_preserve_svg(self):
query = """
query ($id: ID!) {
image(id: $id) {
srcSet(sizes: [100], format: "webp")
}
}
"""

results = self.client.execute(
query, variables={"id": self.example_svg_image.id}
)
self.assertEqual(
results["errors"][0]["message"],
"'SvgImage' object has no attribute 'save_as_webp'",
)

def test_svg_rendition_with_filters_passed_through_to_svg_safe_spec(self):
# bgcolor is not one of the allowed filters, so we should end with an empty filter spec
query = """
Expand Down

0 comments on commit 9693007

Please sign in to comment.