mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-23 19:20:47 +02:00
Merge branch 'main' into ad/3256-new-changes-on-name-servers-page
This commit is contained in:
commit
06870bc8cd
10 changed files with 92 additions and 27 deletions
|
@ -5284,7 +5284,10 @@ const setUpModal = baseComponent => {
|
|||
overlayDiv.classList.add(OVERLAY_CLASSNAME);
|
||||
|
||||
// Set attributes
|
||||
modalWrapper.setAttribute("role", "dialog");
|
||||
// DOTGOV
|
||||
// Removes the dialog role as this causes a double readout bug with screenreaders
|
||||
// modalWrapper.setAttribute("role", "dialog");
|
||||
// END DOTGOV
|
||||
modalWrapper.setAttribute("id", modalID);
|
||||
if (ariaLabelledBy) {
|
||||
modalWrapper.setAttribute("aria-labelledby", ariaLabelledBy);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { hideElement, showElement, addOrRemoveSessionBoolean } from './helpers-admin.js';
|
||||
import { hideElement, showElement, addOrRemoveSessionBoolean, announceForScreenReaders } from './helpers-admin.js';
|
||||
import { handlePortfolioSelection } from './helpers-portfolio-dynamic-fields.js';
|
||||
|
||||
function displayModalOnDropdownClick(linkClickedDisplaysModal, statusDropdown, actionButton, valueToCheck){
|
||||
|
@ -684,3 +684,33 @@ export function initDynamicDomainRequestFields(){
|
|||
handleSuborgFieldsAndButtons();
|
||||
}
|
||||
}
|
||||
|
||||
export function initFilterFocusListeners() {
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
let filters = document.querySelectorAll("#changelist-filter li a"); // Get list of all filter links
|
||||
let clickedFilter = false; // Used to determine if we are truly navigating away or not
|
||||
|
||||
// Restore focus from localStorage
|
||||
let lastClickedFilterId = localStorage.getItem("admin_filter_focus_id");
|
||||
if (lastClickedFilterId) {
|
||||
let focusedElement = document.getElementById(lastClickedFilterId);
|
||||
if (focusedElement) {
|
||||
//Focus the element
|
||||
focusedElement.setAttribute("tabindex", "0");
|
||||
focusedElement.focus({ preventScroll: true });
|
||||
|
||||
// Announce focus change for screen readers
|
||||
announceForScreenReaders("Filter refocused on " + focusedElement.textContent);
|
||||
localStorage.removeItem("admin_filter_focus_id");
|
||||
}
|
||||
}
|
||||
|
||||
// Capture clicked filter and store its ID
|
||||
filters.forEach(filter => {
|
||||
filter.addEventListener("click", function() {
|
||||
localStorage.setItem("admin_filter_focus_id", this.id);
|
||||
clickedFilter = true; // Mark that a filter was clicked
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -32,3 +32,22 @@ export function getParameterByName(name, url) {
|
|||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary live region to announce messages for screen readers.
|
||||
*/
|
||||
export function announceForScreenReaders(message) {
|
||||
let liveRegion = document.createElement("div");
|
||||
liveRegion.setAttribute("aria-live", "assertive");
|
||||
liveRegion.setAttribute("role", "alert");
|
||||
liveRegion.setAttribute("class", "usa-sr-only");
|
||||
document.body.appendChild(liveRegion);
|
||||
|
||||
// Delay the update slightly to ensure it's recognized
|
||||
setTimeout(() => {
|
||||
liveRegion.textContent = message;
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(liveRegion);
|
||||
}, 1000);
|
||||
}, 100);
|
||||
}
|
|
@ -10,7 +10,8 @@ import {
|
|||
initRejectedEmail,
|
||||
initApprovedDomain,
|
||||
initCopyRequestSummary,
|
||||
initDynamicDomainRequestFields } from './domain-request-form.js';
|
||||
initDynamicDomainRequestFields,
|
||||
initFilterFocusListeners } from './domain-request-form.js';
|
||||
import { initDomainFormTargetBlankButtons } from './domain-form.js';
|
||||
import { initDynamicPortfolioFields } from './portfolio-form.js';
|
||||
import { initDynamicDomainInformationFields } from './domain-information-form.js';
|
||||
|
@ -34,6 +35,7 @@ initRejectedEmail();
|
|||
initApprovedDomain();
|
||||
initCopyRequestSummary();
|
||||
initDynamicDomainRequestFields();
|
||||
initFilterFocusListeners();
|
||||
|
||||
// Domain
|
||||
initDomainFormTargetBlankButtons();
|
||||
|
|
|
@ -16,6 +16,7 @@ import { initDomainManagersPage } from './domain-managers.js';
|
|||
import { initDomainDSData } from './domain-dsdata.js';
|
||||
import { initDomainDNSSEC } from './domain-dnssec.js';
|
||||
import { initFormErrorHandling } from './form-errors.js';
|
||||
import { initButtonLinks } from '../getgov-admin/button-utils.js';
|
||||
|
||||
initDomainValidators();
|
||||
|
||||
|
@ -50,3 +51,5 @@ initFormErrorHandling();
|
|||
initPortfolioMemberPageRadio();
|
||||
initPortfolioNewMemberPageToggle();
|
||||
initAddNewMemberPageListeners();
|
||||
|
||||
initButtonLinks();
|
||||
|
|
13
src/registrar/templates/admin/filter.html
Normal file
13
src/registrar/templates/admin/filter.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% comment %} Override of this file: https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/filter.html {% endcomment %}
|
||||
{% load i18n %}
|
||||
<details data-filter-title="{{ title }}" open>
|
||||
<summary>
|
||||
{% blocktranslate with filter_title=title %} By {{ filter_title }} {% endblocktranslate %}
|
||||
</summary>
|
||||
<ul>
|
||||
{% for choice in choices %}
|
||||
<li {% if choice.selected %} class="selected"{% endif %}>
|
||||
<a id="{{ title|lower|cut:' ' }}-filter-{{ choice.display|slugify }}" href="{{ choice.query_string|iriencode }}">{{ choice.display }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
|
@ -9,16 +9,12 @@
|
|||
{% for choice in choices %}
|
||||
{% if choice.reset %}
|
||||
<li{% if choice.selected %} class="selected"{% endif %}">
|
||||
<a href="{{ choice.query_string|iriencode }}" title="{{ choice.display }}">{{ choice.display }}</a>
|
||||
<a id="{{ title|lower|cut:' ' }}-filter-{{ choice.display|slugify }}" href="{{ choice.query_string|iriencode }}" title="{{ choice.display }}">{{ choice.display }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for choice in choices %}
|
||||
{% if not choice.reset %}
|
||||
<li{% if choice.selected %} class="selected"{% endif %}">
|
||||
{% else %}
|
||||
<li{% if choice.selected %} class="selected"{% endif %}>
|
||||
{% if choice.selected and choice.exclude_query_string %}
|
||||
<a role="menuitemcheckbox" class="choice-filter choice-filter--checked" href="{{ choice.exclude_query_string|iriencode }}">{{ choice.display }}
|
||||
<a id="{{ title|lower|cut:' ' }}-filter-{{ choice.display|slugify }}" role="menuitemcheckbox" class="choice-filter choice-filter--checked" href="{{ choice.exclude_query_string|iriencode }}">{{ choice.display }}
|
||||
<svg class="usa-icon position-absolute z-0 left-0" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
||||
<use xlink:href="{%static 'img/sprite.svg'%}#check_box_outline_blank"></use>
|
||||
</svg>
|
||||
|
@ -26,9 +22,8 @@
|
|||
<use xlink:href="{%static 'img/sprite.svg'%}#check"></use>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if not choice.selected and choice.include_query_string %}
|
||||
<a role="menuitemcheckbox" class="choice-filter" href="{{ choice.include_query_string|iriencode }}">{{ choice.display }}
|
||||
{% elif not choice.selected and choice.include_query_string %}
|
||||
<a id="{{ title|lower|cut:' ' }}-filter-{{ choice.display|slugify }}" role="menuitemcheckbox" class="choice-filter" href="{{ choice.include_query_string|iriencode }}">{{ choice.display }}
|
||||
<svg class="usa-icon position-absolute z-0 left-0" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
||||
<use xlink:href="{%static 'img/sprite.svg'%}#check_box_outline_blank"></use>
|
||||
</svg>
|
||||
|
@ -38,4 +33,4 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
</details>
|
|
@ -18,10 +18,10 @@
|
|||
<h1>Manage your domains</h1>
|
||||
|
||||
<p class="margin-top-4">
|
||||
<a href="{% url 'domain-request:start' %}" class="usa-button"
|
||||
<button data-href="{% url 'domain-request:start' %}" class="usa-button use-button-as-link"
|
||||
>
|
||||
Start a new domain request
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
{% include "includes/domains_table.html" with user_domain_count=user_domain_count %}
|
||||
|
|
|
@ -26,10 +26,10 @@
|
|||
<div class="mobile:grid-col-12 tablet:grid-col-6">
|
||||
|
||||
<p class="float-right-tablet tablet:margin-y-0">
|
||||
<a href="{% url 'domain-request:start' %}" class="usa-button"
|
||||
<button data-href="{% url 'domain-request:start' %}" class="usa-button use-button-as-link"
|
||||
>
|
||||
Start a new domain request
|
||||
</a>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
|
|
|
@ -215,14 +215,14 @@ class TestDomainInvitationAdmin(WebTest):
|
|||
)
|
||||
|
||||
# Assert that the filters are added
|
||||
self.assertContains(response, "invited", count=5)
|
||||
self.assertContains(response, "invited", count=6)
|
||||
self.assertContains(response, "Invited", count=2)
|
||||
self.assertContains(response, "retrieved", count=2)
|
||||
self.assertContains(response, "retrieved", count=3)
|
||||
self.assertContains(response, "Retrieved", count=2)
|
||||
|
||||
# Check for the HTML context specificially
|
||||
invited_html = '<a href="?status__exact=invited">Invited</a>'
|
||||
retrieved_html = '<a href="?status__exact=retrieved">Retrieved</a>'
|
||||
invited_html = '<a id="status-filter-invited" href="?status__exact=invited">Invited</a>'
|
||||
retrieved_html = '<a id="status-filter-retrieved" href="?status__exact=retrieved">Retrieved</a>'
|
||||
|
||||
self.assertContains(response, invited_html, count=1)
|
||||
self.assertContains(response, retrieved_html, count=1)
|
||||
|
@ -1269,14 +1269,14 @@ class TestPortfolioInvitationAdmin(TestCase):
|
|||
)
|
||||
|
||||
# Assert that the filters are added
|
||||
self.assertContains(response, "invited", count=4)
|
||||
self.assertContains(response, "invited", count=5)
|
||||
self.assertContains(response, "Invited", count=2)
|
||||
self.assertContains(response, "retrieved", count=2)
|
||||
self.assertContains(response, "retrieved", count=3)
|
||||
self.assertContains(response, "Retrieved", count=2)
|
||||
|
||||
# Check for the HTML context specificially
|
||||
invited_html = '<a href="?status__exact=invited">Invited</a>'
|
||||
retrieved_html = '<a href="?status__exact=retrieved">Retrieved</a>'
|
||||
invited_html = '<a id="status-filter-invited" href="?status__exact=invited">Invited</a>'
|
||||
retrieved_html = '<a id="status-filter-retrieved" href="?status__exact=retrieved">Retrieved</a>'
|
||||
|
||||
self.assertContains(response, invited_html, count=1)
|
||||
self.assertContains(response, retrieved_html, count=1)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue