UNPKG

axe-playwright-report

Version:

Playwright + axe-core integration to run accessibility scans and build HTML dashboard reports.

418 lines (345 loc) 15.2 kB
tailwind.config = { theme: { extend: {} } } function copyToClipboard(text) { if (!navigator.clipboard) { const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; document.body.appendChild(textarea); textarea.focus(); textarea.select(); try { document.execCommand('copy'); } catch (err) { console.error('Fallback: Copy failed', err); } document.body.removeChild(textarea); } else { navigator.clipboard.writeText(text).catch(err => { console.error('Clipboard API copy failed', err); }); } } function setupToggleDetailsButtons() { document.querySelectorAll('.toggle-details').forEach(button => { button.addEventListener('click', function (e) { e.stopPropagation(); const nodeDetails = this.nextElementSibling; nodeDetails.classList.toggle('hidden'); if (nodeDetails.classList.contains('hidden')) { this.innerHTML = '<i class="fas fa-chevron-down"></i> Show failure details'; } else { this.innerHTML = '<i class="fas fa-chevron-up"></i> Hide failure details'; } }); }); } function getTabColor(tab) { const colors = { 'violations': 'text-red-600 border-red-500', 'incomplete': 'text-blue-600 border-blue-500', 'inapplicable': 'text-orange-500 border-orange-500', 'passes': 'text-green-500 border-green-500' }; return colors[tab] || ''; } function setupTabs() { const tabs = document.querySelectorAll('[data-tab]'); tabs.forEach(tab => { tab.addEventListener('click', () => { const tabValue = tab.getAttribute('data-tab'); console.log('Switching to tab:', tabValue); // Update active tab styling tabs.forEach(t => { t.classList.remove('active', 'text-red-600', 'text-orange-500', 'text-blue-600', 'text-green-500'); t.classList.remove('border-red-500', 'border-orange-500', 'border-blue-500', 'border-green-500'); }); // Set active class for styling tab.classList.add('active'); // Add color classes const colorClasses = getTabColor(tabValue).split(' '); tab.classList.add(...colorClasses); // IMPORTANT: Force-hide all tab contents first document.querySelectorAll('[data-tab-content]').forEach(content => { content.classList.add('hidden'); }); // Then show only the matching tab content const activeContent = document.querySelector(`[data-tab-content="${tabValue}"]`); if (activeContent) { activeContent.classList.remove('hidden'); console.log('Showing content for:', tabValue); } else { console.error('No content found for tab:', tabValue); } }); }); } function toggleIssueCard(element) { const details = element.nextElementSibling; const chevron = element.querySelector(".chevron-icon"); if (details.classList.contains("hidden")) { details.classList.remove("hidden"); chevron.innerHTML = '<path d="m18 15-6-6-6 6"/>'; // Change to down chevron } else { details.classList.add("hidden"); chevron.innerHTML = '<path d="m9 18 6-6-6-6"/>'; // Change to right chevron } } // JavaScript to handle tab and node interactions document.addEventListener('DOMContentLoaded', () => { const tabs = document.querySelectorAll('[data-tab]'); tabs.forEach(tab => { tab.addEventListener('click', () => { const tabValue = tab.getAttribute('data-tab'); console.log('Switching to tab:', tabValue); // Update active tab styling tabs.forEach(t => { t.classList.remove('active', 'text-red-600', 'text-orange-500', 'text-blue-600', 'text-green-500'); t.classList.remove('border-red-500', 'border-orange-500', 'border-blue-500', 'border-green-500'); }); // Set active class for styling tab.classList.add('active'); // Add color classes const colorClasses = getTabColor(tabValue).split(' '); tab.classList.add(...colorClasses); // Hide all tab contents document.querySelectorAll('[data-tab-content]').forEach(content => { content.classList.add('hidden'); }); // Show the matching tab content const activeContent = document.querySelector(`[data-tab-content="${tabValue}"]`); if (activeContent) { activeContent.classList.remove('hidden'); console.log('Showing content for:', tabValue); } else { console.error('No content found for tab:', tabValue); } // Apply pagination to the newly activated tab paginateIssues(tabValue); }); }); const rowsPerPage = 10; let currentPageTable = 1; function paginateTable() { const tableBody = document.getElementById('table-body'); const rows = tableBody.querySelectorAll('tr'); const totalPages = Math.ceil(rows.length / rowsPerPage); console.log(rows) console.log(totalPages) rows.forEach((row, index) => { row.style.display = index >= (currentPageTable - 1) * rowsPerPage && index < currentPageTable * rowsPerPage ? '' : 'none'; }); const controls = document.getElementById('pagination-controls'); controls.innerHTML = ''; for (let i = 1; i <= totalPages; i++) { const btn = document.createElement('button'); btn.innerText = i; if (i === currentPageTable) btn.disabled = true; btn.addEventListener('click', () => { currentPageTable = i; paginateTable(); }); controls.appendChild(btn); } } window.onload = paginateTable; }); function applyFilters(impactFilter, tagFilter, disabilityFilter) { if (!impactFilter || !tagFilter || !disabilityFilter) return; const impactValue = impactFilter.value.toLowerCase(); const tagValue = tagFilter.value.toLowerCase(); const disabilityValue = disabilityFilter.value.toLowerCase(); // First check if any filters are active const isFiltering = impactValue || tagValue || disabilityValue; // Track visible counts for each tab const visibleCounts = { 'violations': 0, 'incomplete': 0, 'inapplicable': 0, 'passes': 0 }; // Filter logic document.querySelectorAll(".issue-card").forEach(card => { const tabContent = card.closest('[data-tab-content]'); const tabName = tabContent ? tabContent.getAttribute('data-tab-content') : null; if (!tabName) return; let showCard = true; // Impact filtering if (impactValue) { const impactEl = card.querySelector(`.bg-red-600, .bg-orange-500, .bg-blue-600, .bg-green-500`); if (!impactEl || !impactEl.textContent.toLowerCase().includes(impactValue)) { showCard = false; } } // Tag filtering if (tagValue && showCard) { const tagElements = card.querySelectorAll(".tag_list span"); let hasTag = false; tagElements.forEach(tag => { if (tag.textContent.toLowerCase().includes(tagValue)) { hasTag = true; } }); if (!hasTag) showCard = false; } // Disability filtering if (disabilityValue && showCard) { const disabilityElements = card.querySelectorAll(".disability_list span"); let hasDisability = false; disabilityElements.forEach(disability => { if (disability.textContent.toLowerCase().includes(disabilityValue)) { hasDisability = true; } }); if (!hasDisability) showCard = false; } card.style.display = showCard ? "" : "none"; // Count visible items by tab if (showCard) { visibleCounts[tabName]++; } }); // Update issue counts and show/hide "no results" messages for each tab Object.keys(visibleCounts).forEach(tabId => { const tabHeader = document.querySelector(`[data-tab="${tabId}"]`); const tabContent = document.querySelector(`[data-tab-content="${tabId}"]`); if (tabHeader) { const countElement = tabHeader.querySelector('.issue-count'); if (countElement) { countElement.textContent = visibleCounts[tabId]; } } if (tabContent) { const noResultsMessage = tabContent.querySelector('.no-results-message'); if (visibleCounts[tabId] === 0) { noResultsMessage.classList.remove('hidden'); } else { noResultsMessage.classList.add('hidden'); } } }); } // Add pagination function function paginateIssues(tab) { const issues = document.querySelectorAll(`[data-tab-content="${tab}"] .issue-card:not(.filtered)`); const totalIssues = issues.length; const totalPages = Math.ceil(totalIssues / ITEMS_PER_PAGE); // Update pagination UI updatePaginationUI(tab, currentPage[tab], totalPages, totalIssues); // Show only issues for current page issues.forEach((issue, index) => { const startIndex = (currentPage[tab] - 1) * ITEMS_PER_PAGE; const endIndex = startIndex + ITEMS_PER_PAGE - 1; if (index >= startIndex && index <= endIndex) { issue.classList.remove('pagination-hidden'); } else { issue.classList.add('pagination-hidden'); } }); } // Function to update pagination UI function updatePaginationUI(tab, currentPage, totalPages, totalIssues) { const paginationContainer = document.querySelector(`[data-tab-content="${tab}"] .pagination`); if (!paginationContainer) return; const numbersContainer = paginationContainer.querySelector('.pagination-numbers'); const prevButton = paginationContainer.querySelector('.pagination-prev'); const nextButton = paginationContainer.querySelector('.pagination-next'); // Update range text const startItem = totalIssues > 0 ? Math.min((currentPage - 1) * ITEMS_PER_PAGE + 1, totalIssues) : 0; const endItem = Math.min(currentPage * ITEMS_PER_PAGE, totalIssues); paginationContainer.querySelector('.current-range').textContent = `${startItem}-${endItem}`; paginationContainer.querySelector('.total-items').textContent = totalIssues; // Disable/enable prev/next buttons prevButton.disabled = currentPage === 1; nextButton.disabled = currentPage === totalPages || totalPages === 0; // Generate page numbers numbersContainer.innerHTML = ''; // Determine range of pages to show let startPage = Math.max(1, currentPage - 2); let endPage = Math.min(totalPages, startPage + 4); // Adjust start if we're near the end if (endPage - startPage < 4) { startPage = Math.max(1, endPage - 4); } // Create page buttons for (let i = startPage; i <= endPage; i++) { const pageButton = document.createElement('button'); pageButton.classList.add('page-number', 'px-3', 'py-1', 'rounded'); if (i === currentPage) { pageButton.classList.add('bg-blue-600', 'text-white'); } else { pageButton.classList.add('border'); } pageButton.textContent = i; pageButton.dataset.page = i; pageButton.dataset.tab = tab; numbersContainer.appendChild(pageButton); } } // Add CSS for pagination hiding const style = document.createElement('style'); style.textContent = `.pagination-hidden { display: none !important; }`; document.head.appendChild(style); document.addEventListener('click', (e) => { // Previous button if (e.target.classList.contains('pagination-prev')) { const tab = document.querySelector('[data-tab].active').getAttribute('data-tab'); if (currentPage[tab] > 1) { currentPage[tab]--; paginateIssues(tab); } } // Next button if (e.target.classList.contains('pagination-next')) { const tab = document.querySelector('[data-tab].active').getAttribute('data-tab'); const issues = document.querySelectorAll(`[data-tab-content="${tab}"] .issue-card:not(.filtered)`); const totalPages = Math.ceil(issues.length / ITEMS_PER_PAGE); if (currentPage[tab] < totalPages) { currentPage[tab]++; paginateIssues(tab); } } // Page number buttons if (e.target.classList.contains('page-number')) { const page = parseInt(e.target.dataset.page); const tab = e.target.dataset.tab; currentPage[tab] = page; paginateIssues(tab); } }); function showDashboard() { document.getElementById('report-page').classList.remove('active'); document.getElementById('report-page').classList.add('hidden'); document.getElementById('dashboard').classList.add('active'); document.getElementById('dashboard').classList.remove('hidden'); document.getElementById('dashboard').style.display = 'block'; // Hide breadcrumb container document.getElementById('breadcrumb-container').style.display = 'none'; } function showReport(filePath) { window.location.href = `./pages/${filePath}.html`; // Automatically activate the 'incomplete' tab on page load const violationsTab = document.querySelector('[data-tab="violations"]'); violationsTab.click(); // Reattach event listeners if necessary const impactFilter = document.getElementById("impact-filter"); const tagFilter = document.getElementById("tag-filter"); const disabilityFilter = document.getElementById("disability-filter"); if (impactFilter) impactFilter.addEventListener("change", () => applyFilters(impactFilter, tagFilter, disabilityFilter)); if (tagFilter) tagFilter.addEventListener("change", () => applyFilters(impactFilter, tagFilter, disabilityFilter)); if (disabilityFilter) disabilityFilter.addEventListener("change", () => applyFilters(impactFilter, tagFilter, disabilityFilter)); // Apply filters to the loaded content applyFilters(impactFilter, tagFilter, disabilityFilter); } function switchTab(tabId) { document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active')); document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active')); document.getElementById(`${tabId}-content`).classList.add('active'); document.querySelector(`.tab[onclick="switchTab('${tabId}')"]`).classList.add('active'); }