WCAG EM Report Tool

WCAG EM Report Tool

Generate a report based on the WCAG Evaluation Methodology (EM).

Step 1: Define the Evaluation Scope

Step 2: Explore the Website

Step 3: Select a Representative Sample

Step 4: Audit the Sample

Add pages in Step 3 to begin the audit.

Step 5: Report Findings

This report summarizes the accessibility conformance of the website ${scope.url} against the ${scope.conformance}. The overall result of this evaluation is: ${conformanceStatus}.

A total of ${sample.length} pages were tested, with ${totalFail} failed instances, ${totalPass} passed instances, and ${totalNa} not applicable instances found across ${wcagCriteria.length} criteria.

Detailed Findings

${Object.keys(failedCriteria).length > 0 ? '' : '

No failed criteria found.

'} `; for (const sc in failedCriteria) { const criterion = wcagCriteria.find(c => c.id === sc); reportHtml += `

${criterion.id} ${criterion.name} (Level ${criterion.level}) - FAILED

    ${failedCriteria[sc].map(f => `
  • On page ${f.url}: ${f.notes || 'No notes provided.'}
  • `).join('')}
`; } reportHtml += `
`; dom.reportPreview.innerHTML = reportHtml; }; // --- EVENT HANDLERS & LOGIC --- const updateReportDataFromUI = () => { reportData.scope.title = dom.evalTitle.value; reportData.scope.commissioner = dom.evalCommissioner.value; reportData.scope.url = dom.evalUrl.value; reportData.scope.conformance = dom.conformanceLevel.value; reportData.scope.tech = dom.techRelied.value; reportData.exploration.commonPages = dom.commonPages.value; reportData.exploration.keyTasks = dom.keyTasks.value; }; dom.addPageBtn.addEventListener('click', () => { const url = dom.newPageUrl.value.trim(); if (url && !reportData.sample.some(p => p.url === url)) { const initialFindings = wcagCriteria.map(sc => ({ sc: sc.id, result: 'na', notes: '' })); reportData.sample.push({ url, findings: initialFindings }); dom.newPageUrl.value = ''; renderPageSampleList(); renderAuditSection(); } }); dom.pageSampleList.addEventListener('click', (e) => { if (e.target.closest('.remove-page-btn')) { const index = e.target.closest('.remove-page-btn').dataset.index; reportData.sample.splice(index, 1); renderPageSampleList(); renderAuditSection(); } }); dom.auditSection.addEventListener('change', (e) => { if (e.target.classList.contains('audit-result')) { const { pageIndex, scId } = e.target.dataset; const finding = reportData.sample[pageIndex].findings.find(f => f.sc === scId); if (finding) { finding.result = e.target.value; } } }); dom.auditSection.addEventListener('input', (e) => { if (e.target.classList.contains('audit-notes')) { const { pageIndex, scId } = e.target.dataset; const finding = reportData.sample[pageIndex].findings.find(f => f.sc === scId); if (finding) { finding.notes = e.target.value; } } }); dom.downloadPdfBtn.addEventListener('click', async () => { const { jsPDF } = window.jspdf; const pdfExportArea = document.getElementById('pdf-export-area'); const originalBg = pdfExportArea.style.backgroundColor; pdfExportArea.style.backgroundColor = 'white'; try { const canvas = await html2canvas(pdfExportArea, { scale: 2, useCORS: true }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const canvasWidth = canvas.width; const canvasHeight = canvas.height; const ratio = canvasWidth / canvasHeight; const newCanvasWidth = pdfWidth; const newCanvasHeight = newCanvasWidth / ratio; let heightLeft = newCanvasHeight; let position = 0; pdf.addImage(imgData, 'PNG', 0, position, newCanvasWidth, newCanvasHeight); heightLeft -= pdfHeight; while (heightLeft > 0) { position = heightLeft - newCanvasHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, newCanvasWidth, newCanvasHeight); heightLeft -= pdfHeight; } pdf.save('WCAG-EM-Report.pdf'); } catch (error) { console.error("Error generating PDF:", error); alert("Could not generate PDF. Please try again."); } finally { pdfExportArea.style.backgroundColor = originalBg; } }); // --- TAB NAVIGATION --- window.changeTab = (button, tabId) => { updateReportDataFromUI(); // Save data before switching tabs currentTabIndex = Array.from(dom.tabButtons).indexOf(button); dom.tabs.forEach(tab => tab.classList.remove('active')); dom.tabButtons.forEach(btn => btn.classList.remove('active')); document.getElementById(tabId).classList.add('active'); button.classList.add('active'); if (tabId === 'step5') { renderReport(); } updateNavButtons(); }; const updateNavButtons = () => { dom.prevTabBtn.disabled = currentTabIndex === 0; dom.nextTabBtn.disabled = currentTabIndex === dom.tabButtons.length - 1; }; dom.nextTabBtn.addEventListener('click', () => { if (currentTabIndex < dom.tabButtons.length - 1) { dom.tabButtons[currentTabIndex + 1].click(); } }); dom.prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) { dom.tabButtons[currentTabIndex - 1].click(); } }); // --- INITIALIZATION --- renderPageSampleList(); renderAuditSection(); updateNavButtons(); lucide.createIcons(); });
Scroll to Top