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.
pull/6740/head
Helen C 2021-01-27 11:36:56 +00:00 zatwierdzone przez Thibaud Colas
rodzic bf33842f45
commit 5682aea460
11 zmienionych plików z 90 dodań i 7 usunięć

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 216 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 179 KiB

Wyświetl plik

@ -53,7 +53,8 @@ In addition, Wagtail allows you to choose the format of your image.
.. image:: ../../_static/images/screen18_image_format.png .. image:: ../../_static/images/screen18_image_format.png
#. You can select how the image is displayed by selecting one of the format options. #. 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: The format options available are described below:

Wyświetl plik

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

Wyświetl plik

@ -98,7 +98,22 @@ class ImageInsertionForm(forms.Form):
choices=[(format.name, format.label) for format in get_image_formats()], choices=[(format.name, format.label) for format in get_image_formats()],
widget=forms.RadioSelect 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): class URLGeneratorForm(forms.Form):

Wyświetl plik

@ -134,6 +134,35 @@ IMAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
modal.close(); modal.close();
}, },
'select_format': function(modal) { '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() { $('form', modal.body).on('submit', function() {
$.post(this.action, $(this).serialize(), modal.loadResponseText, 'text'); $.post(this.action, $(this).serialize(), modal.loadResponseText, 'text');

Wyświetl plik

@ -1034,9 +1034,19 @@ class TestImageChooserSelectFormatView(TestCase, WagtailTestUtils):
response = self.get(params={'alt_text': "some previous alt text"}) response = self.get(params={'alt_text': "some previous alt text"})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, 'value=\\"some previous alt text\\"') 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): 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.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json') self.assertEqual(response['Content-Type'], 'application/json')
@ -1051,6 +1061,27 @@ class TestImageChooserSelectFormatView(TestCase, WagtailTestUtils):
self.assertEqual(result['alt'], 'Arthur "two sheds" Jackson') self.assertEqual(result['alt'], 'Arthur "two sheds" Jackson')
self.assertIn('alt="Arthur &quot;two sheds&quot; Jackson"', result['html']) 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): class TestImageChooserUploadView(TestCase, WagtailTestUtils):
def setUp(self): def setUp(self):

Wyświetl plik

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