Skip to content
This repository was archived by the owner on Feb 16, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/_layouts/kurzbericht.11ty.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ module.exports = {
const status = item.data.meta && item.data.meta.status ? `is-${item.data.meta.status}` : '';

return `
<section class="${status} ${item.data.class ? item.data.class : ''} ${item.data.level===1 ? 'has-seperator' : ''}" id="${this.slugify(item.data.title)}" data-js-scrollspy-section>
<section class="${status} ${item.data.class ? item.data.class : ''} ${item.data.level===1 ? 'has-seperator' : ''}">
<div class="content">
<h${item.data.level + 1}>${item.data.title}
<h${item.data.level + 1} id="${this.slugify(item.data.title)}">${item.data.title}
${utils.getOpenInNewWindowLink(item, data)}${utils.getEditLink(item, data)}</h${item.data.level + 1}>
${meta}
${item.content}
Expand Down
122 changes: 44 additions & 78 deletions src/assets/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,7 @@ const addScrollToTop = () => {

/* Scrollspy
############################################################################ */

const addScrollSpy = () => {
const addScrollSpy = () => {
const inlineNavigation = document.querySelector("[data-js-scrollspy]");
if(!inlineNavigation) return;

Expand All @@ -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
############################################################################ */

Expand Down