@@ -6,128 +6,130 @@ const p = new DOMParser()
66let activeAnchor : HTMLAnchorElement | null = null
77
88async function mouseEnterHandler (
9- this : HTMLAnchorElement ,
10- { clientX, clientY } : { clientX : number ; clientY : number } ,
9+ this : HTMLAnchorElement ,
10+ { clientX, clientY } : { clientX : number ; clientY : number } ,
1111) {
12- const link = ( activeAnchor = this )
13- if ( link . dataset . noPopover === "true" ) {
14- return
15- }
16-
17- async function setPosition ( popoverElement : HTMLElement ) {
18- const { x, y } = await computePosition ( link , popoverElement , {
19- strategy : "fixed" ,
20- middleware : [ inline ( { x : clientX , y : clientY } ) , shift ( ) , flip ( ) ] ,
21- } )
22- Object . assign ( popoverElement . style , {
23- transform : `translate(${ x . toFixed ( ) } px, ${ y . toFixed ( ) } px)` ,
24- } )
25- }
26-
27- function showPopover ( popoverElement : HTMLElement ) {
28- clearActivePopover ( )
29- popoverElement . classList . add ( "active-popover" )
30- setPosition ( popoverElement as HTMLElement )
31-
32- if ( hash !== "" ) {
33- const targetAnchor = `#popover-internal-${ hash . slice ( 1 ) } `
34- const heading = popoverInner . querySelector ( targetAnchor ) as HTMLElement | null
35- if ( heading ) {
36- // leave ~12px of buffer when scrolling to a heading
37- popoverInner . scroll ( { top : heading . offsetTop - 12 , behavior : "instant" } )
38- }
12+ const link = ( activeAnchor = this )
13+ if ( link . dataset . noPopover === "true" ) {
14+ return
15+ }
16+
17+ async function setPosition ( popoverElement : HTMLElement ) {
18+ const { x, y } = await computePosition ( link , popoverElement , {
19+ strategy : "fixed" ,
20+ middleware : [ inline ( { x : clientX , y : clientY } ) , shift ( ) , flip ( ) ] ,
21+ } )
22+ Object . assign ( popoverElement . style , {
23+ transform : `translate(${ x . toFixed ( ) } px, ${ y . toFixed ( ) } px)` ,
24+ } )
25+ }
26+
27+ function showPopover ( popoverElement : HTMLElement ) {
28+ clearActivePopover ( )
29+ popoverElement . classList . add ( "active-popover" )
30+ setPosition ( popoverElement as HTMLElement )
31+
32+ if ( hash !== "" ) {
33+ const targetAnchor = `#popover-internal-${ hash . slice ( 1 ) } `
34+ const heading = popoverInner . querySelector ( targetAnchor ) as HTMLElement | null
35+ if ( heading ) {
36+ // leave ~12px of buffer when scrolling to a heading
37+ popoverInner . scroll ( { top : heading . offsetTop - 12 , behavior : "instant" } )
38+ }
39+ }
40+ }
41+
42+ const targetUrl = new URL ( link . href )
43+ const hash = decodeURIComponent ( targetUrl . hash )
44+ targetUrl . hash = ""
45+ targetUrl . search = ""
46+ const popoverId = `popover-${ link . pathname } `
47+ const prevPopoverElement = document . getElementById ( popoverId )
48+
49+ // dont refetch if there's already a popover
50+ if ( ! ! document . getElementById ( popoverId ) ) {
51+ showPopover ( prevPopoverElement as HTMLElement )
52+ return
3953 }
40- }
41-
42- const targetUrl = new URL ( link . href )
43- const hash = decodeURIComponent ( targetUrl . hash )
44- targetUrl . hash = ""
45- targetUrl . search = ""
46- const popoverId = `popover-${ link . pathname } `
47- const prevPopoverElement = document . getElementById ( popoverId )
48-
49- // dont refetch if there's already a popover
50- if ( ! ! document . getElementById ( popoverId ) ) {
51- showPopover ( prevPopoverElement as HTMLElement )
52- return
53- }
54-
55- const response = await fetchCanonical ( targetUrl ) . catch ( ( err ) => {
56- console . error ( err )
57- } )
58-
59- if ( ! response ) return
60- const [ contentType ] = response . headers . get ( "Content-Type" ) ! . split ( ";" )
61- const [ contentTypeCategory , typeInfo ] = contentType . split ( "/" )
62-
63- const popoverElement = document . createElement ( "div" )
64- popoverElement . id = popoverId
65- popoverElement . classList . add ( "popover" )
66- const popoverInner = document . createElement ( "div" )
67- popoverInner . classList . add ( "popover-inner" )
68- popoverInner . dataset . contentType = contentType ?? undefined
69- popoverElement . appendChild ( popoverInner )
70-
71- switch ( contentTypeCategory ) {
72- case "image" :
73- const img = document . createElement ( "img" )
74- img . src = targetUrl . toString ( )
75- img . alt = targetUrl . pathname
76-
77- popoverInner . appendChild ( img )
78- break
79- case "application" :
80- switch ( typeInfo ) {
81- case "pdf" :
82- const pdf = document . createElement ( "iframe" )
83- pdf . src = targetUrl . toString ( )
84- popoverInner . appendChild ( pdf )
85- break
54+
55+ const response = await fetchCanonical ( targetUrl ) . catch ( ( err ) => {
56+ console . error ( err )
57+ } )
58+
59+ if ( ! response ) return
60+ const [ contentType ] = response . headers . get ( "Content-Type" ) ! . split ( ";" )
61+ const [ contentTypeCategory , typeInfo ] = contentType . split ( "/" )
62+
63+ const popoverElement = document . createElement ( "div" )
64+ popoverElement . id = popoverId
65+ popoverElement . classList . add ( "popover" )
66+ const popoverInner = document . createElement ( "div" )
67+ popoverInner . classList . add ( "popover-inner" )
68+ popoverInner . dataset . contentType = contentType ?? undefined
69+ popoverElement . appendChild ( popoverInner )
70+
71+ switch ( contentTypeCategory ) {
72+ case "image" :
73+ const img = document . createElement ( "img" )
74+ img . src = targetUrl . toString ( )
75+ img . alt = targetUrl . pathname
76+
77+ popoverInner . appendChild ( img )
78+ break
79+ case "application" :
80+ switch ( typeInfo ) {
81+ case "pdf" :
82+ const pdf = document . createElement ( "iframe" )
83+ pdf . src = targetUrl . toString ( )
84+ popoverInner . appendChild ( pdf )
85+ break
86+ default :
87+ break
88+ }
89+ break
8690 default :
87- break
88- }
89- break
90- default :
91- const contents = await response . text ( )
92- const html = p . parseFromString ( contents , "text/html" )
93- normalizeRelativeURLs ( html , targetUrl )
94- // prepend all IDs inside popovers to prevent duplicates
95- html . querySelectorAll ( "[id]" ) . forEach ( ( el ) => {
96- const targetID = `popover-internal-${ el . id } `
97- el . id = targetID
98- } )
99- const elts = [ ...html . getElementsByClassName ( "popover-hint" ) ]
100- if ( elts . length === 0 ) return
101-
102- elts . forEach ( ( elt ) => popoverInner . appendChild ( elt ) )
103- }
104-
105- if ( ! ! document . getElementById ( popoverId ) ) {
106- return
107- }
108-
109- document . body . appendChild ( popoverElement )
110- if ( activeAnchor !== this ) {
111- return
112- }
113-
114- showPopover ( popoverElement )
91+ const contents = await response . text ( )
92+ const html = p . parseFromString ( contents , "text/html" )
93+ normalizeRelativeURLs ( html , targetUrl )
94+ // prepend all IDs inside popovers to prevent duplicates
95+ html . querySelectorAll ( "[id]" ) . forEach ( ( el ) => {
96+ const targetID = `popover-internal-${ el . id } `
97+ el . id = targetID
98+ } )
99+ const elts = [ ...html . getElementsByClassName ( "popover-hint" ) ]
100+ if ( elts . length === 0 ) return
101+
102+ elts . forEach ( ( elt ) => popoverInner . appendChild ( elt ) )
103+ }
104+
105+ if ( ! ! document . getElementById ( popoverId ) ) {
106+ return
107+ }
108+
109+ document . body . appendChild ( popoverElement )
110+ if ( activeAnchor !== this ) {
111+ return
112+ }
113+
114+ showPopover ( popoverElement )
115115}
116116
117117function clearActivePopover ( ) {
118- activeAnchor = null
119- const allPopoverElements = document . querySelectorAll ( ".popover" )
120- allPopoverElements . forEach ( ( popoverElement ) => popoverElement . classList . remove ( "active-popover" ) )
118+ activeAnchor = null
119+ const allPopoverElements = document . querySelectorAll ( ".popover" )
120+ allPopoverElements . forEach ( ( popoverElement ) => popoverElement . classList . remove ( "active-popover" ) )
121121}
122122
123123document . addEventListener ( "nav" , ( ) => {
124- const links = [ ...document . querySelectorAll ( "a.internal" ) ] as HTMLAnchorElement [ ]
125- for ( const link of links ) {
126- link . addEventListener ( "mouseenter" , mouseEnterHandler )
127- link . addEventListener ( "mouseleave" , clearActivePopover )
128- window . addCleanup ( ( ) => {
129- link . removeEventListener ( "mouseenter" , mouseEnterHandler )
130- link . removeEventListener ( "mouseleave" , clearActivePopover )
131- } )
132- }
124+ const links = [ ...document . querySelectorAll ( "a.internal" ) ] as HTMLAnchorElement [ ]
125+ for ( const link of links ) {
126+ link . addEventListener ( "mouseenter" , mouseEnterHandler )
127+ link . addEventListener ( "mouseleave" , clearActivePopover )
128+ window . addCleanup ( ( ) => {
129+ link . removeEventListener ( "mouseenter" , mouseEnterHandler )
130+ link . removeEventListener ( "mouseleave" , clearActivePopover )
131+ } )
132+ }
133133} )
134+
135+ export { mouseEnterHandler , clearActivePopover }
0 commit comments