diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4bac0537307..42218602f73 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -82,6 +82,7 @@ Changelog * Maintenance: Implement `date_since` in `get_most_popular` inside `search_promotions.models.Query` (TopDevPros) * Maintenance: Refactor generic view subclasses to better reuse the generic templates and breadcrumbs (Sage Abdullah) * Maintenance: Adopt consistent `classname` (not `classnames`) attributes for all `MenuItem` usage, including deprecation warnings (LB (Ben) Johnston) + * Maintenance: Adopt consistent `classname` (not `classnames`) attribute within the `wagtail.images.formats.Format` instance, including deprecation warnings (LB (Ben) Johnston) * Maintenance: Deprecate `context` argument of `construct_snippet_listing_buttons` hook (Sage Abdullah) * Maintenance: Deprecate legacy moderation system (Sage Abdullah) diff --git a/docs/advanced_topics/customisation/page_editing_interface.md b/docs/advanced_topics/customisation/page_editing_interface.md index dd58caf6fc1..2df9461115e 100644 --- a/docs/advanced_topics/customisation/page_editing_interface.md +++ b/docs/advanced_topics/customisation/page_editing_interface.md @@ -115,11 +115,11 @@ The unique key used to identify the format. To unregister this format, call `unr **`label`**\ The label used in the chooser form when inserting the image into the `RichTextField`. -**`classnames`**\ +**`classname`**\ The string to assign to the `class` attribute of the generated `` tag. ```{note} -Any class names you provide must have CSS rules matching them written separately, as part of the front end CSS code. Specifying a `classnames` value of `left` will only ensure that class is output in the generated markup, it won't cause the image to align itself left. +Any class names you provide must have CSS rules matching them written separately, as part of the front end CSS code. Specifying a `classname` value of `left` will only ensure that class is output in the generated markup, it won't cause the image to align itself left. ``` **`filter_spec`** diff --git a/docs/advanced_topics/images/changing_rich_text_representation.md b/docs/advanced_topics/images/changing_rich_text_representation.md index c575730f993..f52a1b51913 100644 --- a/docs/advanced_topics/images/changing_rich_text_representation.md +++ b/docs/advanced_topics/images/changing_rich_text_representation.md @@ -25,7 +25,7 @@ class SubclassedImageFormat(Format): register_image_format( - SubclassedImageFormat('subclassed_format', 'Subclassed Format', classnames, filter_spec) + SubclassedImageFormat('subclassed_format', 'Subclassed Format', 'image-classes object-contain', filter_spec) ) ``` diff --git a/docs/releases/5.2.md b/docs/releases/5.2.md index 45f77f40853..e5d239bfa3f 100644 --- a/docs/releases/5.2.md +++ b/docs/releases/5.2.md @@ -103,6 +103,7 @@ depth: 1 * Implement `date_since` in `get_most_popular` inside `search_promotions.models.Query` (TopDevPros) * Refactor generic view subclasses to better reuse the generic templates and breadcrumbs (Sage Abdullah) * Adopt consistent `classname` (not `classnames`) attributes for all `MenuItem` usage, including deprecation warnings (LB (Ben) Johnston) + * Adopt consistent `classname` (not `classnames`) attribute within the `wagtail.images.formats.Format` instance, including deprecation warnings (LB (Ben) Johnston) * Deprecate `context` argument of `construct_snippet_listing_buttons` hook (Sage Abdullah) * Deprecate legacy moderation system (Sage Abdullah) @@ -398,3 +399,32 @@ def my_view(request): The [`construct_snippet_listing_buttons`](construct_snippet_listing_buttons) hook no longer accepts a `context` argument. If you have implemented this hook, you will need to remove the `context` argument from your implementation. If you need to access values computed by the view, you'll need to override the {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.index_view_class` with a custom `IndexView` subclass. The `get_list_buttons` and `get_list_more_buttons` methods in particular may be overridden to customise the buttons on the listing. Defining a function for this hook that accepts the `context` argument will raise a warning, and the function will receive an empty dictionary (`{}`) as the `context`. Support for defining the `context` argument will be completely removed in a future Wagtail release. + +### Adoption of `classname` convention within the Image `Format` instance + +When using `wagtail.images.formats.Format`, the created instance set the argument for classes to the attribute `classnames` (plural), this has now changed to `classname` (singular). + +For any custom code that accessed or modified this undocumented attribute, updates will need to be made as follows. + +Accessing `self.classnames` will still work until a future release, simply returning `self.classname`, but this will raise a deprecation warning. + +```python +# image_formats.py +from django.utils.html import format_html +from wagtail.images.formats import Format, register_image_format + + +class CustomImageFormat(Format): + + def image_to_html(self, image, alt_text, extra_attributes=None): + # contrived example - pull out the class and render on outside element + classname = self.classname # not self.classnames + self.classname = "" # not self.classnames + inner_html = super().image_to_html(image, alt_text, extra_attributes) + return format_html("{}", classname, inner_html) + + +custom_format = CustomImageFormat('custom_example', 'Custom example', 'example-image object-fit', 'width-750') + +register_image_format(custom_format) +``` diff --git a/wagtail/images/formats.py b/wagtail/images/formats.py index e133fb17e3c..3e2bd66ff87 100644 --- a/wagtail/images/formats.py +++ b/wagtail/images/formats.py @@ -1,26 +1,37 @@ +from warnings import warn + from django.utils.html import escape from django.utils.translation import gettext_lazy as _ from wagtail.utils.apps import get_app_submodules +from wagtail.utils.deprecation import RemovedInWagtail60Warning from .shortcuts import get_rendition_or_not_found class Format: - def __init__(self, name, label, classnames, filter_spec): + def __init__(self, name, label, classname, filter_spec): self.name = name self.label = label - self.classnames = classnames + self.classname = classname self.filter_spec = filter_spec def __str__(self): return ( - f'"{self.name}", "{self.label}", "{self.classnames}", "{self.filter_spec}"' + f'"{self.name}", "{self.label}", "{self.classname}", "{self.filter_spec}"' ) def __repr__(self): return f"Format({self})" + @property + def classnames(self): + warn( + "The class property `classnames` is deprecated - use `classname` instead.", + category=RemovedInWagtail60Warning, + ) + return self.classname + def editor_attributes(self, image, alt_text): """ Return additional attributes to go on the HTML element @@ -44,8 +55,8 @@ def image_to_html(self, image, alt_text, extra_attributes=None): rendition = get_rendition_or_not_found(image, self.filter_spec) extra_attributes["alt"] = escape(alt_text) - if self.classnames: - extra_attributes["class"] = "%s" % escape(self.classnames) + if self.classname: + extra_attributes["class"] = "%s" % escape(self.classname) return rendition.img_tag(extra_attributes) diff --git a/wagtail/images/tests/tests.py b/wagtail/images/tests/tests.py index 79a0e660af1..f5df41f5131 100644 --- a/wagtail/images/tests/tests.py +++ b/wagtail/images/tests/tests.py @@ -22,6 +22,7 @@ from wagtail.images.views.serve import ServeView from wagtail.test.testapp.models import CustomImage, CustomImageFilePath from wagtail.test.utils import WagtailTestUtils, disconnect_signal_receiver +from wagtail.utils.deprecation import RemovedInWagtail60Warning from .utils import ( Image, @@ -237,7 +238,7 @@ def test_rich_text_with_missing_image(self): class TestFormat(WagtailTestUtils, TestCase): def setUp(self): # test format - self.format = Format("test name", "test label", "test classnames", "original") + self.format = Format("test name", "test label", "test is-primary", "original") # test image self.image = Image.objects.create( title="Test image", @@ -260,7 +261,7 @@ def test_image_to_editor_html(self): result = self.format.image_to_editor_html(self.image, "test alt text") self.assertTagInHTML( 'test alt text' % self.image.pk, result, allow_extra_attrs=True, @@ -272,26 +273,28 @@ def test_image_to_editor_html_with_quoting(self): ) expected_html = ( 'Arthur "two sheds" Jackson' % self.image.pk ) self.assertTagInHTML(expected_html, result, allow_extra_attrs=True) def test_image_to_html_no_classnames(self): - self.format.classnames = None + self.format.classname = None result = self.format.image_to_html(self.image, "test alt text") self.assertTagInHTML( 'test alt text', result, allow_extra_attrs=True, ) - self.format.classnames = "test classnames" + self.format.classname = ( + "test is-primary" # reset to original value for other tests + ) def test_image_to_html_with_quoting(self): result = self.format.image_to_html(self.image, 'Arthur "two sheds" Jackson') self.assertTagInHTML( - '', result, allow_extra_attrs=True, @@ -302,6 +305,11 @@ def test_get_image_format(self): result = get_image_format("test name") self.assertEqual(result, self.format) + def test_deprecated_classnames_property_access(self): + with self.assertWarns(RemovedInWagtail60Warning): + classname = self.format.classnames + self.assertEqual(classname, "test is-primary") + class TestSignatureGeneration(TestCase): def test_signature_generation(self): diff --git a/wagtail/images/views/chooser.py b/wagtail/images/views/chooser.py index f247cb2b3b5..ce1792f4404 100644 --- a/wagtail/images/views/chooser.py +++ b/wagtail/images/views/chooser.py @@ -277,7 +277,7 @@ def get_chosen_response_data(self, image): { "format": format.name, "alt": alt_text, - "class": format.classnames, + "class": format.classname, "html": format.image_to_editor_html(image, alt_text), } )