From 76a660a4c9fb7545516698957527f7d57f5200ce Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 5 Mar 2025 16:05:09 -0700 Subject: [PATCH] Removed timeout (thanks Zander!), cleanup --- .../assets/src/js/getgov-admin/andi.js | 83 +++++++++++-------- .../assets/src/js/getgov-admin/main.js | 4 +- src/registrar/fixtures/fixtures_portfolios.py | 1 + 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/registrar/assets/src/js/getgov-admin/andi.js b/src/registrar/assets/src/js/getgov-admin/andi.js index 8c17b2d07..a6b42b966 100644 --- a/src/registrar/assets/src/js/getgov-admin/andi.js +++ b/src/registrar/assets/src/js/getgov-admin/andi.js @@ -4,46 +4,57 @@ It relies on an override in detail_table_fieldset.html that provides a span with a corresponding id for aria-describedby content. This allows us to avoid overriding aria-label, which is used by select2 -to send the current dropdown selection to ANDI +to send the current dropdown selection to ANDI. */ -export function initAriaInjections() { +export function initAriaInjectionsForSelect2Dropdowns() { document.addEventListener('DOMContentLoaded', function () { - // Set timeout so this fires after select2.js finishes adding to the DOM - setTimeout(function () { - // Find all spans with "--aria-description" in their id - const descriptionSpans = document.querySelectorAll('span[id*="--aria-description"]'); + // Find all spans with "--aria-description" in their id + const descriptionSpans = document.querySelectorAll('span[id*="--aria-description"]'); - // Iterate through each span to add aria-describedby - descriptionSpans.forEach(function(span) { - // Extract the base ID from the span's id (remove "--aria-description" part) - const fieldId = span.id.replace('--aria-description', ''); + descriptionSpans.forEach(function (span) { + // Extract the base ID from the span's id (remove "--aria-description") + const fieldId = span.id.replace('--aria-description', ''); + const field = document.getElementById(fieldId); - // Find the field element with the corresponding ID - const field = document.getElementById(fieldId); - - // If the field exists, set the aria-describedby attribute - if (field) { - let select2ElementDetected = false - if (field.classList.contains('admin-autocomplete')) { - const select2Id="select2-"+fieldId+"-container" - console.log("select2---> "+select2Id) - // If it's a Select2 component, find the rendered span inside Select2 - const select2SpanThatTriggersAria = document.querySelector("span[aria-labelledby='"+select2Id+"']"); - const select2SpanThatHoldsSelection = document.getElementById(select2Id) - if (select2SpanThatTriggersAria) { - console.log("set select2 aria") - select2SpanThatTriggersAria.setAttribute('aria-describedby', span.id); - // select2SpanThatTriggersAria.setAttribute('aria-labelledby', select2Id); - select2ElementDetected=true - } - } - if (!select2ElementDetected) - { - // Otherwise, set aria-describedby directly on the field - field.setAttribute('aria-describedby', span.id); - } + if (field) { + // If Select2 is already initialized, apply aria-describedby immediately + if (field.classList.contains('select2-hidden-accessible')) { + applyAriaDescribedBy(field, span.id); + return; } - }); - }, 500); + + // Use MutationObserver to detect Select2 initialization + const observer = new MutationObserver(function (mutations) { + if (document.getElementById(fieldId)?.classList.contains("select2-hidden-accessible")) { + applyAriaDescribedBy(field, span.id); + observer.disconnect(); // Stop observing after applying attributes + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + } + }); + + // Function to apply aria-describedby to Select2 UI + function applyAriaDescribedBy(field, descriptionId) { + let select2ElementDetected = false; + const select2Id = "select2-" + field.id + "-container"; + + // Find the Select2 selection box + const select2SpanThatTriggersAria = document.querySelector(`span[aria-labelledby='${select2Id}']`); + + if (select2SpanThatTriggersAria) { + select2SpanThatTriggersAria.setAttribute('aria-describedby', descriptionId); + select2ElementDetected = true; + } + + // If no Select2 component was detected, apply aria-describedby directly to the field + if (!select2ElementDetected) { + field.setAttribute('aria-describedby', descriptionId); + } + } }); } \ No newline at end of file diff --git a/src/registrar/assets/src/js/getgov-admin/main.js b/src/registrar/assets/src/js/getgov-admin/main.js index 456863437..6ea73b9f3 100644 --- a/src/registrar/assets/src/js/getgov-admin/main.js +++ b/src/registrar/assets/src/js/getgov-admin/main.js @@ -19,7 +19,7 @@ import { initDynamicDomainInformationFields } from './domain-information-form.js import { initDynamicDomainFields } from './domain-form.js'; import { initAnalyticsDashboard } from './analytics.js'; import { initButtonLinks } from './button-utils.js'; -import { initAriaInjections } from './andi.js' +import { initAriaInjectionsForSelect2Dropdowns } from './andi.js' // General initModals(); @@ -27,7 +27,7 @@ initCopyToClipboard(); initFilterHorizontalWidget(); initDescriptions(); initSubmitBar(); -initAriaInjections(); +initAriaInjectionsForSelect2Dropdowns(); initButtonLinks(); // Domain request diff --git a/src/registrar/fixtures/fixtures_portfolios.py b/src/registrar/fixtures/fixtures_portfolios.py index b93b9efdd..4bf6f5da6 100644 --- a/src/registrar/fixtures/fixtures_portfolios.py +++ b/src/registrar/fixtures/fixtures_portfolios.py @@ -74,6 +74,7 @@ class PortfolioFixture: if not portfolio.federal_agency: if portfolio_dict.get("federal_agency") is not None: portfolio.federal_agency, _ = FederalAgency.objects.get_or_create(name=portfolio_dict["federal_agency"]) + portfolio.federal_agency.federal_type, _ = Federal_type.objects.get_or_create(name=portfolio_dict["federal_agency"]) else: federal_agencies = FederalAgency.objects.all() # Random choice of agency for selects, used as placeholders for testing.