diff --git a/djangocms_frontend/contrib/image/cms_plugins.py b/djangocms_frontend/contrib/image/cms_plugins.py index dec1d97a..55d68ebe 100644 --- a/djangocms_frontend/contrib/image/cms_plugins.py +++ b/djangocms_frontend/contrib/image/cms_plugins.py @@ -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", ), diff --git a/djangocms_frontend/contrib/image/forms.py b/djangocms_frontend/contrib/image/forms.py index 55e6df29..f8255a80 100644 --- a/djangocms_frontend/contrib/image/forms.py +++ b/djangocms_frontend/contrib/image/forms.py @@ -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", @@ -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"), @@ -140,31 +144,17 @@ class Meta: help_text=_("Attributes apply to the link."), ) - # 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"), @@ -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"), ] diff --git a/djangocms_frontend/contrib/image/models.py b/djangocms_frontend/contrib/image/models.py index c09966ea..1213d403 100644 --- a/djangocms_frontend/contrib/image/models.py +++ b/djangocms_frontend/contrib/image/models.py @@ -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) @@ -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( diff --git a/tests/image/test_plugins.py b/tests/image/test_plugins.py index 01697e5d..537a3503 100644 --- a/tests/image/test_plugins.py +++ b/tests/image/test_plugins.py @@ -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 = { @@ -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)