Skip to content

Commit

Permalink
Merge pull request #1280 from maykinmedia/issue/2379-search-feedback-…
Browse files Browse the repository at this point in the history
…notification

♿ [#2379] Search feedback notification for screenreaders
  • Loading branch information
alextreme authored Jul 11, 2024
2 parents a731fd9 + 2f6998e commit ad14929
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/open_inwoner/cms/cases/tests/test_htmx.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ def mock_upload(request, context):
upload_form = page.locator("#document-upload")
file_input = upload_form.get_by_label("Sleep of selecteer bestanden")
submit_button = upload_form.get_by_role("button", name=_("Upload documenten"))
notification_list = page.get_by_role("alert").get_by_role("list")
notification_list = page.locator(".notification").get_by_role("list")
notification_list_items = notification_list.get_by_role("listitem")
file_list = page.get_by_role("list").last
file_list_items = file_list.get_by_role("listitem")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="notifications notifications__errors">
<div class="notification notification--warning">
{% icon icon="warning_amber" icon_position="before" outlined=True %}
<div class="notification__content">
<div class="notification__content" role="alert" tabindex="-1">
<p class="utrecht-paragraph utrecht-paragraph--oip utrecht-paragraph--oip-compact">{{ message.message }}</p>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
{% load i18n utils button_tags icon_tags button_tags icon_tags %}
<div class="notification{% if contents %} notification--contents{% endif %}{% if type %} notification--{{ type }}{% endif %}{% if compact %} notification--compact{% endif %} {% if ctx %}notification--{{ ctx }}{% endif %}" role="alert">
<div class="notification{% if contents %} notification--contents{% endif %}{% if type %} notification--{{ type }}{% endif %}{% if compact %} notification--compact{% endif %} {% if ctx %}notification--{{ ctx }}{% endif %}">
{% if not icon == False %}
<div class="notification__icon">
{% icon icon outlined=True %}
</div>
{% endif %}

<div class="notification__content">
<div class="notification__content"
{% if type == "error" %}
role="alert"
{% elif type == "warning" %}
role="alert"
{% else %}
role="status"
{% endif %} tabindex="-1">
{% if title %}<h2 class="utrecht-heading-2">{{ title }}</h2>{% endif %}
{% if notification %}<p class="utrecht-paragraph">{{ notification }}</p>{% endif %}
{% if action %}{% button href=action text=action_text %}{% endif %}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% load notification_tags string_tags %}

<div class="notifications">
<section class="notifications">
{% for message in messages %}
{% with as_markdown=message.extra_tags|is_substring:"as_markdown" %}
{% with local_message=message.extra_tags|is_substring:"local_message" %}
Expand All @@ -14,4 +14,4 @@
{% endwith %}
{% endwith %}
{% endfor %}
</div>
</section>
4 changes: 2 additions & 2 deletions src/open_inwoner/conf/locale/nl/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -6552,9 +6552,9 @@ msgstr "Zoekindex opnieuw opbouwen"
#: open_inwoner/search/tests/test_feedback.py:192
#: open_inwoner/search/views.py:158
msgid ""
"Thank you for your feedback. It will help us to improve our search engine"
"Thank you for your feedback, it will help us improve our search engine."
msgstr ""
"Dank u voor uw feedback, hiermee kunnen wij de omgeving verder verbeteren"
"Dank u voor uw feedback, hiermee kunnen wij de omgeving verder verbeteren."

#: open_inwoner/search/tests/test_logging.py:33 open_inwoner/search/views.py:63
#, python-brace-format
Expand Down
7 changes: 7 additions & 0 deletions src/open_inwoner/js/components/form/LoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ export class LoginFormFocus {
}

hideLoginFormOnLoad() {
const notificationContent = this.loginFormColumn.querySelector(
'.notification__content'
)
if (this.loginFormColumn) {
this.loginFormColumn.classList.add('hide')
}
// Show form on error
if (notificationContent) {
this.loginFormColumn.classList.remove('hide')
}
}

addEmailToggleListener() {
Expand Down
95 changes: 85 additions & 10 deletions src/open_inwoner/js/components/notifications/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
const typeOrder = ['error', 'warning', 'success', 'info']

/**
* Helper function to determine the order index of a notification type.
* @param {HTMLElement} notification - The notification element.
* @returns {number} - Order index of the notification type.
*/
const getTypeOrderIndex = (notification) => {
const type = getTypeFromNotification(notification)
return typeOrder.indexOf(type)
}

/**
* Helper function to get the type of a notification.
* @param {HTMLElement} notification - The notification element.
* @returns {string} - Type of the notification.
*/
const getTypeFromNotification = (notification) => {
let notificationType = ''
notification.classList.forEach((cls) => {
if (cls.startsWith('notification--')) {
notificationType = cls.replace('notification--', '')
}
})
return notificationType
}

/**
* Notification class.
* Single Notification class.
* @class
*/
export class Notification {
Expand All @@ -14,6 +41,7 @@ export class Notification {
this.node = node

this.bindEvents()
this.reorderNotifications()
}

/**
Expand All @@ -25,16 +53,27 @@ export class Notification {
}

/**
* Scrolls to the notification content.
* Scrolls to the notification content and sets focus.
*/
scrollToNotification() {
const notificationContent = document.querySelector('.notification__content')
const notificationContents = Array.from(
this.node.querySelectorAll('.notification__content')
)

if (notificationContents) {
notificationContents.forEach((content) => {
// If errors are present, scroll and trigger the opened state
// The document.querySelectorAll method returns elements in the order they appear in the document,
// so the forEach method will create Notification instances in this same order.
content.scrollIntoView({
block: 'center',
behavior: 'smooth',
})

if (notificationContent) {
// If errors are present, scroll and trigger the opened state
notificationContent.scrollIntoView({
block: 'center',
behavior: 'smooth',
// Add a pause before setting focus for screen readers after DOM load
setTimeout(() => {
content.focus()
}, 100)
})
}
}
Expand All @@ -47,8 +86,6 @@ export class Notification {
e.preventDefault()
this.close()
})

this.scrollToNotification()
}

/**
Expand All @@ -57,6 +94,35 @@ export class Notification {
close() {
this.node.parentElement.removeChild(this.node)
}

/**
* Reorders notifications based on type.
*/
reorderNotifications() {
// Select the parent container, in order to re-index its children
const notificationsContainer = document.querySelector('.notifications')

if (notificationsContainer) {
const notifications = Array.from(
// Get first matching element in the document
notificationsContainer.querySelectorAll(Notification.selector)
)

// Re-indexing the NodeList: Sort notifications (children/siblings) based on type order
notifications.sort((a, b) => {
const typeA = getTypeOrderIndex(a)
const typeB = getTypeOrderIndex(b)
return typeA - typeB
})

// Re-append sorted notifications to parent container
notifications.forEach((notification) =>
notificationsContainer.appendChild(notification)
)
} else {
return
}
}
}

// Start!
Expand All @@ -65,3 +131,12 @@ export class Notification {
document
.querySelectorAll(Notification.selector)
.forEach((notification) => new Notification(notification))

// Scroll to the notifications after reordering
setTimeout(() => {
const firstNotification = document.querySelector(Notification.selector)
if (firstNotification) {
const instance = new Notification(firstNotification)
instance.scrollToNotification()
}
}, 0)
6 changes: 6 additions & 0 deletions src/open_inwoner/scss/components/Grid/Grid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
}
}
}

/// Search grid
&--search {
display: flex;
flex-direction: column;
}
}

&--limit &__sidebar,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@
& &__content {
margin-top: var(--spacing-tiny);

&:focus,
&:focus-visible {
outline: none;
border: none;
}

& * {
margin: 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
top: var(--spacing-extra-large);
display: flex;
flex-direction: column;
gap: var(--spacing-extra-large);
gap: var(--spacing-medium);
z-index: 1002;

/// Multiple errors.
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/search/tests/test_feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,6 @@ def test_feedback_form_not_displayed_after_submit(self):
self.assertEqual(
message.message,
_(
"Thank you for your feedback. It will help us to improve our search engine"
"Thank you for your feedback, it will help us improve our search engine."
),
)
2 changes: 1 addition & 1 deletion src/open_inwoner/search/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def form_valid(self, form):
self.request,
messages.SUCCESS,
_(
"Thank you for your feedback. It will help us to improve our search engine"
"Thank you for your feedback, it will help us improve our search engine."
),
)
redirect = furl(reverse("search:search"))
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/templates/pages/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ <h2 class="utrecht-heading-2">{% trans "Zoekfilters" %}</h2>
{# end search filters #}
</aside>

<div class="grid__main">
<div class="grid__main grid__main--search">
{% if paginator.count %}
<div class="search-results">
<h2 class="utrecht-heading-2 search-results__title">
Expand Down

0 comments on commit ad14929

Please sign in to comment.