MDL-85858 mod_scorm: Fix Table of Contents toggle button's accessibility

* Set proper label via `aria-label`.
* Instead of changing the button's label to 'Show'/'Hide', set the
button's `aria-expanded` attribute accordingly.
* Remove unnecessary event handling for the toggle button when pressing
Enter or Space key. This is already natively supported and triggers
the click event.
* Adjust Behat tests accordingly.
This commit is contained in:
Jun Pataleta
2025-11-28 21:01:09 +08:00
parent 8c1f502f82
commit c30e6ba062
4 changed files with 25 additions and 16 deletions
+1
View File
@@ -425,6 +425,7 @@ $string['syntax'] = 'Syntax error';
$string['tag_error'] = 'Unknown tag ({$a->tag}) with this content: {$a->value}';
$string['time'] = 'Time';
$string['title'] = 'Title';
$string['toggletableofcontents'] = 'Toggle table of contents';
$string['toolbar'] = 'Show the toolbar';
$string['too_many_attributes'] = 'Tag {$a->tag} has too many attributes';
$string['too_many_children'] = 'Tag {$a->tag} has too many children';
+10 -1
View File
@@ -2018,7 +2018,16 @@ function scorm_get_toc($user, $scorm, $cmid, $toclink=TOCJSLINK, $currentorg='',
if ($tocheader) {
$result->toc .= html_writer::end_div().html_writer::end_div();
$result->toc .= html_writer::start_div('loading', array('id' => 'scorm_toc_toggle'));
$result->toc .= html_writer::tag('button', '', array('id' => 'scorm_toc_toggle_btn')).html_writer::end_div();
$toggletoclabel = get_string('toggletableofcontents', 'scorm');
$toggletocbutton = html_writer::tag('button', '', [
'id' => 'scorm_toc_toggle_btn',
'type' => 'button',
'class' => 'btn btn-secondary btn-sm mb-1',
'title' => $toggletoclabel,
'aria-label' => $toggletoclabel,
'aria-controls' => 'scorm_toc',
]);
$result->toc .= $toggletocbutton . html_writer::end_div();
$result->toc .= html_writer::start_div('', array('id' => 'scorm_content'));
$result->toc .= html_writer::div('', '', array('id' => 'scorm_navpanel'));
$result->toc .= html_writer::end_div().html_writer::end_div();
+6 -7
View File
@@ -293,14 +293,14 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
toc.addClass(cssclasses.disabled)
.setAttribute('disabled-by', 'screen-size');
scorm_toc_toggle_btn.setHTML('>')
.set('title', M.util.get_string('show', 'moodle'));
.set('aria-expanded', false);
scorm_content.removeClass(cssclasses.scorm_grid_content_toc_visible)
.addClass(cssclasses.scorm_grid_content_toc_hidden);
} else if (body.get('winWidth') > collapsetocwinsize) {
toc.removeClass(cssclasses.disabled)
.removeAttribute('disabled-by');
scorm_toc_toggle_btn.setHTML('<')
.set('title', M.util.get_string('hide', 'moodle'));
.set('aria-expanded', true);
scorm_content.removeClass(cssclasses.scorm_grid_content_toc_hidden)
.addClass(cssclasses.scorm_grid_content_toc_visible);
}
@@ -310,14 +310,14 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
toc.removeClass(cssclasses.disabled)
.removeAttribute('disabled-by');
scorm_toc_toggle_btn.setHTML('<')
.set('title', M.util.get_string('hide', 'moodle'));
.set('aria-expanded', true);
scorm_content.removeClass(cssclasses.scorm_grid_content_toc_hidden)
.addClass(cssclasses.scorm_grid_content_toc_visible);
} else {
toc.addClass(cssclasses.disabled)
.setAttribute('disabled-by', 'user');
scorm_toc_toggle_btn.setHTML('>')
.set('title', M.util.get_string('show', 'moodle'));
.set('aria-expanded', false);
scorm_content.removeClass(cssclasses.scorm_grid_content_toc_visible)
.addClass(cssclasses.scorm_grid_content_toc_hidden);
}
@@ -634,7 +634,7 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
Y.one('#scorm_toc_toggle').addClass(cssclasses.scorm_grid_toggle);
Y.one('#scorm_toc_toggle_btn')
.setHTML('<')
.setAttribute('title', M.util.get_string('hide', 'moodle'));
.setAttribute('aria-expanded', true);
Y.one('#scorm_content').addClass(cssclasses.scorm_grid_content_toc_visible);
scorm_toggle_toc(true);
}
@@ -645,7 +645,7 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
Y.one('#scorm_toc').addClass(cssclasses.disabled);
Y.one('#scorm_toc_toggle_btn')
.setHTML('>')
.setAttribute('title', M.util.get_string('show', 'moodle'));
.setAttribute('aria-expanded', false);
Y.one('#scorm_content')
.removeClass(cssclasses.scorm_grid_content_toc_visible)
.addClass(cssclasses.scorm_grid_content_toc_hidden);
@@ -861,7 +861,6 @@ M.mod_scorm.init = function(Y, nav_display, navposition_left, navposition_top, h
// Collapse/expand TOC.
Y.one('#scorm_toc_toggle').on('click', scorm_toggle_toc);
Y.one('#scorm_toc_toggle').on('key', scorm_toggle_toc, 'down:enter,32');
// fix layout if window resized
Y.on("windowresize", function() {
scorm_resize_layout();
@@ -29,20 +29,20 @@ Feature: Scorm display options
When I press "Preview"
# Confirm TOC display
# Used css_element to check > and < button display in TOC since similar buttons also exist in navigation
Then I <tocdisplay> see "Golf Explained - Minimum Run-time Calls"
And "[title='Show']" "css_element" <showdisplay> exist
And "[title='Hide']" "css_element" <hidedisplay> exist
Then I <tocdisplay> see "Golf Explained - Minimum Run-time Calls" in the "#scorm_toc" "css_element"
And "Toggle table of contents" "button" <toggletoc> be visible
# Confirm TOC dropdown display
And "scoid" "select" <tocdropdown> exist
# Confirm the navigation display
And "[id='scorm_nav']" "css_element" <navbar> exist
Examples:
| toc | shownavigation | tocdisplay | showdisplay | hidedisplay | tocdropdown | navbar |
| 1 | | should not | should | should not | should not | should not |
| 2 | 1 | should | should | should not | should | should not |
| 0 | 0 | should | should not | should | should not | should not |
| 0 | 1 | should | should not | should | should not | should |
| toc | shownavigation | tocdisplay | toggletoc | tocdropdown | navbar |
| 1 | | should not | should | should not | should not |
| 2 | 1 | should not | should | should | should not |
| 0 | 0 | should | should | should not | should not |
| 0 | 1 | should | should | should not | should |
| 3 | 0 | should not | should not | should not | should not |
Scenario: Student can exit Scorm activity in single activity course format
Given the following "activities" exist: