Phase 1: Remove obsolete files and standardize all pages
- Standardize script loading on faq, privacy, returns, shipping-info pages - Archive 14 unused JS files (cart-functions, shopping, cart.js, enhanced versions, etc.) - Archive 2 unused CSS files (responsive-enhanced, responsive-fixes) - All pages now use consistent script loading order - Eliminated shopping.js dependency (not needed after standardization)
This commit is contained in:
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* Accessibility Enhancements
|
||||
* WCAG 2.1 AA Compliance Utilities
|
||||
*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
class AccessibilityManager {
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.addSkipLinks();
|
||||
this.enhanceFocusManagement();
|
||||
this.addARIALabels();
|
||||
this.setupKeyboardNavigation();
|
||||
this.announceChanges();
|
||||
}
|
||||
|
||||
// Add skip link to main content
|
||||
addSkipLinks() {
|
||||
if (document.querySelector(".skip-link")) return;
|
||||
|
||||
const skipLink = document.createElement("a");
|
||||
skipLink.href = "#main-content";
|
||||
skipLink.className = "skip-link";
|
||||
skipLink.textContent = "Skip to main content";
|
||||
skipLink.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
const main =
|
||||
document.getElementById("main-content") ||
|
||||
document.querySelector("main");
|
||||
if (main) {
|
||||
main.setAttribute("tabindex", "-1");
|
||||
main.focus();
|
||||
main.removeAttribute("tabindex");
|
||||
}
|
||||
});
|
||||
document.body.insertBefore(skipLink, document.body.firstChild);
|
||||
}
|
||||
|
||||
// Enhance focus management
|
||||
enhanceFocusManagement() {
|
||||
// Track focus for modal/dropdown management
|
||||
let lastFocusedElement = null;
|
||||
|
||||
document.addEventListener("focusin", (e) => {
|
||||
const dropdown = e.target.closest(
|
||||
'[role="dialog"], .cart-dropdown, .wishlist-dropdown'
|
||||
);
|
||||
if (dropdown && dropdown.classList.contains("active")) {
|
||||
if (!lastFocusedElement) {
|
||||
lastFocusedElement = document.activeElement;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Return focus when dropdowns close
|
||||
const observeDropdowns = () => {
|
||||
const dropdowns = document.querySelectorAll(
|
||||
".cart-dropdown, .wishlist-dropdown"
|
||||
);
|
||||
dropdowns.forEach((dropdown) => {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.attributeName === "class") {
|
||||
if (
|
||||
!dropdown.classList.contains("active") &&
|
||||
lastFocusedElement
|
||||
) {
|
||||
lastFocusedElement.focus();
|
||||
lastFocusedElement = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe(dropdown, { attributes: true });
|
||||
});
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", observeDropdowns);
|
||||
} else {
|
||||
observeDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
// Add missing ARIA labels
|
||||
addARIALabels() {
|
||||
// Add labels to buttons without text
|
||||
document
|
||||
.querySelectorAll("button:not([aria-label]):not([aria-labelledby])")
|
||||
.forEach((button) => {
|
||||
if (button.textContent.trim() === "") {
|
||||
const icon = button.querySelector('i[class*="bi-"]');
|
||||
if (icon) {
|
||||
const iconClass = Array.from(icon.classList).find((c) =>
|
||||
c.startsWith("bi-")
|
||||
);
|
||||
if (iconClass) {
|
||||
const label = iconClass.replace("bi-", "").replace(/-/g, " ");
|
||||
button.setAttribute("aria-label", label);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure all images have alt text
|
||||
document.querySelectorAll("img:not([alt])").forEach((img) => {
|
||||
img.setAttribute("alt", "");
|
||||
});
|
||||
|
||||
// Add role to navigation landmarks
|
||||
document.querySelectorAll(".navbar, .modern-navbar").forEach((nav) => {
|
||||
if (!nav.getAttribute("role")) {
|
||||
nav.setAttribute("role", "navigation");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Setup keyboard navigation
|
||||
setupKeyboardNavigation() {
|
||||
// Escape key closes dropdowns
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
const activeDropdown = document.querySelector(
|
||||
".cart-dropdown.active, .wishlist-dropdown.active"
|
||||
);
|
||||
if (activeDropdown) {
|
||||
const closeBtn = activeDropdown.querySelector(
|
||||
".close-btn, [data-close]"
|
||||
);
|
||||
if (closeBtn) closeBtn.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Tab trap in modal/dropdowns
|
||||
document
|
||||
.querySelectorAll(".cart-dropdown, .wishlist-dropdown")
|
||||
.forEach((dropdown) => {
|
||||
dropdown.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Tab" && dropdown.classList.contains("active")) {
|
||||
const focusableElements = dropdown.querySelectorAll(
|
||||
'a[href], button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
||||
);
|
||||
const firstElement = focusableElements[0];
|
||||
const lastElement =
|
||||
focusableElements[focusableElements.length - 1];
|
||||
|
||||
if (e.shiftKey && document.activeElement === firstElement) {
|
||||
e.preventDefault();
|
||||
lastElement.focus();
|
||||
} else if (
|
||||
!e.shiftKey &&
|
||||
document.activeElement === lastElement
|
||||
) {
|
||||
e.preventDefault();
|
||||
firstElement.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Announce dynamic changes to screen readers
|
||||
announceChanges() {
|
||||
// Create live region if it doesn't exist
|
||||
let liveRegion = document.getElementById("aria-live-region");
|
||||
if (!liveRegion) {
|
||||
liveRegion = document.createElement("div");
|
||||
liveRegion.id = "aria-live-region";
|
||||
liveRegion.setAttribute("role", "status");
|
||||
liveRegion.setAttribute("aria-live", "polite");
|
||||
liveRegion.setAttribute("aria-atomic", "true");
|
||||
liveRegion.className = "sr-only";
|
||||
document.body.appendChild(liveRegion);
|
||||
}
|
||||
|
||||
// Listen for cart/wishlist updates
|
||||
window.addEventListener("cart-updated", () => {
|
||||
const count = window.AppState?.getCartCount?.() || 0;
|
||||
this.announce(
|
||||
`Cart updated. ${count} item${count !== 1 ? "s" : ""} in cart.`
|
||||
);
|
||||
});
|
||||
|
||||
window.addEventListener("wishlist-updated", () => {
|
||||
const count = window.AppState?.wishlist?.length || 0;
|
||||
this.announce(
|
||||
`Wishlist updated. ${count} item${
|
||||
count !== 1 ? "s" : ""
|
||||
} in wishlist.`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Announce message to screen readers
|
||||
announce(message) {
|
||||
const liveRegion = document.getElementById("aria-live-region");
|
||||
if (liveRegion) {
|
||||
liveRegion.textContent = "";
|
||||
setTimeout(() => {
|
||||
liveRegion.textContent = message;
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize accessibility manager
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
window.A11y = new AccessibilityManager();
|
||||
});
|
||||
} else {
|
||||
window.A11y = new AccessibilityManager();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user