Skip to content
Merged
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
5 changes: 2 additions & 3 deletions djangocms_frontend/contrib/image/cms_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,16 @@ class ImagePlugin(
"classes": ("collapse",),
"fields": (
"use_responsive_image",
("width", "height"),
"alignment",
),
},
),
(
_("Cropping"),
_("Sizing"),
{
"classes": ("collapse",),
"fields": (
("use_automatic_scaling", "use_no_cropping"),
("width", "height"),
("use_crop", "use_upscale"),
"thumbnail_options",
),
Expand Down
35 changes: 10 additions & 25 deletions djangocms_frontend/contrib/image/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ class Meta:
"height",
"alignment",
"link_attributes",
"use_automatic_scaling",
"use_crop",
"use_no_cropping",
"use_upscale",
"use_responsive_image",
"thumbnail_options",
Expand Down Expand Up @@ -120,13 +118,19 @@ class Meta:
label=_("Width"),
required=False,
min_value=1,
help_text=_('The image width as number in pixels. Example: "720" and not "720px".'),
help_text=_(
'The image width as number in pixels (eg, "720" and not "720px"). '
),
)
height = forms.IntegerField(
label=_("Height"),
required=False,
min_value=1,
help_text=_('The image height as number in pixels. Example: "720" and not "720px".'),
help_text=_(
'The image height as number in pixels (eg, "720" and not "720px"). '
"Note: if width is set, height will be calculated automatically to preserve aspect ratio. "
"In case of cropping, then both width and height are applied as given."
),
)
alignment = forms.ChoiceField(
label=_("Alignment"),
Expand All @@ -140,31 +144,17 @@ class Meta:
help_text=_("Attributes apply to the <b>link</b>."),
)

# cropping models
# active per default
use_automatic_scaling = forms.BooleanField(
label=_("Automatic scaling"),
required=False,
help_text=_("Uses the placeholder dimensions to automatically calculate the size."),
)
# ignores all other cropping options
# throws validation error if other cropping options are selected
use_no_cropping = forms.BooleanField(
label=_("Use original image"),
required=False,
help_text=_("Outputs the raw image without cropping."),
)
# upscale and crop work together
# throws validation error if other cropping options are selected
use_crop = forms.BooleanField(
label=_("Crop image"),
required=False,
help_text=_("Crops the image according to the thumbnail settings provided in the template."),
help_text=_("Crops the image rather than resizing"),
)
use_upscale = forms.BooleanField(
label=_("Upscale image"),
required=False,
help_text=_("Upscales the image to the size of the thumbnail settings in the template."),
help_text=_("Allows the image to be upscaled beyond its original size."),
)
use_responsive_image = forms.ChoiceField(
label=_("Use responsive image"),
Expand Down Expand Up @@ -215,11 +205,6 @@ def clean(self):
# certain cropping options do not work together, the following
# list defines the disallowed options used in the ``clean`` method
invalid_option_pairs = [
("use_automatic_scaling", "use_no_cropping"),
("use_automatic_scaling", "thumbnail_options"),
("use_no_cropping", "use_crop"),
("use_no_cropping", "use_upscale"),
("use_no_cropping", "thumbnail_options"),
("thumbnail_options", "use_crop"),
("thumbnail_options", "use_upscale"),
]
Expand Down
7 changes: 4 additions & 3 deletions djangocms_frontend/contrib/image/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def get_size(self, width=None, height=None):
height = thumbnail_options.height
crop = thumbnail_options.crop
upscale = thumbnail_options.upscale
elif not getattr(self, "use_automatic_scaling", None):
else:
width = getattr(self, "width", None)
height = getattr(self, "height", None)

Expand Down Expand Up @@ -120,8 +120,9 @@ def img_src(self):
# in this case we want to return an empty string to avoid #69
elif not self.picture:
return ""
# return the original, unmodified image
elif self.use_no_cropping:
# skip image processing when there's no width or height defined,
# or when legacy use_no_cropping flag is present
elif getattr(self, 'use_no_cropping', None) or not (self.width or self.height):
return self.rel_image.url if self.rel_image else ""

picture_options = self.get_size(
Expand Down
66 changes: 64 additions & 2 deletions tests/image/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,67 @@ def test_plugin(self):
f'class="img-thumbnail rounded" not found in {response.content.decode("utf-8")}',
)

def test_img_processing(self):
# Image gets resized if user width and height are provided
plugin = add_plugin(
placeholder=self.placeholder,
plugin_type=ImagePlugin.__name__,
language=self.language,
config={
"picture": {"pk": self.image.id, "model": "filer.Image"},
"width": 50,
"height": 100,
},
)
plugin.initialize_from_form(ImageForm)
plugin.save()
self.publish(self.page, self.language)

with self.login_user_context(self.superuser):
response = self.client.get(self.request_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, '/test_file.jpg__50x100_q85_subsampling-2.jpg"')

# Original image is used if NEITHER width nor height are provided
plugin = add_plugin(
placeholder=self.placeholder,
plugin_type=ImagePlugin.__name__,
language=self.language,
config={
"picture": {"pk": self.image.id, "model": "filer.Image"},
},
)
plugin.initialize_from_form(ImageForm)
plugin.save()
self.publish(self.page, self.language)

with self.login_user_context(self.superuser):
response = self.client.get(self.request_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, '/test_file.jpg"')

# Original image also used if legacy use_no_cropping flag is present,
# even when there is widht and height
plugin = add_plugin(
placeholder=self.placeholder,
plugin_type=ImagePlugin.__name__,
language=self.language,
config={
"picture": {"pk": self.image.id, "model": "filer.Image"},
"width": 50,
"height": 100,
"use_no_cropping": True,
},
)
plugin.initialize_from_form(ImageForm)
plugin.save()
self.publish(self.page, self.language)

with self.login_user_context(self.superuser):
response = self.client.get(self.request_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, '/test_file.jpg"')

def test_image_form(self):
request = HttpRequest()
request.POST = {
Expand All @@ -77,10 +138,11 @@ def test_image_form(self):
self.assertTrue(form.is_valid(), f"{form.__class__.__name__}:form errors: {form.errors}")
self.assertEqual(form.cleaned_data["config"]["use_responsive_image"], "yes")

# Test invalid option pair
request.POST.update(
{
"use_automatic_scaling": True,
"use_no_cropping": True,
"thumbnail_options": True,
"use_crop": True,
}
)
form = ImageForm(request.POST)
Expand Down