Skip to content

Commit 13240be

Browse files
committed
fix: global handling of anchor jumps
1 parent 1611f85 commit 13240be

File tree

2 files changed

+69
-69
lines changed

2 files changed

+69
-69
lines changed

ui/src/pages/Layout/index.tsx

+69-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
HttpErrorContent,
4040
} from '@/components';
4141
import { LoginToContinueModal, BadgeModal } from '@/components/Modal';
42-
import { changeTheme, Storage } from '@/utils';
42+
import { changeTheme, Storage, scrollToElementTop } from '@/utils';
4343
import { useQueryNotificationStatus } from '@/services';
4444
import { useExternalToast } from '@/hooks';
4545
import { EXTERNAL_CONTENT_DISPLAY_MODE } from '@/common/constants';
@@ -58,6 +58,74 @@ const Layout: FC = () => {
5858
const { show: showLoginToContinueModal } = loginToContinueStore();
5959
const { data: notificationData } = useQueryNotificationStatus();
6060

61+
useEffect(() => {
62+
// handle footnote links
63+
const fixFootnoteLinks = () => {
64+
const footnoteLinks = document.querySelectorAll(
65+
'a[href^="#"]:not([data-footnote-fixed])',
66+
);
67+
68+
footnoteLinks.forEach((link) => {
69+
link.setAttribute('data-footnote-fixed', 'true');
70+
const href = link.getAttribute('href');
71+
link.addEventListener('click', (e) => {
72+
e.preventDefault();
73+
const targetId = href?.substring(1) || '';
74+
const targetElement = document.getElementById(targetId);
75+
76+
if (targetElement) {
77+
window.history.pushState(null, '', `${location.pathname}${href}`);
78+
79+
scrollToElementTop(targetElement);
80+
}
81+
});
82+
});
83+
84+
if (window.location.hash) {
85+
const { hash } = window.location;
86+
const targetElement = document.getElementById(hash.substring(1));
87+
88+
if (targetElement) {
89+
setTimeout(() => {
90+
scrollToElementTop(targetElement);
91+
}, 100);
92+
}
93+
}
94+
};
95+
fixFootnoteLinks();
96+
97+
const observer = new MutationObserver(() => {
98+
fixFootnoteLinks();
99+
});
100+
101+
observer.observe(document.body, {
102+
childList: true,
103+
subtree: true,
104+
attributes: true,
105+
attributeFilter: ['id', 'href'],
106+
});
107+
108+
const handleHashChange = () => {
109+
if (window.location.hash) {
110+
const { hash } = window.location;
111+
const targetElement = document.getElementById(hash.substring(1));
112+
113+
if (targetElement) {
114+
setTimeout(() => {
115+
scrollToElementTop(targetElement);
116+
}, 100);
117+
}
118+
}
119+
};
120+
121+
window.addEventListener('hashchange', handleHashChange);
122+
123+
return () => {
124+
observer.disconnect();
125+
window.removeEventListener('hashchange', handleHashChange);
126+
};
127+
}, [location.pathname]);
128+
61129
useEffect(() => {
62130
httpStatusReset();
63131
}, [location]);

ui/src/pages/Questions/Detail/index.tsx

-68
Original file line numberDiff line numberDiff line change
@@ -242,74 +242,6 @@ const Index = () => {
242242
}
243243
}
244244

245-
useEffect(() => {
246-
// handle footnote links
247-
const fixFootnoteLinks = () => {
248-
const footnoteLinks = document.querySelectorAll(
249-
'a[href^="#"]:not([data-footnote-fixed])',
250-
);
251-
252-
footnoteLinks.forEach((link) => {
253-
link.setAttribute('data-footnote-fixed', 'true');
254-
const href = link.getAttribute('href');
255-
link.addEventListener('click', (e) => {
256-
e.preventDefault();
257-
const targetId = href?.substring(1) || '';
258-
const targetElement = document.getElementById(targetId);
259-
260-
if (targetElement) {
261-
window.history.pushState(null, '', `${location.pathname}${href}`);
262-
263-
scrollToElementTop(targetElement);
264-
}
265-
});
266-
});
267-
268-
if (window.location.hash) {
269-
const { hash } = window.location;
270-
const targetElement = document.getElementById(hash.substring(1));
271-
272-
if (targetElement) {
273-
setTimeout(() => {
274-
scrollToElementTop(targetElement);
275-
}, 100);
276-
}
277-
}
278-
};
279-
fixFootnoteLinks();
280-
281-
const observer = new MutationObserver(() => {
282-
fixFootnoteLinks();
283-
});
284-
285-
observer.observe(document.body, {
286-
childList: true,
287-
subtree: true,
288-
attributes: true,
289-
attributeFilter: ['id', 'href'],
290-
});
291-
292-
const handleHashChange = () => {
293-
if (window.location.hash) {
294-
const { hash } = window.location;
295-
const targetElement = document.getElementById(hash.substring(1));
296-
297-
if (targetElement) {
298-
setTimeout(() => {
299-
scrollToElementTop(targetElement);
300-
}, 100);
301-
}
302-
}
303-
};
304-
305-
window.addEventListener('hashchange', handleHashChange);
306-
307-
return () => {
308-
observer.disconnect();
309-
window.removeEventListener('hashchange', handleHashChange);
310-
};
311-
}, [location.pathname]);
312-
313245
return (
314246
<Row className="questionDetailPage pt-4 mb-5">
315247
<Col className="page-main flex-auto">

0 commit comments

Comments
 (0)