Browse Source

Fixed #34045 -- Improved accessibility of selecting items in admin changelist.

This adds "aria-label".
Durval Carvalho 2 years ago
parent
commit
85366fbca7

+ 1 - 0
AUTHORS

@@ -288,6 +288,7 @@ answer newbie questions, and generally made Django that much better:
     Doug Beck <doug@douglasbeck.com>
     Doug Napoleone <doug@dougma.com>
     dready <wil@mojipage.com>
+    Durval Carvalho de Souza <dudurval2@gmail.com>
     dusk@woofle.net
     Dustyn Gibson <miigotu@gmail.com>
     Ed Morley <https://github.com/edmorley>

+ 0 - 3
django/contrib/admin/helpers.py

@@ -36,9 +36,6 @@ class ActionForm(forms.Form):
     )
 
 
-checkbox = forms.CheckboxInput({"class": "action-select"}, lambda value: False)
-
-
 class AdminForm:
     def __init__(
         self,

+ 6 - 3
django/contrib/admin/options.py

@@ -13,7 +13,6 @@ from django.contrib.admin.checks import (
     InlineModelAdminChecks,
     ModelAdminChecks,
 )
-from django.contrib.admin.decorators import display
 from django.contrib.admin.exceptions import DisallowedModelAdminToField
 from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
 from django.contrib.admin.utils import (
@@ -962,12 +961,16 @@ class ModelAdmin(BaseModelAdmin):
             action_flag=DELETION,
         )
 
-    @display(description=mark_safe('<input type="checkbox" id="action-toggle">'))
     def action_checkbox(self, obj):
         """
         A list_display column containing a checkbox widget.
         """
-        return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, str(obj.pk))
+        attrs = {
+            "class": "action-select",
+            "aria-label": format_html(_("Select this object for an action - {}"), obj),
+        }
+        checkbox = forms.CheckboxInput(attrs, lambda value: False)
+        return checkbox.render(helpers.ACTION_CHECKBOX_NAME, str(obj.pk))
 
     @staticmethod
     def _get_action_description(func, name):

+ 5 - 1
django/contrib/admin/templatetags/admin_list.py

@@ -96,8 +96,12 @@ def result_headers(cl):
 
             # if the field is the action checkbox: no sorting and special class
             if field_name == "action_checkbox":
+                aria_label = _("Select all objects on this page for an action")
                 yield {
-                    "text": text,
+                    "text": mark_safe(
+                        f'<input type="checkbox" id="action-toggle" '
+                        f'aria-label="{aria_label}">'
+                    ),
                     "class_attrib": mark_safe(' class="action-checkbox-column"'),
                     "sortable": False,
                 }

+ 2 - 0
docs/releases/5.0.txt

@@ -254,6 +254,8 @@ Miscellaneous
 * The ``instance`` argument of the undocumented
   ``BaseModelFormSet.save_existing()`` method is renamed to ``obj``.
 
+* The undocumented ``django.contrib.admin.helpers.checkbox`` is removed.
+
 .. _deprecated-features-5.0:
 
 Features deprecated in 5.0

+ 1 - 1
js_tests/tests.html

@@ -17,7 +17,7 @@
             <table id="result_list">
                 <tr>
                     <th>
-                       <input type="checkbox" id="action-toggle">
+                       <input type="checkbox" id="action-toggle" aria-label="Select all objects on this page for an action">
                     </th>
                 </tr>
                 <tr>

+ 12 - 7
tests/admin_changelist/tests.py

@@ -74,15 +74,15 @@ from .models import (
 )
 
 
-def build_tbody_html(pk, href, extra_fields):
+def build_tbody_html(obj, href, extra_fields):
     return (
         "<tbody><tr>"
         '<td class="action-checkbox">'
         '<input type="checkbox" name="_selected_action" value="{}" '
-        'class="action-select"></td>'
+        'class="action-select" aria-label="Select this object for an action - {}"></td>'
         '<th class="field-name"><a href="{}">name</a></th>'
         "{}</tr></tbody>"
-    ).format(pk, href, extra_fields)
+    ).format(obj.pk, str(obj), href, extra_fields)
 
 
 @override_settings(ROOT_URLCONF="admin_changelist.urls")
@@ -245,7 +245,7 @@ class ChangeListTests(TestCase):
         table_output = template.render(context)
         link = reverse("admin:admin_changelist_child_change", args=(new_child.id,))
         row_html = build_tbody_html(
-            new_child.id, link, '<td class="field-parent nowrap">-</td>'
+            new_child, link, '<td class="field-parent nowrap">-</td>'
         )
         self.assertNotEqual(
             table_output.find(row_html),
@@ -272,7 +272,7 @@ class ChangeListTests(TestCase):
         table_output = template.render(context)
         link = reverse("admin:admin_changelist_child_change", args=(new_child.id,))
         row_html = build_tbody_html(
-            new_child.id, link, '<td class="field-parent nowrap">???</td>'
+            new_child, link, '<td class="field-parent nowrap">???</td>'
         )
         self.assertNotEqual(
             table_output.find(row_html),
@@ -297,7 +297,7 @@ class ChangeListTests(TestCase):
         table_output = template.render(context)
         link = reverse("admin:admin_changelist_child_change", args=(new_child.id,))
         row_html = build_tbody_html(
-            new_child.id,
+            new_child,
             link,
             '<td class="field-age_display">&amp;dagger;</td>'
             '<td class="field-age">-empty-</td>',
@@ -327,13 +327,18 @@ class ChangeListTests(TestCase):
         table_output = template.render(context)
         link = reverse("admin:admin_changelist_child_change", args=(new_child.id,))
         row_html = build_tbody_html(
-            new_child.id, link, '<td class="field-parent nowrap">%s</td>' % new_parent
+            new_child, link, '<td class="field-parent nowrap">%s</td>' % new_parent
         )
         self.assertNotEqual(
             table_output.find(row_html),
             -1,
             "Failed to find expected row element: %s" % table_output,
         )
+        self.assertInHTML(
+            '<input type="checkbox" id="action-toggle" '
+            'aria-label="Select all objects on this page for an action">',
+            table_output,
+        )
 
     def test_result_list_editable_html(self):
         """