Indeed, now that I actually examine the code the AI made in highlightHeaderInView
what itâs doing is checking the distance of headers from the top edge of the page downward. So, once you scroll down enough for a header to cross the top edge and go out of view, the next header below is detected as the new closest one.
The logic is then actually the reverse of what it should be. It should be checking whether the header has gone above the top edge.
I asked Github copilot to fix the code again.
Updated highlightHeaderInView
script
- The new code didnât change much, just flipped the
distance
check for for negative distance (which is then distance above the page top edge.
- An exception is made when no header is above the top edge, which would be the case right in the beginning before youâve scrolled down enough. In that case the first header is considered active.
- I guessed that this would make it so that the last header can never never active, if you canât scroll down enough to make it go out of view. It seems Wikipediaâs sidebard has this flaw and they didnât bother fixing it. Though it should be fixable, just check whether the scroll position is the very bottom.
- Not sure if
window.innerHeight + window.scrollY >= document.body.offsetHeight - 10
will work in the Anki reviewer.
- I checked that Wikipedia makes the header active a bit before it crosses the top edge. So the
distance
check should actually allow the header to close to or past to the top edge to be considered active.
First prompt I used
The code in highlightHeaderInView is not highlighting the header in the desired way. Currently, the highlighted header is the closest one below the viewport top edge. Instead, the highlighted header should be the one that
- has crossed (and is above) the viewport top and is out of view
- or in the case where no header has yet been scrolled past, the active header is the first one.
Fix the code in highlightHeaderInView to implement this correct functionality.
Second prompt
In the updated code, the last header can never be active because you likely canât scroll down enough to make it go past the viewport top. What would be the options to fix this?
Third prompt
Make it so that the header doesnât need to all the way past the viewport top but is considered active once itâs close to it, say, 10% of the viewport height below the viewport top or higher.
<script>
// Function to highlight the header in view on the sidebar
function highlightHeaderInView() {
// Select all header elements in the content container
const headers = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
// Select all links in the sidebar list
const sidebarLinks = document.querySelectorAll("#sidebar-list a");
// Initialize variables to keep track of the closest header and its distance from the top
let closestHeader = null;
let closestHeaderDistance = -Infinity; // Tracking the largest negative distance
// Calculate 10% of the viewport height
const viewportHeightThreshold = window.innerHeight * 0.1;
// Loop through each header to find the one closest to the top of the viewport, from above
headers.forEach(header => {
const distance = header.getBoundingClientRect().top;
// Update to find the header with the smallest distance less than the threshold
if (distance < viewportHeightThreshold && distance > closestHeaderDistance) {
closestHeader = header;
closestHeaderDistance = distance;
}
});
// If no header has been scrolled past, select the first one
if (!closestHeader && headers.length > 0) {
closestHeader = headers[0];
}
// If a closest header is found, proceed to highlight the corresponding sidebar link
if (closestHeader) {
// Loop through each link in the sidebar
sidebarLinks.forEach(link => {
// Get the parent <li> element of the link
const listItem = link.parentElement;
// Check if the link's href matches the id of the closest header
if (link.getAttribute("href") === "#" + closestHeader.id) {
// If it matches, add the 'active-header' class to highlight it
listItem.classList.add("active-header");
} else {
// If it doesn't match, remove the 'active-header' class
listItem.classList.remove("active-header");
}
});
}
}
// Attach the scroll event listener, prevent adding it multiple times on desktop
var addEventListenerAdded;
if (!addEventListenerAdded) {
window.addEventListener("scroll", highlightHeaderInView);
addEventListenerAdded = true;
}
// Also highlight the header once on initially rendering the card
highlightHeaderInView();
</script>