mirror of
https://github.com/moodle/moodle.git
synced 2025-04-16 05:54:19 +02:00
MDL-70288 theme_boost: Manage aria-describedby on form validation
* The aria-describedby attribute can be a list of element IDs that describe the element. On form validation, the ID of the error message container is added to this attribute which may already be containing another ID. So we need to properly add/remove the error message ID so that we don't delete any existing ID(s) in the aria-describedby attribute during form validation.
This commit is contained in:
parent
9dabd071fe
commit
da237792ec
@ -1,2 +1,2 @@
|
||||
define ("theme_boost/form-display-errors",["jquery","core/event"],function(a,b){return{enhance:function enhance(c){var d=document.getElementById(c);if(!d){return}a(d).on(b.Events.FORM_FIELD_VALIDATION,function(b,c){b.preventDefault();var e=a(d).closest(".form-group"),f=e.find(".form-control-feedback");if("TEXTAREA"==a(d).prop("tagName")&&e.find("[contenteditable]")){d=e.find("[contenteditable]")}if(""!==c){e.addClass("has-danger");e.data("client-validation-error",!0);a(d).addClass("is-invalid");a(d).attr("aria-describedby",f.attr("id"));a(d).attr("aria-invalid",!0);f.attr("tabindex",0);f.html(c);if(!f.is(":visible")){f.show();f.focus()}}else{if(!0===e.data("client-validation-error")){e.removeClass("has-danger");e.data("client-validation-error",!1);a(d).removeClass("is-invalid");a(d).removeAttr("aria-describedby");a(d).attr("aria-invalid",!1);f.hide()}}});var e=d.closest("form");if(e&&!("boostFormErrorsEnhanced"in e.dataset)){e.addEventListener("submit",function(){var b=a(".form-control-feedback:visible");if(b.length){b[0].focus()}});e.dataset.boostFormErrorsEnhanced=1}}}});
|
||||
define ("theme_boost/form-display-errors",["jquery","core/event"],function(a,b){return{enhance:function enhance(c){var d=document.getElementById(c);if(!d){return}a(d).on(b.Events.FORM_FIELD_VALIDATION,function(b,c){b.preventDefault();var e=a(d).closest(".form-group"),f=e.find(".form-control-feedback"),g=f.attr("id"),h=a(d).attr("aria-describedby");if("undefined"==typeof h){h=""}var i=[];if(h.length){i=h.split(" ")}var j=i.indexOf(g);if("TEXTAREA"==a(d).prop("tagName")&&e.find("[contenteditable]")){d=e.find("[contenteditable]")}if(""!==c){e.addClass("has-danger");e.data("client-validation-error",!0);a(d).addClass("is-invalid");if(-1===j){i.push(g);a(d).attr("aria-describedby",i.join(" "))}a(d).attr("aria-invalid",!0);f.attr("tabindex",0);f.html(c);if(!f.is(":visible")){f.show();f.focus()}}else{if(!0===e.data("client-validation-error")){e.removeClass("has-danger");e.data("client-validation-error",!1);a(d).removeClass("is-invalid");if(-1<j){i.splice(j,1)}if(i.length){h=i.join(" ");a(d).attr("aria-describedby",h)}else{a(d).removeAttr("aria-describedby")}a(d).attr("aria-invalid",!1);f.hide()}}});var e=d.closest("form");if(e&&!("boostFormErrorsEnhanced"in e.dataset)){e.addEventListener("submit",function(){var b=a(".form-control-feedback:visible");if(b.length){b[0].focus()}});e.dataset.boostFormErrorsEnhanced=1}}}});
|
||||
//# sourceMappingURL=form-display-errors.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
@ -35,6 +35,20 @@ define(['jquery', 'core/event'], function($, Event) {
|
||||
event.preventDefault();
|
||||
var parent = $(element).closest('.form-group');
|
||||
var feedback = parent.find('.form-control-feedback');
|
||||
const feedbackId = feedback.attr('id');
|
||||
|
||||
// Get current aria-describedby value.
|
||||
let describedBy = $(element).attr('aria-describedby');
|
||||
if (typeof describedBy === "undefined") {
|
||||
describedBy = '';
|
||||
}
|
||||
// Split aria-describedby attribute into an array of IDs if necessary.
|
||||
let describedByIds = [];
|
||||
if (describedBy.length) {
|
||||
describedByIds = describedBy.split(" ");
|
||||
}
|
||||
// Find the the feedback container in the aria-describedby attribute.
|
||||
const feedbackIndex = describedByIds.indexOf(feedbackId);
|
||||
|
||||
// Sometimes (atto) we have a hidden textarea backed by a real contenteditable div.
|
||||
if (($(element).prop("tagName") == 'TEXTAREA') && parent.find('[contenteditable]')) {
|
||||
@ -44,7 +58,11 @@ define(['jquery', 'core/event'], function($, Event) {
|
||||
parent.addClass('has-danger');
|
||||
parent.data('client-validation-error', true);
|
||||
$(element).addClass('is-invalid');
|
||||
$(element).attr('aria-describedby', feedback.attr('id'));
|
||||
// Append the feedback ID to the aria-describedby attribute if it doesn't exist yet.
|
||||
if (feedbackIndex === -1) {
|
||||
describedByIds.push(feedbackId);
|
||||
$(element).attr('aria-describedby', describedByIds.join(" "));
|
||||
}
|
||||
$(element).attr('aria-invalid', true);
|
||||
feedback.attr('tabindex', 0);
|
||||
feedback.html(msg);
|
||||
@ -61,7 +79,20 @@ define(['jquery', 'core/event'], function($, Event) {
|
||||
parent.removeClass('has-danger');
|
||||
parent.data('client-validation-error', false);
|
||||
$(element).removeClass('is-invalid');
|
||||
$(element).removeAttr('aria-describedby');
|
||||
// If the aria-describedby attribute contains the error container's ID, remove it.
|
||||
if (feedbackIndex > -1) {
|
||||
describedByIds.splice(feedbackIndex, 1);
|
||||
}
|
||||
// Check the remaining element IDs in the aria-describedby attribute.
|
||||
if (describedByIds.length) {
|
||||
// If there's at least one, combine them with a blank space and update the aria-describedby attribute.
|
||||
describedBy = describedByIds.join(" ");
|
||||
// Put back the new describedby attribute.
|
||||
$(element).attr('aria-describedby', describedBy);
|
||||
} else {
|
||||
// If there's none, remove the aria-describedby attribute.
|
||||
$(element).removeAttr('aria-describedby');
|
||||
}
|
||||
$(element).attr('aria-invalid', false);
|
||||
feedback.hide();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user