diff --git a/src/_layouts/kurzbericht.11ty.js b/src/_layouts/kurzbericht.11ty.js index ea28bf05c..dc798763a 100644 --- a/src/_layouts/kurzbericht.11ty.js +++ b/src/_layouts/kurzbericht.11ty.js @@ -15,9 +15,9 @@ module.exports = { const status = item.data.meta && item.data.meta.status ? `is-${item.data.meta.status}` : ''; return ` -
+
- ${item.data.title} + ${item.data.title} ${utils.getOpenInNewWindowLink(item, data)}${utils.getEditLink(item, data)} ${meta} ${item.content} diff --git a/src/assets/scripts/main.js b/src/assets/scripts/main.js index 7400caeff..5fde114c8 100644 --- a/src/assets/scripts/main.js +++ b/src/assets/scripts/main.js @@ -230,8 +230,7 @@ const addScrollToTop = () => { /* Scrollspy ############################################################################ */ - -const addScrollSpy = () => { +const addScrollSpy = () => { const inlineNavigation = document.querySelector("[data-js-scrollspy]"); if(!inlineNavigation) return; @@ -243,94 +242,61 @@ const addScrollSpy = () => { } if(viewportSize !== "large") return; - const sections = document.querySelectorAll("[data-js-scrollspy-section]"); + const headlines = document.querySelectorAll('h2[id], h3[id]'); + const arrayHeadlines = Array.from(headlines); + let lastActiveElementId = false; const intersectionCallback = (entries, observer) => { - let updated = false; entries.forEach(entry => { - // if the menu was aleady updated by a previous entry, we don't need to check the other entries. - if (updated) { - return; - } - let activeBlock; // the block that should be highlighted in the menu. - if(!entry.isIntersecting) { - - // This element has just left the viewport. This means at least one of 2 possibilities: - // 1. the next element has its top aligned with the top of the viewport. - // In this case the next element should be activated. - // 2. the previous element is (at least partly) visible. - // In this case we need to keep looking at previous elements until - // we find the highest one that is still visible. - if (isInViewport(entry.target.nextElementSibling)) { - // possibility 1. - activeBlock = entry.target.nextElementSibling; - - } else if (isInViewport(entry.target.previousElementSibling)) { - // possibility 2. - activeBlock = entry.target.previousElementSibling; - while ( isInViewport(activeBlock.previousElementSibling) ) { - activeBlock = activeBlock.previousElementSibling; - } - } - } else { - // This element just entered the viewport. 2 possibilities: - // 1. The top of the element moved in from the bottom. - // In this case nothing needs to happen. - // 2. The bottom of the element moved in from the top. - // In this case the current element should also become active. - if (!isInViewport(entry.target.nextElementSibling)) { - // possibility 1. - return; - - } else if (!isInViewport(entry.target.previousElementSibling)) { - // possibility 2. - activeBlock = entry.target; + if (entry.isIntersecting) { + let position = (entry.boundingClientRect.top + (entry.boundingClientRect.top - entry.boundingClientRect.bottom)); + if (position < 0) { + if (arrayHeadlines.indexOf(entry.target) > 0) { + if (lastActiveElementId) { + setStatusNavElement(lastActiveElementId, false); + } + const previousElement = arrayHeadlines[arrayHeadlines.indexOf(entry.target) - 1]; + setStatusNavElement(previousElement, true); + lastActiveElementId = previousElement; + } + } + } else { + if (entry.intersectionRatio < 0) { + } else { + if (entry.boundingClientRect.top < 1) { + if (lastActiveElementId) { + setStatusNavElement(lastActiveElementId, false); + } + setStatusNavElement(entry.target, true); + lastActiveElementId = entry.target; + } + } } - } - - // remove active class on all elements. - inlineNavigation.querySelectorAll('.is-active').forEach((item) => { - item.classList.remove('is-active'); - }); - // Couldn't deternmine an active block. So don't do anything. - if (!activeBlock) { - return; - } - - // get id of the intersecting section - const id = activeBlock.getAttribute('id'); - - // find matching link and add appropriate class - const navElement = inlineNavigation.querySelector(`[data-scrollspy-target="${id}"] a`); - - if(!navElement) return; - navElement.classList.add('is-active'); - - // Wer're done. Set flag to make sure that we don't check other entries. - updated = true; }); }; - - - const isInViewport = (element) => { - if (!element) { - return false; - } - const rect = element.getBoundingClientRect(); - return ( - rect.bottom >= 0 && - rect.top <= (window.innerHeight || document.documentElement.clientHeight) - ); - } const intersectionObserver = new IntersectionObserver(intersectionCallback, { - rootMargin: '-1px', + rootMargin: '-1px 0px 0px 0px', + threshold: [1], }); - sections.forEach((section) => { - intersectionObserver.observe(section); + headlines.forEach((headline) => { + intersectionObserver.observe(headline); }); + + const setStatusNavElement = (target, isActive) => { + const id = target.getAttribute('id'); + if(!id) return; + const navElement = inlineNavigation.querySelector(`[data-scrollspy-target="${id}"] a`); + if(!navElement) return; + if(isActive) { + navElement.classList.add('is-active'); + } else { + navElement.classList.remove('is-active'); + } + } }; + /* Größe des Viewports ermitteln ############################################################################ */