@@ -1020,46 +1020,52 @@ function setupArticleTocSyncing() {
1020
1020
// highlight.
1021
1021
let disableObserver = false ;
1022
1022
1023
+ function temporarilyDisableObserver ( time ) {
1024
+ disableObserver = true ;
1025
+ setTimeout ( ( ) => {
1026
+ disableObserver = false ;
1027
+ } , time ) ;
1028
+ }
1029
+
1023
1030
/**
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.
1027
1035
*/
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 ) ;
1032
1039
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 ) ;
1039
1047
activate ( matchingTocLink ) ;
1040
1048
}
1041
1049
}
1042
1050
}
1043
1051
1044
1052
// When the page loads and when the user clicks an in-page link,
1045
1053
// 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.
1051
1061
window . addEventListener ( "click" , ( event ) => {
1052
1062
// Match any link because an in-page ("hash link") can occur anywhere on the
1053
1063
// page, not just in the side table of contents (e.g., one section of the
1054
1064
// page linking to another section of the page, also each of the headings
1055
1065
// 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 ) ;
1063
1069
}
1064
1070
} ) ;
1065
1071
0 commit comments