MDL-85698 core: combo box informs screen reader users

This commit is contained in:
Jayce Birrell
2025-07-29 10:52:55 +09:30
parent 51662cb8ef
commit 38fe5cc384
5 changed files with 59 additions and 3 deletions
+3
View File
@@ -1451,6 +1451,7 @@ $string['moveselectedcategoriesto'] = 'Move selected categories to';
$string['moveselectedcoursesto'] = 'Move selected courses to...';
$string['movetoanotherfolder'] = 'Move to another folder';
$string['moveup'] = 'Move up';
$string['multipleitemsfound'] = 'There are {$a} items found.';
$string['mustconfirm'] = 'You need to confirm your account';
$string['mustchangepassword'] = 'The new password must be different than the current one';
$string['mycourses'] = 'My courses';
@@ -1537,6 +1538,7 @@ $string['nograde'] = 'No grade';
$string['nohelpforactivityorresource'] = 'There is currently no help associated with this resource or activity';
$string['nochange'] = 'No change';
$string['noimagesyet'] = 'No images have been uploaded to your course yet';
$string['noitemsfound'] = 'No items found.';
$string['nologsfound'] = 'No logs have been found';
$string['nomatchingusers'] = 'No users match \'{$a}\'';
$string['nomorecourses'] = 'No more matching courses could be found';
@@ -1611,6 +1613,7 @@ $string['numyears'] = '{$a} years';
$string['ok'] = 'OK';
$string['oldpassword'] = 'Current password';
$string['olduserdirectory'] = 'This is the OLD users directory, and is no longer needed. You may safely delete it. The files it contains have been copied to the NEW user directory.';
$string['oneitemfound'] = 'There is 1 item found.';
$string['opendrawerblocks'] = 'Open block drawer';
$string['opendrawerindex'] = 'Open course index';
$string['opensinnewwindow'] = 'Opens in new window';
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,6 +16,8 @@
import $ from 'jquery';
import {debounce} from 'core/utils';
import Pending from 'core/pending';
import {get_string as getString} from 'core/str';
/**
* The class that manages the state of the search within a combobox.
@@ -330,6 +332,7 @@ export default class {
this.setMatchedResults(await this.filterDataset(await this.getDataset()));
this.filterMatchDataset();
await this.renderDropdown();
await this.updateLiveRegion();
}
/**
@@ -345,6 +348,7 @@ export default class {
await this.renderDropdown();
// Set the dropdown to open.
this.toggleDropdown(true);
await this.updateLiveRegion();
}
/**
@@ -380,4 +384,51 @@ export default class {
changeHandler(e) {
// Components may override this method to do something.
}
/**
* Updates the screen reader live region with the result count.
*/
async updateLiveRegion() {
if (!this.searchDropdown?.id) {
return;
}
const idParts = this.searchDropdown.id.split('-');
if (idParts.length < 3) {
return;
}
const [, instanceId, id] = idParts; // E.g. dialog-12-34 only want the last two parts.
const liveRegion = document.getElementById(`combobox-status-${instanceId}-${id}`);
if (!liveRegion) {
return;
}
const resultCount = this.getMatchedResults().length;
let message;
if (resultCount === 0) {
message = await getString('noitemsfound', 'core');
} else if (resultCount === 1) {
message = await getString('oneitemfound', 'core');
} else {
message = await getString('multipleitemsfound', 'core', resultCount);
}
liveRegion.textContent = message;
// Reset previous timeout if it exists.
if (this.liveRegionTimeout) {
clearTimeout(this.liveRegionTimeout);
}
// Clear the feedback message after 4 seconds. This is similar to the default timeout of toast messages
// before disappearing from view. It is important to clear the message to prevent screen reader users from navigating
// into this region and avoiding confusion.
this.liveRegionTimeout = setTimeout(() => {
liveRegion.textContent = '';
this.liveRegionTimeout = null;
}, 4000);
}
}
+2
View File
@@ -90,3 +90,5 @@
</div>
</div>
</div>
<!-- ARIA live region for screen readers -->
<div id="combobox-status-{{instance}}-{{uniqid}}" class="sr-only" aria-live="polite" aria-atomic="true"></div>