|
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 }; |
|
|