Skip to content

Commit ae49b46

Browse files
committed
No need to wait for window.location.hash to update
1 parent b5c3dc4 commit ae49b46

File tree

1 file changed

+31
-25
lines changed

1 file changed

+31
-25
lines changed

src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,46 +1020,52 @@ function setupArticleTocSyncing() {
10201020
// highlight.
10211021
let disableObserver = false;
10221022

1023+
function temporarilyDisableObserver(time) {
1024+
disableObserver = true;
1025+
setTimeout(() => {
1026+
disableObserver = false;
1027+
}, time);
1028+
}
1029+
10231030
/**
1024-
* Check the hash portion of the page URL. If it matches an entry in the page
1025-
* table of contents, highlight that entry and temporarily disable the
1026-
* intersection observer while the page scrolls to the corresponding heading.
1031+
* If the provided URL hash fragment (beginning with "#") matches an entry in
1032+
* the page table of contents, highlight that entry and temporarily disable
1033+
* the intersection observer while the page scrolls to the corresponding
1034+
* heading.
10271035
*/
1028-
function syncTocHash() {
1029-
const { hash: pageHash } = window.location;
1030-
if (pageHash.length > 1) {
1031-
const matchingTocLink = tocLinks.find((link) => link.hash === pageHash);
1036+
function syncTocHash(hash) {
1037+
if (hash.length > 1) {
1038+
const matchingTocLink = tocLinks.find((tocLink) => tocLink.hash === hash);
10321039
if (matchingTocLink) {
1033-
disableObserver = true;
1034-
setTimeout(() => {
1035-
// Give the page ample time to finish scrolling, then re-enable the
1036-
// intersection observer.
1037-
disableObserver = false;
1038-
}, 1000);
1040+
// It's important to disable the intersection observer before
1041+
// highlighting the TOC link and its corresponding article heading. This
1042+
// is because the browser takes a little time to scroll to the article
1043+
// heading, and while scrolling, it could trigger intersection events
1044+
// that cause some other link in the table of contents to be
1045+
// highlighted.
1046+
temporarilyDisableObserver(1000);
10391047
activate(matchingTocLink);
10401048
}
10411049
}
10421050
}
10431051

10441052
// When the page loads and when the user clicks an in-page link,
10451053
// sync the page's table of contents.
1046-
syncTocHash();
1047-
// Note we cannot use the "hashchange" event because if the user clicks a hash
1048-
// link, scrolls away, then clicks the same hash link again, it will not fire
1049-
// the change event (because it's the same hash), but we still want to re-sync
1050-
// the table of contents.
1054+
syncTocHash(window.location.hash);
1055+
1056+
// Listen for link clicks to sync the table of contents. Note we cannot use
1057+
// the "hashchange" event because if the user clicks a hash link, then scrolls
1058+
// away and clicks the same hash link again, it will not fire the change event
1059+
// (because it's the same hash), but we still want to re-sync the table of
1060+
// contents.
10511061
window.addEventListener("click", (event) => {
10521062
// Match any link because an in-page ("hash link") can occur anywhere on the
10531063
// page, not just in the side table of contents (e.g., one section of the
10541064
// page linking to another section of the page, also each of the headings
10551065
// contains a link to itself).
1056-
if (event.target.closest("a")) {
1057-
// Defer the sync operation because window.location.hash does not change
1058-
// until after the default action for the event has happened (i.e., the
1059-
// link click).
1060-
setTimeout(() => {
1061-
syncTocHash();
1062-
}, 0);
1066+
const link = event.target.closest("a");
1067+
if (link && link.hash) {
1068+
syncTocHash(link.hash);
10631069
}
10641070
});
10651071

0 commit comments

Comments
 (0)