// custom popups that appear on hover that uses the alt/aria-label attribute on elements // replacement for using title without the issue it causes with screen readers and such document.addEventListener("DOMContentLoaded", function () { let popup = document.getElementById("alt-popup"); // add popup to all elements with alt or aria-label function initializePopups() { // find all elements with alt or aria-label const elementsWithAlt = document.querySelectorAll("[alt], [aria-label]"); // add mouse events to each element elementsWithAlt.forEach((element) => { element.addEventListener("mousemove", showPopup); element.addEventListener("mouseout", hidePopup); }); } // show popup and position it near the cursor function showPopup(event) { // get alt text or aria-label const altText = event.target.getAttribute("alt"); const ariaLabel = event.target.getAttribute("aria-label"); // Use alt text if available, otherwise use aria-label const displayText = altText || ariaLabel; if (displayText) { // use text in popup popup.textContent = displayText; // Make the popup visible but with position:fixed and visibility:hidden // so we can measure its dimensions without it being visible yet popup.style.opacity = "0"; popup.style.visibility = "visible"; popup.style.position = "fixed"; // Changed from absolute to fixed // Get viewport dimensions const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; // Get popup dimensions const popupWidth = popup.offsetWidth; const popupHeight = popup.offsetHeight; // Use clientX/clientY which are relative to the viewport (for fixed positioning) let leftPos = event.clientX + 20; let topPos = event.clientY + 20; // Check if popup would extend beyond right edge of viewport if (leftPos + popupWidth > viewportWidth) { // Flip to left side of cursor leftPos = event.clientX - popupWidth - 10; } // Check if popup would extend beyond bottom edge of viewport if (topPos + popupHeight > viewportHeight) { // Flip to above cursor topPos = event.clientY - popupHeight - 10; } // Additional check if flipping to left puts it offscreen if (leftPos < 0) { leftPos = 10; } // Additional check if flipping to top puts it offscreen if (topPos < 0) { topPos = 10; } // Set the final position and make it visible popup.style.left = leftPos + "px"; popup.style.top = topPos + "px"; popup.style.opacity = "1"; popup.style.visibility = "visible"; } } function hidePopup() { popup.style.opacity = "0"; popup.style.visibility = "hidden"; } initializePopups(); if (window.MutationObserver) { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length) { initializePopups(); } }); }); // Only set up the observer once if (document.body) { observer.observe(document.body, { childList: true, subtree: true }); } } });