a11y: add aria attributes for help and errors (#75681)
gitea/gadjo/pipeline/head This commit looks good Details

This commit is contained in:
Frédéric Péters 2023-05-07 16:42:07 +02:00
parent 246b6b3c5c
commit 75f38ce67a
5 changed files with 51 additions and 2 deletions

View File

@ -21,7 +21,7 @@
{% block widget-attrs %}{% endblock %}>
{% block widget-hint %}
{% if field.help_text %}
<div class="hint">{{ field.help_text|safe }}</div>
<div class="hint" id="help_text_{{field.id_for_label}}">{{ field.help_text|safe }}</div>
{% endif %}
{% endblock %}
{% block widget-control %}
@ -29,7 +29,7 @@
{% endblock %}
{% block widget-error %}
{% if field.errors %}
<div class="error"><p>
<div class="error" id="error_{{field.id_for_label}}"><p>
{% for error in field.errors %}
{{ error }}{% if not forloop.last %}<br>{% endif %}
{% endfor %}

View File

@ -108,6 +108,14 @@ def with_template(form):
templates = ['gadjo/widget.html']
if hasattr(widget, 'input_type'):
templates.insert(0, 'gadjo/%s-widget.html' % widget.input_type)
aria_described_by = []
if field.field.help_text:
aria_described_by.append(f'help_text_{field.id_for_label}')
if field.errors:
aria_described_by.append(f'error_{field.id_for_label}')
field.field.widget.attrs['aria-invalid'] = 'true'
if aria_described_by:
field.field.widget.attrs['aria-describedby'] = ' '.join(aria_described_by)
fields_with_templates.append(
(
field,

View File

@ -28,6 +28,7 @@ INSTALLED_APPS = [
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sites",
"gadjo",
]
STATIC_URL = "/static/"
SITE_ID = 1

View File

@ -1,8 +1,10 @@
import html
import urllib
from django import forms
from django.template import Context, Template
from django.test.client import RequestFactory
from pyquery import PyQuery
def test_start_timestamp():
@ -32,3 +34,40 @@ def test_querystring():
assert urllib.parse.parse_qs(urllib.parse.urlparse(html.unescape(t.render(ctx))).query) == {
'name': ['Ayers']
}
def test_with_template():
class ExampleForm(forms.Form):
text = forms.CharField(label='Text', max_length=50)
request = RequestFactory().get('/')
t = Template('{{ form|with_template }}')
ctx = Context({'request': request, 'form': ExampleForm()})
rendered = t.render(ctx)
assert PyQuery(rendered).find('input[type=text]')
assert not PyQuery(rendered).find('input[type=text]').attr['aria-invalid']
ctx = Context({'request': request, 'form': ExampleForm(data=request.GET)})
rendered = t.render(ctx)
assert (
PyQuery(rendered).find('input[type=text][aria-describedby]').attr['aria-describedby']
== 'error_id_text'
)
assert PyQuery(rendered).find('input[type=text]').attr['aria-invalid']
class ExampleForm(forms.Form):
text = forms.CharField(label='Text', max_length=50, help_text='Help text')
ctx = Context({'request': request, 'form': ExampleForm()})
rendered = t.render(ctx)
assert (
PyQuery(rendered).find('input[type=text][aria-describedby]').attr['aria-describedby']
== 'help_text_id_text'
)
ctx = Context({'request': request, 'form': ExampleForm(data=request.GET)})
rendered = t.render(ctx)
assert (
PyQuery(rendered).find('input[type=text][aria-describedby]').attr['aria-describedby']
== 'help_text_id_text error_id_text'
)

View File

@ -16,6 +16,7 @@ deps =
WebTest
psycopg2-binary
psycopg2
pyquery
codestyle: pre-commit
coverage: pytest-cov
pylint: pylint