Skip to content

Commit

Permalink
rewrites JS to show all violations discovered
Browse files Browse the repository at this point in the history
  • Loading branch information
markconroy committed Nov 4, 2024
1 parent be670ad commit 0b84d57
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 31 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
urls.json
.vscode
urls.json
violations.json
5 changes: 5 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ <h1>Accessibility Report</h1>
<footer class="bg">
<p>Created by Mark Conroy & Big Blue Door</p>
</footer>
<dialog class="dialog-violations">
<button class="dialog-close">Close</button>
<h2 class="dialog-violations__title"></h2>
<ol class="dialog-violations__list"></ol>
</dialog>
<script src="public/script.js"></script>
</body>
</html>
114 changes: 88 additions & 26 deletions public/script.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,50 @@
const app = document.querySelector('#app');
const violations = fetch('violations.json').then(response => response.json());
// Helper function to convert to sentence case
const toSentenceCase = (string) => {
return string
.toLowerCase()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
};
const replaceHyphensWithSpaces = (string) => string.replace(/-/g, ' ');

// Helper function to escape HTML
const escapeHtml = (unsafe) => {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
};

const dialog = document.querySelector('.dialog-violations');
const violationsList = dialog.querySelector('.dialog-violations__list');

violations.then(data => {
const numberOfURLsTested = data.numberOfURLsTested;
const allViolations = data.violations;

// Filter for color-contrast violations
const colorContrastViolations = allViolations.filter(violation => violation.id === 'color-contrast');
// Group violations by type
const violationsByType = allViolations.reduce((acc, violation) => {
if (!acc[violation.id]) {
acc[violation.id] = [];
}
acc[violation.id].push(violation);
return acc;
}, {});

// Create variables for each violation type dynamically
const violationTypes = Object.keys(violationsByType);
const violationVariables = violationTypes.reduce((acc, type) => {
acc[type] = violationsByType[type];
return acc;
}, {});

// Count the number of nodes in color-contrast violations
const numberOfColorContrastNodes = colorContrastViolations.reduce((acc, violation) => acc + violation.nodes.length, 0);
// const numberOfColorContrastNodes = violationVariables['color-contrast'].reduce((acc, violation) => acc + violation.nodes.length, 0);

// Get unique URLs with violations
const uniqueURLsWithViolations = [...new Set(allViolations.map(violation => violation.url))];
Expand All @@ -26,28 +61,55 @@ violations.then(data => {
`).join('')}
</ul>
<h2 id="violations">Accessibility Violations</h2>
<h3>Colour contrast issues</h3>
<p>We found <strong>${numberOfColorContrastNodes}</strong> color-contrast issues across the tested pages.</p>
<p>Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds.</p>
<p>For more information, see <a href="https://www.w3.org/TR/WCAG20/#visual-audio-contrast">WCAG 2.0 Guideline 1.4</a>.</p>
<p>For a list of pages with color-contrast issues, see below:</p>
<ol>
${colorContrastViolations.map(violation => `
<li>
<a href="${violation.url}">${violation.url}</a>
<ul>
${violation.nodes.map(node => `
<li>
<ul>
<li>HTML: ${node.html}</li>
<li>Violating selector: ${node.target.join(' > ')}</li>
<li>Failure summary: ${node.failureSummary}</li>
</ul>
</li>
`).join('')}
</ul>
</li>
`).join('')}
</ol>
<div class="grid grid--2">
${violationTypes.map(type => `
<article class="violations">
<h3>${toSentenceCase(replaceHyphensWithSpaces(type))}</h3>
<p>There are <strong>${violationVariables[type].length} ${type} violations</strong> across <strong>${uniqueURLsWithViolations.length} URLs</strong>.</p>
<ol class="violations__list">
${violationVariables[type].map((violation, index) => `
<li>
<a href="${violation.url}">${violation.url}</a>
<ul>
<li>Description: ${violation.description}</li>
<li>Impact: <span class="impact impact--${violation.impact}">${toSentenceCase(violation.impact)}</span></li>
<li>Instances: ${violation.nodes.length} - <button data-index="${index}" data-type="${type}" class="view-violations" type="button">View All</button></li>
</ul>
</li>
`).join('')}
</ol>
</article>
`).join('')}
</div>
`;

// Event listener for the view violations buttons
document.querySelectorAll('.view-violations').forEach(button => {
button.addEventListener('click', (event) => {
const type = event.target.getAttribute('data-type');
const index = event.target.getAttribute('data-index');
const violation = violationVariables[type][index];
violationsList.innerHTML = '';

violation.nodes.forEach(node => {
console.log(node);
const listItem = document.createElement('li');
listItem.innerHTML = `
<p><strong>HTML:</strong></p>
<code>${escapeHtml(node.html)}</code>
<p><strong>Target:</strong> ${node.target.join(' > ')}</p>
<p><strong>Summary:</strong> ${node.failureSummary}</p>
`;
violationsList.appendChild(listItem);
});

dialog.showModal();
});
});

// Event listener for the close dialog button
dialog.querySelector('.dialog-close').addEventListener('click', () => {
document.querySelector('.dialog-violations').close();
});

});
88 changes: 84 additions & 4 deletions public/style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
:root {
--color-primary: #095dff;
--color-white: #ffffff;
--spacing: 1rem;
--color-grey-lightest: #f2f2f2;
--color-black: #000000;
--transition-time: 0.3s;
--border: 1px solid var(--color-primary);
}

*,
*::before,
*::after {
Expand All @@ -12,7 +22,7 @@ body {
margin: 0;
line-height: 1.5;
font-family: Arial, sans-serif;
color: #095dff;
color: var(--color-black);
}

header,
Expand All @@ -22,20 +32,90 @@ footer {
}

a {
color: #095dff;
color: var(--color-primary);
}
a:hover,
a:focus-visible {
text-decoration: none;
}

a,
button,
input,
select,
textarea {
transition: var(--transition-time);
}

h2 ~ h2 {
margin-block-start: 2rem;
padding-block-start: 2rem;
border-top: 1px solid #095dff;
border-top: 1px solid var(--color-primary);
}

.bg {
background-color: #095dff;
background-color: var(--color-primary);
color: #ffffff;
}

.bg a {
color: #ffffff;
}

.impact {
padding: 0.15rem;
border: var(--border);
color: var(--color-black);
border-color: var(--color-black);
}
.impact--minor {
background-color: #f3ea00;
}
.impact--moderate {
background-color: #d4cd00;
}
.impact--serious {
background-color: #c86e00;
color: var(--color-white);
}
.impact--critical {
color: var(--color-white);
background-color: #dc0000;
}

dialog::backdrop {
background-color: var(--color-primary);
opacity: 0.9;
}

button {
padding: 0.25rem 0.5rem;
background-color: var(--color-primary);
color: var(--color-white);
border: var(--border);
}
button:focus-visible,
button:hover {
background-color: var(--color-white);
color: var(--color-primary);
border-color: var(--color-primary);
}

.violations {
padding: 1rem;
background-color: var(--color-grey-lightest);
border: var(--border);
}

.violations__list > li {
margin-block-end: 1rem;
}
.violations__list > li li {
margin-block-start: 0.5rem;
}

.grid {
display: grid;
gap: var(--spacing);
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
}

0 comments on commit 0b84d57

Please sign in to comment.