Skip to content
Merged
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
172 changes: 90 additions & 82 deletions assets/js/highlightHeadline.js
Original file line number Diff line number Diff line change
@@ -1,103 +1,111 @@
function initHighlightHeadline() {
import * as mq from './mediaqueries';

function isAsideActive() {
return window.matchMedia(mq.minLG).matches;
}

// In this site's layout, the table of contents (.content_with_heading) is an element that appears before any other content at the same hierarchy level
const headings = Array.from(document.querySelectorAll('.content_with_heading :is(h1, h2, h3, h4)'));
const asideMobileCurrentHeadline = document.getElementById('aside_mobile_current_headline');
const windowPath = window.location.pathname;
if (headings.length === 0) {
return; // No headings? No business here
}
function initHighlightHeadline() {

// A few helper functions (.toc is the top-level ordered list)
const markTocItemActive = (a) => {return a.setAttribute('data-current', '');}
const markTocItemInactive = (a) => {return a.removeAttribute('data-current');};
const getTocLinkFromHeading = (h) => {return document.querySelector(`.toc a[href="${windowPath}#${encodeURIComponent(h.id).replace(/%\w\w/g, match => match.toLowerCase())}"]`);}
// In this site's layout, the table of contents (.content_with_heading) is an element that appears before any other content at the same hierarchy level
const headings = Array.from(document.querySelectorAll('.content_with_heading :is(h1, h2, h3, h4)'));
const windowPath = window.location.pathname;
if (headings.length === 0) {
return; // No headings? No business here
}

const getDocHeight = () => Math.floor(document.body.clientHeight);
// A few helper functions (.toc is the top-level ordered list)
const markTocItemActive = (a) => {return a.setAttribute('data-current', '');}
const markTocItemInactive = (a) => {return a.removeAttribute('data-current');};
const getTocLinkFromHeading = (h) => {return document.querySelector(`.toc a[href="${windowPath}#${encodeURIComponent(h.id).replace(/%\w\w/g, match => match.toLowerCase())}"]`);}

const visibleHeadings = new Set();
let resizeDebounce;
let currentObserver;
let height = getDocHeight();
const getDocHeight = () => Math.floor(document.body.clientHeight);

function beginObservation(docHeight) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
// Keep track of visible headings
if (entry.isIntersecting) {
visibleHeadings.add(entry.target);
} else {
visibleHeadings.delete(entry.target);
}
});
const visibleHeadings = new Set();
let resizeDebounce;
let currentObserver;
let height = getDocHeight();

// Sort visible (intersecting) headings by inverted order of appearance, then grab the first item (i.e. last visible heading)
const lastVisible = Array.from(visibleHeadings.values()).sort((a, b) => headings.indexOf(b) - headings.indexOf(a))[0];
if (!lastVisible) {
return; // If nothing is visible, weird — TOC are opt-in — but let's skip this logic
function beginObservation(docHeight) {
const observer = new IntersectionObserver(
(entries) => {
if (!isAsideActive()) {
return; // Exit if .o-aside is not active
}

headings.forEach((heading) => {
entries.forEach((entry) => {
// Keep track of visible headings
if (entry.isIntersecting) {
visibleHeadings.add(entry.target);
} else {
visibleHeadings.delete(entry.target);
}
});

// If it's the last visible item, mark it to make it stand out, else, revert to the default style
// Find the link in the TOC list matching the heading in this list of hheding elements
const tocLink = getTocLinkFromHeading(heading);
if (heading === lastVisible) {
asideMobileCurrentHeadline.textContent = heading.textContent;
if(tocLink){
markTocItemActive(tocLink);
}
} else {
if(tocLink){
markTocItemInactive(tocLink);
}
}
});
},
{
//? docHeight: Extend the detection above the heading so it's always considered as intersecting if above the scrollport
//? -33%: The element won't be considered as intersecting until it has gone _above_ the bottom third of the scrollport
rootMargin: `${docHeight}px 0px -80% 0px`,
threshold: 1, // Only considered intersecting if all the pixels are inside the intersection area
}
);
// Sort visible (intersecting) headings by inverted order of appearance, then grab the first item (i.e. last visible heading)
const lastVisible = Array.from(visibleHeadings.values()).sort((a, b) => headings.indexOf(b) - headings.indexOf(a))[0];
if (!lastVisible) {
return; // If nothing is visible, weird — TOC are opt-in — but let's skip this logic
}

headings.forEach((heading) => observer.observe(heading));

return observer;
}
headings.forEach((heading) => {

// On page load...
// If it's the last visible item, mark it to make it stand out, else, revert to the default style
// Find the link in the TOC list matching the heading in this list of heading elements
const tocLink = getTocLinkFromHeading(heading);
if (heading === lastVisible) {
if(tocLink){
markTocItemActive(tocLink);
}
} else {
if(tocLink){
markTocItemInactive(tocLink);
}
}
});
},
{
//? docHeight: Extend the detection above the heading so it's always considered as intersecting if above the scrollport
//? -33%: The element won't be considered as intersecting until it has gone _above_ the bottom third of the scrollport
rootMargin: `${docHeight}px 0px -80% 0px`,
threshold: 1, // Only considered intersecting if all the pixels are inside the intersection area
}
);

headings.forEach((heading) => observer.observe(heading));

return observer;
}

// On page load...
// Let us don't do this
/*
markTocItemActive(getTocLinkFromHeading(headings[0])); // Mark the first item as active (even if the heading appears a bit further down)
*/
currentObserver = beginObservation(height); // Start the intersection observer
currentObserver = beginObservation(height); // Start the intersection observer

// On resize, replace the observer with a new one matching the updated body height, if different
window.addEventListener('resize', () => {
clearTimeout(resizeDebounce);
resizeDebounce = setTimeout(() => {
const heightAfterResize = getDocHeight();
if (height !== heightAfterResize) {
if (currentObserver) {
currentObserver.disconnect();
}
currentObserver = beginObservation(heightAfterResize);
}
}, 200);
});
// On resize, replace the observer with a new one matching the updated body height, if different
window.addEventListener('resize', () => {
clearTimeout(resizeDebounce);
resizeDebounce = setTimeout(() => {
const heightAfterResize = getDocHeight();
if (height !== heightAfterResize) {
if (currentObserver) {
currentObserver.disconnect();
}
currentObserver = beginObservation(heightAfterResize);
}
}, 200);
});
}

if (document.readyState === "interactive") {
if (document.getElementById('aside')) {
initHighlightHeadline();
}
if (document.getElementById('aside')) {
initHighlightHeadline();
}
} else {
window.addEventListener("DOMContentLoaded", () => {
if (document.getElementById('aside')) {
initHighlightHeadline();
}
});
window.addEventListener("DOMContentLoaded", () => {
if (document.getElementById('aside')) {
initHighlightHeadline();
}
});
}
1 change: 0 additions & 1 deletion assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ import './resizeObserver.js';
import './mediaqueries.js';
import './highlightHeadline.js';
import './anchorlinks.js';
//import './aside.js';
3 changes: 0 additions & 3 deletions assets/js/mobileMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ function initMobileMenu() {
closeMobileMenu()
});

//TODO: window.onClick in mobileMenu.js und aside.js konsollidieren; momentan funktioniert es nicht gemeinsam.
//const target = initWindowOnClick();

window.onclick = e => {
//console.log(e.target);
if (e.target.classList.contains('o-header__curtain')) {
Expand Down
5 changes: 0 additions & 5 deletions assets/js/windowOnClickHandling.js

This file was deleted.

24 changes: 0 additions & 24 deletions assets/sass/sidemenu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,6 @@
margin-bottom: 1.6rem;
}

//TODO: Bessere Benamung
.o-aside__mobile-container1 {
display: none;

button {
display: flex;
border: 0;
width: 100%;
border-radius: var(--border-radius-m);
align-items: center;
justify-content: space-between;
}
}

//TODO: Bessere Benamung
.o-aside__mobile-container2 {
display: block;

@include media-breakpoint-down(lg) {
display: none;
justify-content: space-between;
}
}

.o-aside__mobile-container--open {
@include media-breakpoint-down(lg) {
display: block;
Expand Down
8 changes: 1 addition & 7 deletions layouts/partials/sidemenu.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
<aside id="aside" class="o-aside tableOfContents">
<div class="o-aside__mobile o-aside__mobile-container1 o-single__container o-aside__mobile-container--open">
<button>
<div id="aside_mobile_current_headline">{{ .Title }}</div>
{{ partial "ico" (dict "icon" "list" ) }}
</button>
</div>
<div class="o-aside__mobile-container2 o-single__container">
<div class="o-single__container">
{{ if eq .Page.Type "operator" }}
<ul>
{{ $related := .Site.RegularPages.RelatedIndices . "country" }}
Expand Down