UNPKG

axe-playwright-report

Version:

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

793 lines (683 loc) 31.5 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-yellow-800 border-yellow-800', '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-yellow-800', 'text-green-500'); t.classList.remove('border-red-500', 'border-orange-500', 'border-yellow-800', '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); } // Update select-all checkbox states after tab switch updateSelectAllCheckboxStates(); // Update the badge count after tab switch updateBugReportButtonBadge(); }); }); } 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-yellow-800', 'text-green-500'); t.classList.remove('border-red-500', 'border-orange-500', 'border-yellow-800', '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); 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; }); // Initialize Select2 for multi-select filters function initializeSelect2() { if (typeof $ !== 'undefined' && $.fn.select2) { $('.select2-filter').select2({ placeholder: function() { return $(this).data('placeholder'); }, allowClear: true, width: '100%' }); } } function applyFilters(impactFilter, tagFilter, disabilityFilter) { if (!impactFilter || !tagFilter || !disabilityFilter) return; // Get selected values from Select2 (multiple selections) const impactValues = $(impactFilter).val() || []; const tagValues = $(tagFilter).val() || []; const disabilityValues = $(disabilityFilter).val() || []; // Check if any filters are active const isFiltering = impactValues.length > 0 || tagValues.length > 0 || disabilityValues.length > 0; // 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 - check if any selected impact matches if (impactValues.length > 0) { const impactEl = card.querySelector(`.issue-impact`); if (!impactEl) { showCard = false; } else { const cardImpact = impactEl.textContent.toLowerCase(); const hasMatchingImpact = impactValues.some(selectedImpact => cardImpact.includes(selectedImpact.toLowerCase()) ); if (!hasMatchingImpact) { showCard = false; } } } // Tag filtering - check if any selected tag matches if (tagValues.length > 0 && showCard) { const tagElements = card.querySelectorAll(".tag_list span"); let hasMatchingTag = false; tagElements.forEach(tag => { const tagText = tag.textContent.toLowerCase(); if (tagValues.some(selectedTag => tagText.includes(selectedTag.toLowerCase()))) { hasMatchingTag = true; } }); if (!hasMatchingTag) showCard = false; } // Disability filtering - check if any selected disability matches if (disabilityValues.length > 0 && showCard) { const disabilityElements = card.querySelectorAll(".disability_list span"); let hasMatchingDisability = false; disabilityElements.forEach(disability => { const disabilityText = disability.textContent.toLowerCase(); if (disabilityValues.some(selectedDisability => disabilityText.includes(selectedDisability.toLowerCase()) )) { hasMatchingDisability = true; } }); if (!hasMatchingDisability) 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'); } } }); // Update select-all checkbox states based on no-results messages updateSelectAllCheckboxStates(); // Update the badge count after filtering updateBugReportButtonBadge(); } // 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 'violations' tab on page load // const violationsTab = document.querySelector('[data-tab="violations"]'); // violationsTab.click(); // // // Initialize Select2 after DOM is loaded // $(document).ready(function() { // initializeSelect2(); // // // Get filter elements // const impactFilter = document.getElementById("impact-filter"); // const tagFilter = document.getElementById("tag-filter"); // const disabilityFilter = document.getElementById("disability-filter"); // // // Add Select2 change event listeners // if (impactFilter) { // $(impactFilter).on('change', () => applyFilters(impactFilter, tagFilter, disabilityFilter)); // } // if (tagFilter) { // $(tagFilter).on('change', () => applyFilters(impactFilter, tagFilter, disabilityFilter)); // } // if (disabilityFilter) { // $(disabilityFilter).on('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'); } // Initialize everything when DOM is ready $(document).ready(function() { // Initialize Select2 initializeSelect2(); // Set up filter event listeners const impactFilter = document.getElementById("impact-filter"); const tagFilter = document.getElementById("tag-filter"); const disabilityFilter = document.getElementById("disability-filter"); if (impactFilter) { $(impactFilter).on('change', () => applyFilters(impactFilter, tagFilter, disabilityFilter)); } if (tagFilter) { $(tagFilter).on('change', () => applyFilters(impactFilter, tagFilter, disabilityFilter)); } if (disabilityFilter) { $(disabilityFilter).on('change', () => applyFilters(impactFilter, tagFilter, disabilityFilter)); } // Set up select-all checkboxes for violations and incomplete tabs ['violations', 'incomplete'].forEach(tabName => { const selectAllCheckbox = document.getElementById('select-all-checkbox-' + tabName); if (selectAllCheckbox) { selectAllCheckbox.addEventListener('change', function() { const checked = this.checked; const tabContent = document.querySelector('[data-tab-content="' + tabName + '"]'); if (tabContent && !tabContent.classList.contains('hidden')) { // Only select/deselect visible checkboxes tabContent.querySelectorAll('input[type="checkbox"][id^="issue-"]').forEach(cb => { const issueCard = cb.closest('.issue-card'); if (issueCard && issueCard.style.display !== 'none') { cb.checked = checked; } }); } }); } }); // Initial update of select-all checkbox states updateSelectAllCheckboxStates(); // Initial update of badge count updateBugReportButtonBadge(); }); // --- DASHBOARD TABLE SEARCH --- $(document).ready(function() { const dashboardSearchInput = document.getElementById('dashboard-search-input'); const dashboardSearchButton = document.getElementById('dashboard-search-button'); const filterPriority = document.getElementById('filter-priority'); if (dashboardSearchInput) { dashboardSearchInput.addEventListener('input', performSearch); } if (dashboardSearchButton) { dashboardSearchButton.addEventListener('click', performSearch); } if (filterPriority) { filterPriority.addEventListener('change', performSearch); } }); // Enhanced search and filter functionality function performSearch() { const searchInput = document.getElementById('dashboard-search-input'); const filterSelect = document.getElementById('filter-priority'); const searchValue = (searchInput && searchInput.value) ? searchInput.value.toLowerCase() : ''; const filterValue = (filterSelect && filterSelect.value) ? filterSelect.value : 'all'; const rows = document.querySelectorAll('#sortable-table tbody tr'); const tableBody = document.getElementById('table-body'); let visibleCount = 0; rows.forEach(row => { const pageLink = row.querySelector('.url-cell a'); const pageUrl = pageLink ? pageLink.textContent.toLowerCase() : ''; const matchesSearch = searchValue === '' || pageUrl.includes(searchValue); let matchesFilter = true; if (filterValue === 'critical') { const criticalCell = row.querySelector('.status-cell.critical_elements'); const criticalCount = criticalCell ? parseInt(criticalCell.textContent) || 0 : 0; matchesFilter = criticalCount > 0; } else if (filterValue === 'serious') { const seriousCell = row.querySelector('.status-cell.serious_elements'); const seriousCount = seriousCell ? parseInt(seriousCell.textContent) || 0 : 0; matchesFilter = seriousCount > 0; } else if (filterValue === 'moderate') { const moderateCell = row.querySelector('.status-cell.moderate_elements'); const moderateCount = moderateCell ? parseInt(moderateCell.textContent) || 0 : 0; matchesFilter = moderateCount > 0; } else if (filterValue === 'minor') { const minorCell = row.querySelector('.status-cell.minor_elements'); const minorCount = minorCell ? parseInt(minorCell.textContent) || 0 : 0; matchesFilter = minorCount > 0; } else if (filterValue === 'violation') { const violationBadge = row.querySelector('.violation-badge.violations'); const violationCount = violationBadge ? parseInt(violationBadge.textContent) || 0 : 0; matchesFilter = violationCount > 0; } else if (filterValue === 'incomplete') { const incompleteBadge = row.querySelector('.violation-badge.incomplete'); const incompleteCount = incompleteBadge ? parseInt(incompleteBadge.textContent) || 0 : 0; matchesFilter = incompleteCount > 0; } if (matchesSearch && matchesFilter) { row.style.display = ''; visibleCount++; } else { row.style.display = 'none'; } }); // Show/hide no results message let noResultsRow = tableBody.querySelector('.no-results-row'); if (visibleCount === 0) { if (!noResultsRow) { noResultsRow = document.createElement('tr'); noResultsRow.className = 'no-results-row'; noResultsRow.innerHTML = ` <td colspan="6" class="no-results-message"> <div class="text-center py-8"> <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.47-.881-6.08-2.33" /> </svg> <h3 class="mt-2 text-sm font-medium text-gray-900">No pages found</h3> <p class="mt-1 text-sm text-gray-500"> ${searchValue ? `No pages match "${searchValue}"` : ''} ${filterValue !== 'all' ? `No pages have ${filterValue} issues` : ''} ${searchValue && filterValue !== 'all' ? ' with the current criteria' : ''} </p> <div> <button type="button" onclick="clearSearchAndFilters()" class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> Clear filters </button> </div> </div> </td> `; tableBody.appendChild(noResultsRow); } noResultsRow.style.display = ''; const paginationControls = document.getElementById('pagination-controls'); if (paginationControls) { paginationControls.style.display = 'none'; } } else { if (noResultsRow) { noResultsRow.style.display = 'none'; const paginationControls = document.getElementById('pagination-controls'); if (paginationControls) { paginationControls.style.display = ''; } } } } // Function to clear search and filters function clearSearchAndFilters() { const searchInput = document.getElementById('dashboard-search-input'); const filterSelect = document.getElementById('filter-priority'); if (searchInput) { searchInput.value = ''; } if (filterSelect) { filterSelect.value = 'all'; } const paginationControls = document.getElementById('pagination-controls'); if (paginationControls) { paginationControls.style.display = ''; } performSearch(); } // Enhanced table sorting functionality function sortTable(sortBy, direction) { const tableBody = document.getElementById('table-body'); const rows = Array.from(tableBody.querySelectorAll('tr')); const sortedRows = rows.sort((rowA, rowB) => { let valueA, valueB; switch (sortBy) { case 'pagePath': const linkA = rowA.querySelector('.url-cell a'); const linkB = rowB.querySelector('.url-cell a'); valueA = linkA ? linkA.textContent.toLowerCase() : ''; valueB = linkB ? linkB.textContent.toLowerCase() : ''; break; case 'critical_elements': const criticalA = rowA.querySelector('.status-cell.critical_elements'); const criticalB = rowB.querySelector('.status-cell.critical_elements'); valueA = criticalA ? parseInt(criticalA.textContent) || 0 : 0; valueB = criticalB ? parseInt(criticalB.textContent) || 0 : 0; break; case 'serious_elements': const seriousA = rowA.querySelector('.status-cell.serious_elements'); const seriousB = rowB.querySelector('.status-cell.serious_elements'); valueA = seriousA ? parseInt(seriousA.textContent) || 0 : 0; valueB = seriousB ? parseInt(seriousB.textContent) || 0 : 0; break; case 'moderate_elements': const moderateA = rowA.querySelector('.status-cell.moderate_elements'); const moderateB = rowB.querySelector('.status-cell.moderate_elements'); valueA = moderateA ? parseInt(moderateA.textContent) || 0 : 0; valueB = moderateB ? parseInt(moderateB.textContent) || 0 : 0; break; case 'minor_elements': const minorA = rowA.querySelector('.status-cell.minor_elements'); const minorB = rowB.querySelector('.status-cell.minor_elements'); valueA = minorA ? parseInt(minorA.textContent) || 0 : 0; valueB = minorB ? parseInt(minorB.textContent) || 0 : 0; break; case 'violations': const violationBadgeA = rowA.querySelector('.violation-badge.violations'); const violationBadgeB = rowB.querySelector('.violation-badge.violations'); valueA = violationBadgeA ? parseInt(violationBadgeA.textContent) || 0 : 0; valueB = violationBadgeB ? parseInt(violationBadgeB.textContent) || 0 : 0; break; default: return 0; } if (sortBy === 'pagePath') { return direction === 'desc' ? valueB.localeCompare(valueA) : valueA.localeCompare(valueB); } else { return direction === 'desc' ? valueB - valueA : valueA - valueB; } }); // Remove all existing rows while (tableBody.firstChild) { tableBody.removeChild(tableBody.firstChild); } // Add sorted rows sortedRows.forEach(row => { tableBody.appendChild(row); }); } function updateSelectAllCheckboxState() { const noResults = document.querySelector('.no-results-message:not(.hidden)'); const selectAll = document.getElementById('select-all-checkbox'); if (selectAll) { selectAll.disabled = !!noResults; } } // Add this new function to update select-all checkbox states function updateSelectAllCheckboxStates() { // Check violations tab const violationsTabContent = document.querySelector('[data-tab-content="violations"]'); const violationsNoResults = violationsTabContent ? violationsTabContent.querySelector('.no-results-message:not(.hidden)') : null; const violationsSelectAll = document.getElementById('select-all-checkbox-violations'); if (violationsSelectAll) { violationsSelectAll.disabled = !!violationsNoResults; if (violationsNoResults) { violationsSelectAll.checked = false; } } // Check incomplete tab const incompleteTabContent = document.querySelector('[data-tab-content="incomplete"]'); const incompleteNoResults = incompleteTabContent ? incompleteTabContent.querySelector('.no-results-message:not(.hidden)') : null; const incompleteSelectAll = document.getElementById('select-all-checkbox-incomplete'); if (incompleteSelectAll) { incompleteSelectAll.disabled = !!incompleteNoResults; if (incompleteNoResults) { incompleteSelectAll.checked = false; } } } // Add this new function to update the bug report button badge function updateBugReportButtonBadge() { const bugBtn = document.getElementById('generateBugReportBtn'); if (!bugBtn) return; const selectedCheckboxes = document.querySelectorAll('.issue-checkbox:checked'); const count = selectedCheckboxes.length; // Remove existing badge if any const existingBadge = bugBtn.querySelector('.badge-count'); if (existingBadge) { existingBadge.remove(); } // Add new badge if there are selected items if (count > 0) { const badge = document.createElement('div'); badge.className = 'badge-count absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-bold'; badge.textContent = count > 99 ? '99+' : count; badge.style.fontSize = '10px'; badge.style.minWidth = '20px'; badge.style.height = '20px'; bugBtn.appendChild(badge); } } // Update the existing change event listener to include badge updates document.addEventListener('change', function () { const anyChecked = document.querySelectorAll('input[type="checkbox"]:checked').length > 0; const bugBtn = document.getElementById('generateBugReportBtn'); if (bugBtn) { bugBtn.disabled = !anyChecked; bugBtn.classList.toggle('bg-blue-600', anyChecked); bugBtn.classList.toggle('hover:bg-blue-700', anyChecked); bugBtn.classList.toggle('cursor-pointer', anyChecked); bugBtn.classList.toggle('bg-gray-300', !anyChecked); bugBtn.classList.toggle('cursor-not-allowed', !anyChecked); } // Update the badge count updateBugReportButtonBadge(); });