Skip to content

Commit

Permalink
Render a11y issues in separate upgraded cards
Browse files Browse the repository at this point in the history
  • Loading branch information
albinazs committed Jul 15, 2024
1 parent 9d1bf25 commit 7947199
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 136 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Changelog
* Make `routable_resolver_match` attribute available on RoutablePageMixin responses (Andy Chosak)
* Support customizations to `UserViewSet` via the app config (Sage Abdullah)
* Add word count and reading time metrics within the page editor (Albina Starykova. Sponsored by The Motley Fool)
* Implement a new design for accessibility checks (Albina Starykova)
* Fix: Make `WAGTAILIMAGES_CHOOSER_PAGE_SIZE` setting functional again (Rohit Sharma)
* Fix: Enable `richtext` template tag to convert lazy translation values (Benjamin Bach)
* Fix: Ensure permission labels on group permissions page are translated where available (Matt Westcott)
Expand Down
41 changes: 19 additions & 22 deletions client/scss/components/_a11y-result.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
.w-a11y-result__row {
@include box;
padding: theme('spacing.4');
display: flex;
justify-content: space-between;
}

.w-a11y-result__header {
margin: 0;
margin: 0 0 theme('spacing.[0.5]');
width: 100%;
display: flex;
justify-content: space-between;
Expand All @@ -21,40 +23,34 @@
font-weight: theme('fontWeight.semibold');
}

.w-a11y-result__container {
display: flex;
flex-wrap: wrap;
gap: theme('spacing.[2.5]');
padding-top: theme('spacing.3');
}

.w-a11y-result__subtotal_count {
color: theme('colors.icon-primary');
width: theme('spacing.5');
text-align: center;
font-size: theme('fontSize.11');
font-weight: theme('fontWeight.normal');
.w-a11y-result__help {
color: theme('colors.text-placeholder');
font-size: theme('fontSize.14');

.w-dialog--userbar & {
font-size: theme('fontSize.14');
font-size: theme('fontSize.16');
}
}

.w-a11y-result__selector {
display: flex;
align-items: center;
background: theme('colors.surface-field-inactive');
color: theme('colors.text-context');
justify-content: center;
background: theme('colors.surface-page');
border-radius: theme('borderRadius.DEFAULT');
padding: theme('spacing.[1.5]');
margin-top: calc(theme('spacing.[2.5]') * -1);
margin-inline-end: calc(theme('spacing.[2.5]') * -1);
height: theme('spacing.[7.5]');
width: theme('spacing.[7.5]');

&:hover,
&:focus {
background: theme('colors.surface-button-default');
color: theme('colors.text-button');
background: theme('colors.surface-header');

.w-a11y-result__icon {
fill: theme('colors.text-button');
@apply w-scale-110;

fill: theme('colors.text-context');
}
}

Expand All @@ -64,11 +60,12 @@
}

.w-a11y-result__icon {
@apply w-transition hover:w-transform;

flex-shrink: 0;
fill: theme('colors.surface-button-default');
height: theme('spacing.[3.5]');
width: theme('spacing.[3.5]');
margin-inline-end: theme('spacing.[1.5]');
}

.w-a11y-result__count {
Expand Down
12 changes: 1 addition & 11 deletions client/src/entrypoints/admin/preview-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ const runContentChecks = async () => {

const runAccessibilityChecks = async (onClickSelector) => {
const a11yRowTemplate = document.querySelector('#w-a11y-result-row-template');
const a11ySelectorTemplate = document.querySelector(
'#w-a11y-result-selector-template',
);
const checksPanel = document.querySelector('[data-checks-panel]');
const config = getAxeConfiguration(document.body);
const toggleCounter = document.querySelector(
Expand All @@ -41,13 +38,7 @@ const runAccessibilityChecks = async (onClickSelector) => {
'[data-side-panel="checks"] [data-a11y-result-count]',
);

if (
!a11yRowTemplate ||
!a11ySelectorTemplate ||
!config ||
!toggleCounter ||
!panelCounter
) {
if (!a11yRowTemplate || !config || !toggleCounter || !panelCounter) {
return;
}

Expand Down Expand Up @@ -75,7 +66,6 @@ const runAccessibilityChecks = async (onClickSelector) => {
results,
config,
a11yRowTemplate,
a11ySelectorTemplate,
onClickSelector,
);
};
Expand Down
78 changes: 35 additions & 43 deletions client/src/includes/a11y-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ export const sortAxeViolations = (violations: Result[]) =>
* Wagtail's Axe configuration object. This should reflect what's returned by
* `wagtail.admin.userbar.AccessibilityItem.get_axe_configuration()`.
*/

interface ErrorMessage {
error_name: string;
help_text: string;
}
export interface WagtailAxeConfiguration {
context: ElementContext;
options: RunOptions;
messages: Record<string, string>;
messages: Record<string, ErrorMessage>;
spec: Spec;
}

Expand Down Expand Up @@ -151,7 +156,6 @@ export const renderA11yResults = (
results: AxeResults,
config: WagtailAxeConfiguration,
a11yRowTemplate: HTMLTemplateElement,
a11ySelectorTemplate: HTMLTemplateElement,
onClickSelector: (selectorName: string, event: MouseEvent) => void,
) => {
// Reset contents ahead of rendering new results.
Expand All @@ -160,54 +164,42 @@ export const renderA11yResults = (

if (results.violations.length) {
const sortedViolations = sortAxeViolations(results.violations);
sortedViolations.forEach((violation, violationIndex) => {
container.appendChild(a11yRowTemplate.content.cloneNode(true));
const currentA11yRow = container.querySelectorAll<HTMLDivElement>(
'[data-a11y-result-row]',
)[violationIndex];

const a11yErrorName = currentA11yRow.querySelector(
'[data-a11y-result-name]',
) as HTMLSpanElement;
a11yErrorName.id = `w-a11y-result__name-${violationIndex}`;
// Display custom error messages supplied by Wagtail if available,
// fallback to default error message from Axe
a11yErrorName.textContent =
config.messages[violation.id] || violation.help;
const a11yErrorCount = currentA11yRow.querySelector(
'[data-a11y-result-count]',
) as HTMLSpanElement;
a11yErrorCount.textContent = `${violation.nodes.length}`;

const a11yErrorContainer = currentA11yRow.querySelector(
'[data-a11y-result-container]',
) as HTMLDivElement;

violation.nodes.forEach((node, nodeIndex) => {
a11yErrorContainer.appendChild(
a11ySelectorTemplate.content.cloneNode(true),
);
const currentA11ySelector =
a11yErrorContainer.querySelectorAll<HTMLButtonElement>(
'[data-a11y-result-selector]',
)[nodeIndex];

currentA11ySelector.setAttribute('aria-describedby', a11yErrorName.id);
const currentA11ySelectorText = currentA11ySelector.querySelector(
'[data-a11y-result-selector-text]',
let nodeCounter = 0;
sortedViolations.forEach((violation) => {
violation.nodes.forEach((node) => {
container.appendChild(a11yRowTemplate.content.cloneNode(true));

const currentA11yRow = container.querySelectorAll<HTMLDivElement>(
'[data-a11y-result-row]',
)[nodeCounter];
nodeCounter += 1;

const a11yErrorName = currentA11yRow.querySelector(
'[data-a11y-result-name]',
) as HTMLSpanElement;
a11yErrorName.id = `w-a11y-result__name-${nodeCounter}`;
// Display custom error messages supplied by Wagtail if available,
// fallback to default error message from Axe
a11yErrorName.textContent =
config.messages[violation.id].error_name || violation.help;
const a11yErrorHelp = currentA11yRow.querySelector(
'[data-a11y-result-help]',
) as HTMLDivElement;
a11yErrorHelp.textContent =
config.messages[violation.id].help_text || '';

// Special-case when displaying accessibility results within the admin interface.
const selectorName = toSelector(
node.target[0] === '#preview-iframe'
? node.target[1]
: node.target[0],
);
// Remove unnecessary details before displaying selectors to the user
currentA11ySelectorText.textContent = selectorName.replace(
/\[data-block-key="\w{5}"\]/,
'',
);
currentA11ySelector.addEventListener(

const a11ySelector = currentA11yRow.querySelector(
'[data-a11y-result-selector]',
) as HTMLButtonElement;
a11ySelector.setAttribute('aria-describedby', a11yErrorName.id);
a11ySelector?.addEventListener(
'click',
onClickSelector.bind(null, selectorName),
);
Expand Down
12 changes: 1 addition & 11 deletions client/src/includes/userbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,21 +362,12 @@ export class Userbar extends HTMLElement {
const a11yRowTemplate = this.shadowRoot.querySelector<HTMLTemplateElement>(
'#w-a11y-result-row-template',
);
const a11ySelectorTemplate =
this.shadowRoot.querySelector<HTMLTemplateElement>(
'#w-a11y-result-selector-template',
);
const a11yOutlineTemplate =
this.shadowRoot.querySelector<HTMLTemplateElement>(
'#w-a11y-result-outline-template',
);

if (
!accessibilityResultsBox ||
!a11yRowTemplate ||
!a11ySelectorTemplate ||
!a11yOutlineTemplate
) {
if (!accessibilityResultsBox || !a11yRowTemplate || !a11yOutlineTemplate) {
return;
}

Expand Down Expand Up @@ -460,7 +451,6 @@ export class Userbar extends HTMLElement {
results,
config,
a11yRowTemplate,
a11ySelectorTemplate,
onClickSelector,
);
} else {
Expand Down
2 changes: 1 addition & 1 deletion docs/releases/6.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ This feature was developed by Albina Starykova and sponsored by The Motley Fool.
* Implement universal listings UI for report views (Sage Abdullah)
* Make `routable_resolver_match` attribute available on RoutablePageMixin responses (Andy Chosak)
* Support customizations to `UserViewSet` via the app config (Sage Abdullah)

* Implement a new design for accessibility checks (Albina Starykova)

### Bug fixes

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
{% load i18n wagtailadmin_tags %}

<template id="w-a11y-result-row-template">
<div class="w-a11y-result__row" data-a11y-result-row>
<h3 class="w-a11y-result__header">
<span class="w-a11y-result__name" data-a11y-result-name></span>
<span class="w-sr-only">{% trans 'Issues found' %}</span><span class="w-a11y-result__subtotal_count" data-a11y-result-count></span>
</h3>
<div class="w-a11y-result__container" data-a11y-result-container></div>
<div>
<h3 class="w-a11y-result__header">
<span class="w-a11y-result__name" data-a11y-result-name></span>
</h3>
<div class="w-a11y-result__help" data-a11y-result-help></div>
</div>
<button class="w-a11y-result__selector"
data-a11y-result-selector
aria-label="{% trans 'Show issue' %}"
type="button">{% icon name="crosshairs" classname="w-a11y-result__icon" %}</button>
</div>
</template>
<template id="w-a11y-result-selector-template">
Expand All @@ -31,8 +35,8 @@ <h3 class="w-my-2 w-text-14 w-text-text-placeholder">{% trans 'Reading time' %}<
</div>
</div>
</div>
<div>
<h2 class="w-flex w-items-center w-gap-2 w-my-5 w-text-16 w-font-bold w-text-text-label">
<div class="w-mt-12">
<h2 class="w-flex w-items-center w-gap-2 w-my-5 w-text-16 w-font-bold">
<span>{% trans 'Issues found' %}</span><span class="w-a11y-result__count" data-a11y-result-count>0</span>
</h2>
<div class="w-flex w-flex-col w-gap-2.5" data-checks-panel></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@
{# Contents of the dialog created in JS based on these templates. #}
<template id="w-a11y-result-row-template">
<div class="w-a11y-result__row" data-a11y-result-row>
<h3 class="w-a11y-result__header">
<span class="w-a11y-result__name" data-a11y-result-name></span>
<span class="w-sr-only">{% trans 'Issues found' %}</span><span class="w-a11y-result__subtotal_count" data-a11y-result-count></span>
</h3>
<div class="w-a11y-result__container" data-a11y-result-container></div>
<div>
<h3 class="w-a11y-result__header">
<span class="w-a11y-result__name" data-a11y-result-name></span>
</h3>
<div class="w-a11y-result__help" data-a11y-result-help></div>
</div>
<button class="w-a11y-result__selector" data-a11y-result-selector aria-label="{% trans 'Show issue' %}" type="button">
{% icon name="crosshairs" classname="w-a11y-result__icon" %}
</button>
</div>
</template>
<template id="w-a11y-result-selector-template">
<button class="w-a11y-result__selector" data-a11y-result-selector type="button">
{% icon name="crosshairs" classname="w-a11y-result__icon" %}
<span data-a11y-result-selector-text></span>
</button>
</template>
<template id="w-a11y-result-outline-template">
<div class="w-a11y-result__outline" data-a11y-result-outline></div>
</template>
Expand Down
28 changes: 22 additions & 6 deletions wagtail/admin/tests/test_userbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,22 +208,32 @@ def test_messages(self):
config = self.get_config()
self.assertIsInstance(config.get("messages"), dict)
self.assertEqual(
config["messages"]["empty-heading"],
"Empty heading found. Use meaningful text for screen reader users.",
config["messages"]["empty-heading"]["error_name"],
"Empty heading found",
)
self.assertEqual(
config["messages"]["empty-heading"]["help_text"],
"Use meaningful text for screen reader users",
)

def test_custom_message(self):
class CustomMessageAccessibilityItem(AccessibilityItem):
# Override via class attribute
axe_messages = {
"empty-heading": "Headings should not be empty!",
"empty-heading": {
"error_name": "Headings should not be empty!",
"help_text": "Use meaningful text!",
},
}

# Override via method
def get_axe_messages(self, request):
return {
**super().get_axe_messages(request),
"color-contrast-enhanced": "Increase colour contrast!",
"color-contrast-enhanced": {
"error_name": "Insufficient colour contrast!",
"help_text": "Ensure contrast ratio of at least 4.5:1",
},
}

with hooks.register_temporarily(
Expand All @@ -234,8 +244,14 @@ def get_axe_messages(self, request):
self.assertEqual(
config["messages"],
{
"empty-heading": "Headings should not be empty!",
"color-contrast-enhanced": "Increase colour contrast!",
"empty-heading": {
"error_name": "Headings should not be empty!",
"help_text": "Use meaningful text!",
},
"color-contrast-enhanced": {
"error_name": "Insufficient colour contrast!",
"help_text": "Ensure contrast ratio of at least 4.5:1",
},
},
)

Expand Down
Loading

0 comments on commit 7947199

Please sign in to comment.