| const queryArg = "section"; |
|
|
| function syncHFSpacesURLHash() { |
| |
| const hasExplicitRequest = handleExplicitSectionRequest(); |
| |
| |
| updateHashBasedOnHashChange(); |
| |
| |
| setupScrollMonitoring(); |
| |
| |
| |
| } |
|
|
| function handleExplicitSectionRequest() { |
| |
| const urlParams = new URLSearchParams(window.location.search); |
| const sectionId = urlParams.get(queryArg); |
| |
| |
| if (sectionId) { |
| const targetElement = document.getElementById(sectionId); |
| if (targetElement) { |
| |
| setTimeout(() => { |
| targetElement.scrollIntoView(); |
| history.replaceState(null, null, `#${sectionId}`); |
| }, 100); |
| } |
| return true; |
| } |
| |
| |
| return false; |
| } |
|
|
| function setupScrollMonitoring() { |
| |
| let isScrolling = false; |
| let lastKnownScrollPosition = 0; |
| let initialScroll = true; |
| |
| |
| window.addEventListener('scroll', function() { |
| lastKnownScrollPosition = window.scrollY; |
| |
| if (!isScrolling) { |
| window.requestAnimationFrame(function() { |
| |
| |
| if (initialScroll) { |
| initialScroll = false; |
| } else { |
| updateHashBasedOnScroll(lastKnownScrollPosition); |
| } |
| isScrolling = false; |
| }); |
| } |
| |
| isScrolling = true; |
| }); |
| } |
|
|
| |
| function updateHashBasedOnScroll(scrollPosition) { |
| const closestHeading = findClosestHeading(scrollPosition); |
| |
| |
| if (closestHeading && closestHeading.id) { |
| |
| if (window.location.hash !== `#${closestHeading.id}`) { |
| silentlyUpdateHash(closestHeading.id); |
| postMessageToHFSpaces(closestHeading.id); |
| } |
| } |
| } |
|
|
| |
| function findClosestHeading(scrollPosition) { |
| |
| const headingsWithIds = Array.from(document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]')); |
|
|
| |
| if (headingsWithIds.length === 0) return null; |
|
|
| |
| let closestHeading = null; |
| let closestDistance = Infinity; |
| const viewportMiddle = scrollPosition + window.innerHeight / 2; |
| |
| |
| headingsWithIds.forEach(heading => { |
| const headingTop = heading.getBoundingClientRect().top + scrollPosition; |
| const distance = Math.abs(headingTop - viewportMiddle); |
| |
| if (distance < closestDistance) { |
| closestDistance = distance; |
| closestHeading = heading; |
| } |
| }); |
| |
| return closestHeading; |
| } |
|
|
| |
| function silentlyUpdateHash(id) { |
| history.replaceState(null, null, `#${id}`); |
| } |
|
|
| function updateHashBasedOnHashChange() { |
| window.addEventListener('hashchange', () => { |
| const elementId = window.location.hash.slice(1); |
| postMessageToHFSpaces(elementId); |
| }); |
| } |
|
|
| function postMessageToHFSpaces(elementId) { |
| const parentOrigin = "https://huggingface.co"; |
| window.parent.postMessage({ queryString: `${queryArg}=${elementId}` }, parentOrigin); |
| } |
|
|
| export { syncHFSpacesURLHash }; |
|
|