浏览代码

Add the option to set images as decorative

If an image is decorative, the alt text will be set to be empty. If an image is not decorative, then alt text must be supplied for screen readers.
Helen C 4 年之前
父节点
当前提交
5682aea460

+ 2 - 1
client/scss/components/_forms.scss

@@ -138,7 +138,8 @@ li.focused > .help {
     opacity: 1;
 }
 
-.required .field > label:after {
+.required .field > label:after,
+label.required:after {
     content: '*';
     color: $color-red;
     font-weight: bold;

+ 4 - 1
client/src/components/Draftail/blocks/ImageBlock.js

@@ -12,7 +12,10 @@ const ImageBlock = props => {
   const { blockProps } = props;
   const { entity, onEditEntity, onRemoveEntity } = blockProps;
   const { src, alt } = entity.getData();
-  const altLabel = `${STRINGS.ALT_TEXT}: “${alt || ''}”`;
+  let altLabel = STRINGS.DECORATIVE_IMAGE;
+  if (alt) {
+    altLabel = `${STRINGS.ALT_TEXT}: “${alt}”`;
+  }
 
   return (
     <MediaBlock {...props} src={src} alt="">

+ 2 - 2
client/src/components/Draftail/blocks/__snapshots__/ImageBlock.test.js.snap

@@ -54,7 +54,7 @@ exports[`ImageBlock no data 1`] = `
   <p
     className="ImageBlock__alt"
   >
-    Alt text: “”
+    Decorative image
   </p>
   <button
     className="button Tooltip__button"
@@ -89,7 +89,7 @@ exports[`ImageBlock renders 1`] = `
   <p
     className="ImageBlock__alt"
   >
-    Alt text: “”
+    Decorative image
   </p>
   <button
     className="button Tooltip__button"

+ 1 - 0
client/tests/stubs.js

@@ -30,6 +30,7 @@ global.wagtailConfig = {
     SEE_ALL: 'See all',
     CLOSE_EXPLORER: 'Close explorer',
     ALT_TEXT: 'Alt text',
+    DECORATIVE_IMAGE: 'Decorative image',
     WRITE_HERE: 'Write here…',
     HORIZONTAL_LINE: 'Horizontal line',
     LINE_BREAK: 'Line break',

二进制
docs/_static/images/screen18_image_format.png


+ 2 - 1
docs/editor_manual/new_pages/inserting_images.rst

@@ -53,7 +53,8 @@ In addition, Wagtail allows you to choose the format of your image.
 .. image:: ../../_static/images/screen18_image_format.png
 
 #. You can select how the image is displayed by selecting one of the format options.
-#. You must provide specific `alt text <https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#Alternative_text>`_ for your image.
+#. You can choose if the image is `decorative <https://www.w3.org/WAI/tutorials/images/decorative/>`_, in which case you will not need to enter alt text for your image.
+#. If you do not choose for the image to be decorative, you must provide specific `alt text <https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#Alternative_text>`_ for your image.
 
 The format options available are described below:
 

+ 1 - 0
wagtail/admin/localization.py

@@ -62,6 +62,7 @@ def get_js_translation_strings():
         'SEE_ALL': _('See all'),
         'CLOSE_EXPLORER': _('Close explorer'),
         'ALT_TEXT': _('Alt text'),
+        'DECORATIVE_IMAGE': _('Decorative image'),
         'WRITE_HERE': _('Write here…'),
         'HORIZONTAL_LINE': _('Horizontal line'),
         'LINE_BREAK': _('Line break'),

+ 16 - 1
wagtail/images/forms.py

@@ -98,7 +98,22 @@ class ImageInsertionForm(forms.Form):
         choices=[(format.name, format.label) for format in get_image_formats()],
         widget=forms.RadioSelect
     )
-    alt_text = forms.CharField()
+    image_is_decorative = forms.BooleanField(required=False)
+    alt_text = forms.CharField(required=False)
+
+    def clean_alt_text(self):
+        alt_text = self.cleaned_data['alt_text']
+        image_is_decorative = self.cleaned_data['image_is_decorative']
+
+        # Empty the alt text value if the image is set to be decorative
+        if image_is_decorative:
+            return ''
+        else:
+            # Alt text is required if image is not decorative.
+            if not alt_text:
+                msg = _("Please add some alt text for your image or mark it as decorative")
+                self.add_error('alt_text', msg)
+        return alt_text
 
 
 class URLGeneratorForm(forms.Form):

+ 29 - 0
wagtail/images/static_src/wagtailimages/js/image-chooser-modal.js

@@ -134,6 +134,35 @@ IMAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
         modal.close();
     },
     'select_format': function(modal) {
+
+        var decorativeImage = document.querySelector('#id_image-chooser-insertion-image_is_decorative');
+        var altText = document.querySelector('#id_image-chooser-insertion-alt_text');
+        var altTextLabel = document.querySelector('[for="id_image-chooser-insertion-alt_text"]');
+
+        if (decorativeImage.checked) {
+            disableAltText();
+        } else {
+            enableAltText();
+        }
+
+        decorativeImage.addEventListener('change', function(event){
+            if (event.target.checked) {
+                disableAltText();
+            } else {
+                enableAltText();
+            }
+        });
+
+        function disableAltText() {
+            altText.setAttribute('disabled', 'disabled');
+            altTextLabel.classList.remove('required');
+        }
+
+        function enableAltText() {
+            altText.removeAttribute('disabled');
+            altTextLabel.classList.add('required');
+        }
+
         $('form', modal.body).on('submit', function() {
             $.post(this.action, $(this).serialize(), modal.loadResponseText, 'text');
 

+ 32 - 1
wagtail/images/tests/test_admin_views.py

@@ -1034,9 +1034,19 @@ class TestImageChooserSelectFormatView(TestCase, WagtailTestUtils):
         response = self.get(params={'alt_text': "some previous alt text"})
         self.assertEqual(response.status_code, 200)
         self.assertContains(response, 'value=\\"some previous alt text\\"')
+        self.assertNotContains(response, 'id=\\"id_image-chooser-insertion-image_is_decorative\\" checked')
+
+    def test_with_edit_params_no_alt_text_marks_as_decorative(self):
+        response = self.get(params={'alt_text': ""})
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'id=\\"id_image-chooser-insertion-image_is_decorative\\" checked')
 
     def test_post_response(self):
-        response = self.post({'image-chooser-insertion-format': 'left', 'image-chooser-insertion-alt_text': 'Arthur "two sheds" Jackson'})
+        response = self.post({
+            'image-chooser-insertion-format': 'left',
+            'image-chooser-insertion-image_is_decorative': False,
+            'image-chooser-insertion-alt_text': 'Arthur "two sheds" Jackson',
+        })
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response['Content-Type'], 'application/json')
@@ -1051,6 +1061,27 @@ class TestImageChooserSelectFormatView(TestCase, WagtailTestUtils):
         self.assertEqual(result['alt'], 'Arthur "two sheds" Jackson')
         self.assertIn('alt="Arthur &quot;two sheds&quot; Jackson"', result['html'])
 
+    def test_post_response_image_is_decorative_discards_alt_text(self):
+        response = self.post({
+            'image-chooser-insertion-format': 'left',
+            'image-chooser-insertion-alt_text': 'Arthur "two sheds" Jackson',
+            'image-chooser-insertion-image_is_decorative': True,
+        })
+        response_json = json.loads(response.content.decode())
+        result = response_json['result']
+
+        self.assertEqual(result['alt'], '')
+        self.assertIn('alt=""', result['html'])
+
+    def test_post_response_image_is_not_decorative_missing_alt_text(self):
+        response = self.post({
+            'image-chooser-insertion-format': 'left',
+            'image-chooser-insertion-alt_text': '',
+            'image-chooser-insertion-image_is_decorative': False,
+        })
+        response_json = json.loads(response.content.decode())
+        self.assertIn('Please add some alt text for your image or mark it as decorative', response_json['html'])
+
 
 class TestImageChooserUploadView(TestCase, WagtailTestUtils):
     def setUp(self):

+ 1 - 0
wagtail/images/views/chooser.py

@@ -241,6 +241,7 @@ def chooser_select_format(request, image_id):
     else:
         initial = {'alt_text': image.default_alt_text}
         initial.update(request.GET.dict())
+        initial['image_is_decorative'] = initial['alt_text'] == ''
         form = ImageInsertionForm(initial=initial, prefix='image-chooser-insertion')
 
     return render_modal_workflow(