Fixed #34622 -- Improved accessibility of related widget wrapper in admin.
This improves accessibility for screen reader users by adding "aria-disabled" and removing "alt". Thanks Thibaud Colas for the report.
This commit is contained in:
parent
0faad01938
commit
10d9d0ccb2
@ -79,9 +79,11 @@
|
|||||||
siblings.each(function() {
|
siblings.each(function() {
|
||||||
const elm = $(this);
|
const elm = $(this);
|
||||||
elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
|
elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
|
||||||
|
elm.removeAttr('aria-disabled');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
siblings.removeAttr('href');
|
siblings.removeAttr('href');
|
||||||
|
siblings.attr('aria-disabled', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
data-href-template="{{ change_related_template_url }}?{{ url_params }}"
|
data-href-template="{{ change_related_template_url }}?{{ url_params }}"
|
||||||
data-popup="yes"
|
data-popup="yes"
|
||||||
title="{% blocktranslate %}Change selected {{ model }}{% endblocktranslate %}">
|
title="{% blocktranslate %}Change selected {{ model }}{% endblocktranslate %}">
|
||||||
<img src="{% static 'admin/img/icon-changelink.svg' %}" alt="{% translate 'Change' %}">
|
<img src="{% static 'admin/img/icon-changelink.svg' %}" alt="">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if can_add_related %}
|
{% if can_add_related %}
|
||||||
@ -17,7 +17,7 @@
|
|||||||
data-popup="yes"
|
data-popup="yes"
|
||||||
href="{{ add_related_url }}?{{ url_params }}"
|
href="{{ add_related_url }}?{{ url_params }}"
|
||||||
title="{% blocktranslate %}Add another {{ model }}{% endblocktranslate %}">
|
title="{% blocktranslate %}Add another {{ model }}{% endblocktranslate %}">
|
||||||
<img src="{% static 'admin/img/icon-addlink.svg' %}" alt="{% translate 'Add' %}">
|
<img src="{% static 'admin/img/icon-addlink.svg' %}" alt="">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if can_delete_related %}
|
{% if can_delete_related %}
|
||||||
@ -25,14 +25,14 @@
|
|||||||
data-href-template="{{ delete_related_template_url }}?{{ url_params }}"
|
data-href-template="{{ delete_related_template_url }}?{{ url_params }}"
|
||||||
data-popup="yes"
|
data-popup="yes"
|
||||||
title="{% blocktranslate %}Delete selected {{ model }}{% endblocktranslate %}">
|
title="{% blocktranslate %}Delete selected {{ model }}{% endblocktranslate %}">
|
||||||
<img src="{% static 'admin/img/icon-deletelink.svg' %}" alt="{% translate 'Delete' %}">
|
<img src="{% static 'admin/img/icon-deletelink.svg' %}" alt="">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if can_view_related %}
|
{% if can_view_related %}
|
||||||
<a class="related-widget-wrapper-link view-related" id="view_id_{{ name }}"
|
<a class="related-widget-wrapper-link view-related" id="view_id_{{ name }}"
|
||||||
data-href-template="{{ change_related_template_url }}?{{ view_related_url_params }}"
|
data-href-template="{{ change_related_template_url }}?{{ view_related_url_params }}"
|
||||||
title="{% blocktranslate %}View selected {{ model }}{% endblocktranslate %}">
|
title="{% blocktranslate %}View selected {{ model }}{% endblocktranslate %}">
|
||||||
<img src="{% static 'admin/img/icon-viewlink.svg' %}" alt="{% translate 'View' %}">
|
<img src="{% static 'admin/img/icon-viewlink.svg' %}" alt="">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
76
tests/admin_views/test_related_object_lookups.py
Normal file
76
tests/admin_views/test_related_object_lookups.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
from django.contrib.admin.tests import AdminSeleniumTestCase
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.test import override_settings
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(ROOT_URLCONF="admin_views.urls")
|
||||||
|
class SeleniumTests(AdminSeleniumTestCase):
|
||||||
|
available_apps = ["admin_views"] + AdminSeleniumTestCase.available_apps
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.superuser = User.objects.create_superuser(
|
||||||
|
username="super", password="secret", email="super@example.com"
|
||||||
|
)
|
||||||
|
self.admin_login(
|
||||||
|
username="super", password="secret", login_url=reverse("admin:index")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_related_object_link_images_empty_alt(self):
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
|
album_add_url = reverse("admin:admin_views_album_add")
|
||||||
|
self.selenium.get(self.live_server_url + album_add_url)
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
"add_id_owner",
|
||||||
|
"change_id_owner",
|
||||||
|
"delete_id_owner",
|
||||||
|
"view_id_owner",
|
||||||
|
]
|
||||||
|
for link_id in tests:
|
||||||
|
with self.subTest(link_id):
|
||||||
|
link_image = self.selenium.find_element(
|
||||||
|
By.XPATH, f'//*[@id="{link_id}"]/img'
|
||||||
|
)
|
||||||
|
self.assertEqual(link_image.get_attribute("alt"), "")
|
||||||
|
|
||||||
|
def test_related_object_lookup_link_initial_state(self):
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
|
album_add_url = reverse("admin:admin_views_album_add")
|
||||||
|
self.selenium.get(self.live_server_url + album_add_url)
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
"change_id_owner",
|
||||||
|
"delete_id_owner",
|
||||||
|
"view_id_owner",
|
||||||
|
]
|
||||||
|
for link_id in tests:
|
||||||
|
with self.subTest(link_id):
|
||||||
|
link = self.selenium.find_element(By.XPATH, f'//*[@id="{link_id}"]')
|
||||||
|
self.assertEqual(link.get_attribute("aria-disabled"), "true")
|
||||||
|
|
||||||
|
def test_related_object_lookup_link_enabled(self):
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support.select import Select
|
||||||
|
|
||||||
|
album_add_url = reverse("admin:admin_views_album_add")
|
||||||
|
self.selenium.get(self.live_server_url + album_add_url)
|
||||||
|
|
||||||
|
select_element = self.selenium.find_element(By.XPATH, '//*[@id="id_owner"]')
|
||||||
|
option = Select(select_element).options[-1]
|
||||||
|
self.assertEqual(option.text, "super")
|
||||||
|
select_element.click()
|
||||||
|
option.click()
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
"add_id_owner",
|
||||||
|
"change_id_owner",
|
||||||
|
"delete_id_owner",
|
||||||
|
"view_id_owner",
|
||||||
|
]
|
||||||
|
for link_id in tests:
|
||||||
|
with self.subTest(link_id):
|
||||||
|
link = self.selenium.find_element(By.XPATH, f'//*[@id="{link_id}"]')
|
||||||
|
self.assertIsNone(link.get_attribute("aria-disabled"))
|
Loading…
x
Reference in New Issue
Block a user