From c932e8b7e16a623b1a3cc590195d2a340fff3f32 Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Fri, 13 Mar 2026 14:05:55 +0000 Subject: [PATCH] Make WCAG criterion badges clickable links to Understanding pages Each issue card's WCAG criterion (e.g. "1.4.3") is now a link to the WAI Understanding page at w3.org. Comma-separated multi-criteria and PDF/UA are handled separately. Links open in a new tab. - js/utils.js: WCAG_SLUGS map + wcagCriterionLinks() helper - js/results.js: issue-meta now calls wcagCriterionLinks() - css/styles.css: .wcag-link style (dotted underline, hover accent) Co-Authored-By: Claude Sonnet 4.6 --- css/styles.css | 13 +++++++++ js/results.js | 2 +- js/utils.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/css/styles.css b/css/styles.css index 4b4a73b..f23d23b 100644 --- a/css/styles.css +++ b/css/styles.css @@ -753,6 +753,19 @@ h1::before { font-weight: 500; } +.wcag-link { + color: var(--info); + text-decoration: none; + font-weight: 600; + border-bottom: 1px dotted var(--info); + transition: color 0.15s, border-color 0.15s; +} + +.wcag-link:hover { + color: var(--accent); + border-bottom-color: var(--accent); +} + .issue-recommendation { background: var(--success-bg); padding: 10px 12px; diff --git a/js/results.js b/js/results.js index e92627e..a018585 100644 --- a/js/results.js +++ b/js/results.js @@ -143,7 +143,7 @@ function createIssueCard(issue, issueNumber, globalIndex) {
${issue.description}
- ${issue.wcag_criterion ? `
WCAG ${issue.wcag_criterion}
` : ''} + ${issue.wcag_criterion ? `
${wcagCriterionLinks(issue.wcag_criterion)}
` : ''} ${issue.recommendation ? `
Tip: ${issue.recommendation}
` : ''} `; } diff --git a/js/utils.js b/js/utils.js index 2319279..2f5fd41 100644 --- a/js/utils.js +++ b/js/utils.js @@ -59,6 +59,80 @@ function getSeverityIcon(severity) { return map[severity] || '\u2022'; } +/* WCAG 2.1 criterion → Understanding page slug */ +const WCAG_SLUGS = { + '1.1.1': 'non-text-content', + '1.2.1': 'audio-only-and-video-only-prerecorded', + '1.2.2': 'captions-prerecorded', + '1.2.3': 'audio-description-or-media-alternative-prerecorded', + '1.2.4': 'captions-live', + '1.2.5': 'audio-description-prerecorded', + '1.3.1': 'info-and-relationships', + '1.3.2': 'meaningful-sequence', + '1.3.3': 'sensory-characteristics', + '1.3.4': 'orientation', + '1.3.5': 'identify-input-purpose', + '1.4.1': 'use-of-color', + '1.4.2': 'audio-control', + '1.4.3': 'contrast-minimum', + '1.4.4': 'resize-text', + '1.4.5': 'images-of-text', + '1.4.6': 'contrast-enhanced', + '1.4.10': 'reflow', + '1.4.11': 'non-text-contrast', + '1.4.12': 'text-spacing', + '1.4.13': 'content-on-hover-or-focus', + '2.1.1': 'keyboard', + '2.1.2': 'no-keyboard-trap', + '2.2.1': 'timing-adjustable', + '2.2.2': 'pause-stop-hide', + '2.3.1': 'three-flashes-or-below-threshold', + '2.4.1': 'bypass-blocks', + '2.4.2': 'page-titled', + '2.4.3': 'focus-order', + '2.4.4': 'link-purpose-in-context', + '2.4.5': 'multiple-ways', + '2.4.6': 'headings-and-labels', + '2.4.7': 'focus-visible', + '2.5.3': 'label-in-name', + '3.1.1': 'language-of-page', + '3.1.2': 'language-of-parts', + '3.1.5': 'reading-level', + '3.2.1': 'on-focus', + '3.2.2': 'on-input', + '3.2.3': 'consistent-navigation', + '3.2.4': 'consistent-identification', + '3.3.1': 'error-identification', + '3.3.2': 'labels-or-instructions', + '3.3.3': 'error-suggestion', + '3.3.4': 'error-prevention-legal-financial-data', + '4.1.1': 'parsing', + '4.1.2': 'name-role-value', + '4.1.3': 'status-messages', +}; + +/** + * Returns an HTML string of clickable WCAG criterion links. + * Handles comma-separated criteria (e.g. "1.3.1, 4.1.2") and "PDF/UA". + */ +function wcagCriterionLinks(criterion) { + if (!criterion) return ''; + + if (criterion.trim().toUpperCase() === 'PDF/UA') { + return 'PDF/UA'; + } + + return criterion.split(',').map(part => { + const num = part.trim(); + const slug = WCAG_SLUGS[num]; + if (slug) { + const url = `https://www.w3.org/WAI/WCAG21/Understanding/${slug}`; + return `WCAG ${num}`; + } + return `WCAG ${num}`; + }).join(', '); +} + function escapeAttr(str) { return String(str).replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '"'); }