@@ -218,31 +218,40 @@ function initRepoDiffShowMore() {
218218 } ) ;
219219}
220220
221- async function loadUntilFound ( ) {
221+ async function onLocationHashChange ( ) {
222+ // try to scroll to the target element by the current hash
222223 const currentHash = window . location . hash ;
223- if ( ! currentHash . startsWith ( '#diff-' ) && ! currentHash . startsWith ( '#issuecomment-' ) ) {
224- return ;
225- }
224+ if ( ! currentHash . startsWith ( '#diff-' ) && ! currentHash . startsWith ( '#issuecomment-' ) ) return ;
225+
226+ // avoid reentrance when we are changing the hash to scroll and trigger ":target" selection
227+ const attrAutoScrollRunning = 'data-auto-scroll-running' ;
228+ if ( document . body . hasAttribute ( attrAutoScrollRunning ) ) return ;
226229
227- while ( window . location . hash === currentHash ) {
230+ const targetElementId = currentHash . substring ( 1 ) ;
231+ while ( currentHash === window . location . hash ) {
228232 // use getElementById to avoid querySelector throws an error when the hash is invalid
229233 // eslint-disable-next-line unicorn/prefer-query-selector
230- const targetElement = document . getElementById ( currentHash . substring ( 1 ) ) ;
234+ const targetElement = document . getElementById ( targetElementId ) ;
231235 if ( targetElement ) {
232- // re-trigger :target CSS and browser will scroll to the element
236+ // need to change hash to re-trigger ":target" CSS selector, let's manually scroll to it
237+ targetElement . scrollIntoView ( ) ;
238+ document . body . setAttribute ( attrAutoScrollRunning , 'true' ) ;
233239 window . location . hash = '' ;
234- setTimeout ( ( ) => { window . location . hash = currentHash } , 0 ) ;
240+ window . location . hash = currentHash ;
241+ setTimeout ( ( ) => document . body . removeAttribute ( attrAutoScrollRunning ) , 0 ) ;
235242 return ;
236243 }
237244
238245 // If looking for a hidden comment, try to expand the section that contains it
239- if ( currentHash . startsWith ( '#issuecomment-' ) ) {
240- const commentId = currentHash . substring ( '#issuecomment-' . length ) ;
246+ const issueCommentPrefix = '#issuecomment-' ;
247+ if ( currentHash . startsWith ( issueCommentPrefix ) ) {
248+ const commentId = currentHash . substring ( issueCommentPrefix . length ) ;
241249 const expandButton = findExpandButtonForComment ( commentId ) ;
242250 if ( expandButton ) {
243- // Avoid infinite loop, do not re-click the button if already clicked
244- if ( expandButton . hasAttribute ( 'data-auto-load-clicked' ) ) return ;
245- expandButton . setAttribute ( 'data-auto-load-clicked' , 'true' ) ;
251+ // avoid infinite loop, do not re-click the button if already clicked
252+ const attrAutoLoadClicked = 'data-auto-load-clicked' ;
253+ if ( expandButton . hasAttribute ( attrAutoLoadClicked ) ) return ;
254+ expandButton . setAttribute ( attrAutoLoadClicked , 'true' ) ;
246255 expandButton . click ( ) ;
247256 await sleep ( 500 ) ; // Wait for HTMX to load the content. FIXME: need to drop htmx in the future
248257 continue ; // Try again to find the element
@@ -276,8 +285,8 @@ function findExpandButtonForComment(commentId: string): HTMLElement | null {
276285}
277286
278287function initRepoDiffHashChangeListener ( ) {
279- window . addEventListener ( 'hashchange' , loadUntilFound ) ;
280- loadUntilFound ( ) ;
288+ window . addEventListener ( 'hashchange' , onLocationHashChange ) ;
289+ onLocationHashChange ( ) ;
281290}
282291
283292export function initRepoDiffView ( ) {
0 commit comments