MDL-84832 tiny_media: Announce when alt text maxlength is reached
Co-authored-by: Meirza <[email protected]>
This commit is contained in:
@@ -1297,6 +1297,7 @@ $string['maximumgradex'] = 'Maximum grade: {$a}';
|
||||
$string['maximumshort'] = 'Max';
|
||||
$string['maximumupload'] = 'Maximum upload size';
|
||||
$string['maximumupload_help'] = 'The maximum file size allowed for student uploads to the course. Additionally, you can further restrict the maximum upload size for each activity.';
|
||||
$string['maxlengthreached'] = 'Maximum character limit of {$a} has been reached';
|
||||
$string['maxnumberweeks'] = 'Maximum number of sections';
|
||||
$string['maxnumberweeks_desc'] = 'The maximum value in the number of sections drop-down menu (applies to certain course formats only).';
|
||||
$string['maxnumcoursesincombo'] = 'Browse <a href="{$a->link}">{$a->numberofcourses} courses</a>.';
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -65,6 +65,7 @@ export class ImageDetails extends MediaBase {
|
||||
this.canShowDropZone = canShowDropZone;
|
||||
this.currentUrl = currentUrl;
|
||||
this.image = image;
|
||||
this.toggleMaxlengthFeedbackSuffix = false;
|
||||
}
|
||||
|
||||
init = function() {
|
||||
@@ -206,13 +207,13 @@ export class ImageDetails extends MediaBase {
|
||||
/**
|
||||
* Handles changes in the image presentation checkbox and enables/disables the image alt text input accordingly.
|
||||
*/
|
||||
presentationChanged() {
|
||||
async presentationChanged() {
|
||||
const presentation = this.root.querySelector(Selectors.IMAGE.elements.presentation);
|
||||
const alt = this.root.querySelector(Selectors.IMAGE.elements.alt);
|
||||
alt.disabled = presentation.checked;
|
||||
|
||||
// Counting the image description characters.
|
||||
this.handleKeyupCharacterCount();
|
||||
await this.handleKeyupCharacterCount();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,10 +400,10 @@ export class ImageDetails extends MediaBase {
|
||||
}
|
||||
});
|
||||
|
||||
this.root.addEventListener('change', (e) => {
|
||||
this.root.addEventListener('change', async(e) => {
|
||||
const presentationEle = e.target.closest(Selectors.IMAGE.elements.presentation);
|
||||
if (presentationEle) {
|
||||
this.presentationChanged();
|
||||
await this.presentationChanged();
|
||||
}
|
||||
|
||||
const constrainEle = e.target.closest(Selectors.IMAGE.elements.constrain);
|
||||
@@ -421,21 +422,21 @@ export class ImageDetails extends MediaBase {
|
||||
}
|
||||
});
|
||||
|
||||
this.root.addEventListener('blur', (e) => {
|
||||
this.root.addEventListener('blur', async(e) => {
|
||||
if (e.target.nodeType === Node.ELEMENT_NODE) {
|
||||
|
||||
const presentationEle = e.target.closest(Selectors.IMAGE.elements.presentation);
|
||||
if (presentationEle) {
|
||||
this.presentationChanged();
|
||||
await this.presentationChanged();
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Character count.
|
||||
this.root.addEventListener('keyup', (e) => {
|
||||
this.root.addEventListener('keyup', async(e) => {
|
||||
const altEle = e.target.closest(Selectors.IMAGE.elements.alt);
|
||||
if (altEle) {
|
||||
this.handleKeyupCharacterCount();
|
||||
await this.handleKeyupCharacterCount();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -456,10 +457,28 @@ export class ImageDetails extends MediaBase {
|
||||
});
|
||||
}
|
||||
|
||||
handleKeyupCharacterCount() {
|
||||
const alt = this.root.querySelector(Selectors.IMAGE.elements.alt).value;
|
||||
async handleKeyupCharacterCount() {
|
||||
const altField = this.root.querySelector(Selectors.IMAGE.elements.alt);
|
||||
const alt = altField.value;
|
||||
const current = this.root.querySelector('#currentcount');
|
||||
current.innerHTML = alt.length;
|
||||
const maxLength = altField.getAttribute('maxlength');
|
||||
const maxLengthFeedback = document.getElementById('maxlength_feedback');
|
||||
if (alt.length >= maxLength) {
|
||||
maxLengthFeedback.textContent = await getString('maxlengthreached', 'core', maxLength);
|
||||
|
||||
// Clever (or hacky?;p) way to ensure that the feedback message is announced to screen readers.
|
||||
const suffix = this.toggleMaxlengthFeedbackSuffix ? '' : '.';
|
||||
maxLengthFeedback.textContent += suffix;
|
||||
this.toggleMaxlengthFeedbackSuffix = !this.toggleMaxlengthFeedbackSuffix;
|
||||
|
||||
// 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.
|
||||
setTimeout(() => {
|
||||
maxLengthFeedback.textContent = '';
|
||||
}, 4000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<span id="currentcount">0</span>
|
||||
<span class="mx-1">/</span>
|
||||
<span id="maximumcount">{{maxlengthalt}}</span>
|
||||
<span id="maxlength_feedback" class="visually-hidden" role="status"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user