1
- function initHighlightHeadline ( ) {
1
+ import * as mq from './mediaqueries' ;
2
+
3
+ function isAsideActive ( ) {
4
+ return window . matchMedia ( mq . minLG ) . matches ;
5
+ }
2
6
3
- // In this site's layout, the table of contents (.content_with_heading) is an element that appears before any other content at the same hierarchy level
4
- const headings = Array . from ( document . querySelectorAll ( '.content_with_heading :is(h1, h2, h3, h4)' ) ) ;
5
- const asideMobileCurrentHeadline = document . getElementById ( 'aside_mobile_current_headline' ) ;
6
- const windowPath = window . location . pathname ;
7
- if ( headings . length === 0 ) {
8
- return ; // No headings? No business here
9
- }
7
+ function initHighlightHeadline ( ) {
10
8
11
- // A few helper functions (.toc is the top-level ordered list)
12
- const markTocItemActive = ( a ) => { return a . setAttribute ( 'data-current' , '' ) ; }
13
- const markTocItemInactive = ( a ) => { return a . removeAttribute ( 'data-current' ) ; } ;
14
- const getTocLinkFromHeading = ( h ) => { return document . querySelector ( `.toc a[href="${ windowPath } #${ encodeURIComponent ( h . id ) . replace ( / % \w \w / g, match => match . toLowerCase ( ) ) } "]` ) ; }
9
+ // In this site's layout, the table of contents (.content_with_heading) is an element that appears before any other content at the same hierarchy level
10
+ const headings = Array . from ( document . querySelectorAll ( '.content_with_heading :is(h1, h2, h3, h4)' ) ) ;
11
+ const windowPath = window . location . pathname ;
12
+ if ( headings . length === 0 ) {
13
+ return ; // No headings? No business here
14
+ }
15
15
16
- const getDocHeight = ( ) => Math . floor ( document . body . clientHeight ) ;
16
+ // A few helper functions (.toc is the top-level ordered list)
17
+ const markTocItemActive = ( a ) => { return a . setAttribute ( 'data-current' , '' ) ; }
18
+ const markTocItemInactive = ( a ) => { return a . removeAttribute ( 'data-current' ) ; } ;
19
+ const getTocLinkFromHeading = ( h ) => { return document . querySelector ( `.toc a[href="${ windowPath } #${ encodeURIComponent ( h . id ) . replace ( / % \w \w / g, match => match . toLowerCase ( ) ) } "]` ) ; }
17
20
18
- const visibleHeadings = new Set ( ) ;
19
- let resizeDebounce ;
20
- let currentObserver ;
21
- let height = getDocHeight ( ) ;
21
+ const getDocHeight = ( ) => Math . floor ( document . body . clientHeight ) ;
22
22
23
- function beginObservation ( docHeight ) {
24
- const observer = new IntersectionObserver (
25
- ( entries ) => {
26
- entries . forEach ( ( entry ) => {
27
- // Keep track of visible headings
28
- if ( entry . isIntersecting ) {
29
- visibleHeadings . add ( entry . target ) ;
30
- } else {
31
- visibleHeadings . delete ( entry . target ) ;
32
- }
33
- } ) ;
23
+ const visibleHeadings = new Set ( ) ;
24
+ let resizeDebounce ;
25
+ let currentObserver ;
26
+ let height = getDocHeight ( ) ;
34
27
35
- // Sort visible (intersecting) headings by inverted order of appearance, then grab the first item (i.e. last visible heading)
36
- const lastVisible = Array . from ( visibleHeadings . values ( ) ) . sort ( ( a , b ) => headings . indexOf ( b ) - headings . indexOf ( a ) ) [ 0 ] ;
37
- if ( ! lastVisible ) {
38
- return ; // If nothing is visible, weird — TOC are opt-in — but let's skip this logic
28
+ function beginObservation ( docHeight ) {
29
+ const observer = new IntersectionObserver (
30
+ ( entries ) => {
31
+ if ( ! isAsideActive ( ) ) {
32
+ return ; // Exit if .o-aside is not active
39
33
}
40
34
41
- headings . forEach ( ( heading ) => {
35
+ entries . forEach ( ( entry ) => {
36
+ // Keep track of visible headings
37
+ if ( entry . isIntersecting ) {
38
+ visibleHeadings . add ( entry . target ) ;
39
+ } else {
40
+ visibleHeadings . delete ( entry . target ) ;
41
+ }
42
+ } ) ;
42
43
43
- // If it's the last visible item, mark it to make it stand out, else, revert to the default style
44
- // Find the link in the TOC list matching the heading in this list of hheding elements
45
- const tocLink = getTocLinkFromHeading ( heading ) ;
46
- if ( heading === lastVisible ) {
47
- asideMobileCurrentHeadline . textContent = heading . textContent ;
48
- if ( tocLink ) {
49
- markTocItemActive ( tocLink ) ;
50
- }
51
- } else {
52
- if ( tocLink ) {
53
- markTocItemInactive ( tocLink ) ;
54
- }
55
- }
56
- } ) ;
57
- } ,
58
- {
59
- //? docHeight: Extend the detection above the heading so it's always considered as intersecting if above the scrollport
60
- //? -33%: The element won't be considered as intersecting until it has gone _above_ the bottom third of the scrollport
61
- rootMargin : `${ docHeight } px 0px -80% 0px` ,
62
- threshold : 1 , // Only considered intersecting if all the pixels are inside the intersection area
63
- }
64
- ) ;
44
+ // Sort visible (intersecting) headings by inverted order of appearance, then grab the first item (i.e. last visible heading)
45
+ const lastVisible = Array . from ( visibleHeadings . values ( ) ) . sort ( ( a , b ) => headings . indexOf ( b ) - headings . indexOf ( a ) ) [ 0 ] ;
46
+ if ( ! lastVisible ) {
47
+ return ; // If nothing is visible, weird — TOC are opt-in — but let's skip this logic
48
+ }
65
49
66
- headings . forEach ( ( heading ) => observer . observe ( heading ) ) ;
67
-
68
- return observer ;
69
- }
50
+ headings . forEach ( ( heading ) => {
70
51
71
- // On page load...
52
+ // If it's the last visible item, mark it to make it stand out, else, revert to the default style
53
+ // Find the link in the TOC list matching the heading in this list of heading elements
54
+ const tocLink = getTocLinkFromHeading ( heading ) ;
55
+ if ( heading === lastVisible ) {
56
+ if ( tocLink ) {
57
+ markTocItemActive ( tocLink ) ;
58
+ }
59
+ } else {
60
+ if ( tocLink ) {
61
+ markTocItemInactive ( tocLink ) ;
62
+ }
63
+ }
64
+ } ) ;
65
+ } ,
66
+ {
67
+ //? docHeight: Extend the detection above the heading so it's always considered as intersecting if above the scrollport
68
+ //? -33%: The element won't be considered as intersecting until it has gone _above_ the bottom third of the scrollport
69
+ rootMargin : `${ docHeight } px 0px -80% 0px` ,
70
+ threshold : 1 , // Only considered intersecting if all the pixels are inside the intersection area
71
+ }
72
+ ) ;
73
+
74
+ headings . forEach ( ( heading ) => observer . observe ( heading ) ) ;
75
+
76
+ return observer ;
77
+ }
78
+
79
+ // On page load...
72
80
// Let us don't do this
73
81
/*
74
82
markTocItemActive(getTocLinkFromHeading(headings[0])); // Mark the first item as active (even if the heading appears a bit further down)
75
83
*/
76
- currentObserver = beginObservation ( height ) ; // Start the intersection observer
84
+ currentObserver = beginObservation ( height ) ; // Start the intersection observer
77
85
78
- // On resize, replace the observer with a new one matching the updated body height, if different
79
- window . addEventListener ( 'resize' , ( ) => {
80
- clearTimeout ( resizeDebounce ) ;
81
- resizeDebounce = setTimeout ( ( ) => {
82
- const heightAfterResize = getDocHeight ( ) ;
83
- if ( height !== heightAfterResize ) {
84
- if ( currentObserver ) {
85
- currentObserver . disconnect ( ) ;
86
- }
87
- currentObserver = beginObservation ( heightAfterResize ) ;
88
- }
89
- } , 200 ) ;
90
- } ) ;
86
+ // On resize, replace the observer with a new one matching the updated body height, if different
87
+ window . addEventListener ( 'resize' , ( ) => {
88
+ clearTimeout ( resizeDebounce ) ;
89
+ resizeDebounce = setTimeout ( ( ) => {
90
+ const heightAfterResize = getDocHeight ( ) ;
91
+ if ( height !== heightAfterResize ) {
92
+ if ( currentObserver ) {
93
+ currentObserver . disconnect ( ) ;
94
+ }
95
+ currentObserver = beginObservation ( heightAfterResize ) ;
96
+ }
97
+ } , 200 ) ;
98
+ } ) ;
91
99
}
92
100
93
101
if ( document . readyState === "interactive" ) {
94
- if ( document . getElementById ( 'aside' ) ) {
95
- initHighlightHeadline ( ) ;
96
- }
102
+ if ( document . getElementById ( 'aside' ) ) {
103
+ initHighlightHeadline ( ) ;
104
+ }
97
105
} else {
98
- window . addEventListener ( "DOMContentLoaded" , ( ) => {
99
- if ( document . getElementById ( 'aside' ) ) {
100
- initHighlightHeadline ( ) ;
101
- }
102
- } ) ;
106
+ window . addEventListener ( "DOMContentLoaded" , ( ) => {
107
+ if ( document . getElementById ( 'aside' ) ) {
108
+ initHighlightHeadline ( ) ;
109
+ }
110
+ } ) ;
103
111
}
0 commit comments