// Event listener helper function function addEvent(element, event, handler) { if (element?.attachEvent) { return element.attachEvent('on' + event, handler); } return element?.addEventListener(event, handler, false); } // DOM element getters const getElement = id => document.getElementById(id); const getElements = selector => document.querySelectorAll(selector); // Logotype width calculation function recalcLogotypeWidth() { const logotype = getElement('logotype'); const logotypeText = getElement('logotype__text'); logotype?.setAttribute('width', `${logotypeText.getBoundingClientRect().width}px`); } // Viewport adaptation function adaptViewport() { // fix logotype when font loading delayed document.fonts.ready.then(() => { recalcLogotypeWidth(); }); if (window.innerWidth < 640) { getElement('has-search')?.setAttribute('open', 'open'); getElement('has-search')?.removeAttribute('name'); getElement('has-more-menu')?.setAttribute('open', 'open'); } else { getElement('top-nav')?.setAttribute('open', 'open') addEvent(visualViewport, 'resize', adaptViewport); } } addEvent(window, 'DOMContentLoaded', adaptViewport); // Node collapse handlers const collapseParentNode = getElements('.js-cpn'); const collapseGrandParentNode = getElements('.js-cgpn'); const detailsElements = getElements('details.js-details'); collapseParentNode.forEach(element => { const handler = () => element.parentNode?.removeAttribute('open'); addEvent(element, 'click', handler); }); collapseGrandParentNode.forEach(element => { const handler = () => element.parentNode?.parentNode?.removeAttribute('open'); addEvent(element, 'click', handler); }); if (window.innerWidth > 640) { // Details element handler for firefox based browsers which do not respect the same name attribute detailsElements.forEach(detail => { const handler = (e) => { const name = detail.getAttribute('name'); if (name) { getElements(`details.js-details[name="${name}"]`).forEach(otherDetail => { if (otherDetail !== detail && otherDetail.hasAttribute('open')) { otherDetail.removeAttribute('open'); } }); } }; addEvent(detail, 'click', handler); }); } // Share functionality if (typeof navigatorShare !== 'undefined') { getElement('navigatorShare')?.setAttribute( 'href', 'javascript:navigator.share({title: document.title, url: window.location.href})' ); if (location.protocol === 'https:') { getElement('copyPermalink')?.removeAttribute('class'); } } getElement('print-button')?.removeAttribute('class'); getElement('back')?.removeAttribute('class'); // Date handling const date = new Date(); // Mastodon and QR code functionality if (typeof mastodonInstance !== 'undefined') { getElement('has-mastodon').className = 'active'; const mastodonHandler = () => { mastodonTitle.disabled = true; mastodonPermalink.disabled = true; mastodonText.disabled = false; mastodon?.setAttribute('action', `${mastodonInstance.value}/share`); }; addEvent(mastodonInstance, 'input', mastodonHandler); if (typeof QRCode !== 'undefined') { getElement('colophon').removeAttribute('style'); qr?.appendChild( QRCode({ msg: window.location.href, ecl: 'M', pal: ['#000', '#fff'], pad: 2, dim: 96, }) ); const isoTime = date.toISOString(); const timeStamp = getElement('time-stamp'); timeStamp.innerHTML = isoTime; timeStamp?.setAttribute('datetime', isoTime); } } // Digital well-being clock const hour = date.getHours(); const isDaytime = hour > 6 && hour < 21; function toggleNightElements(hidden) { const elements = ['grain', 'dwclock']; elements.forEach(id => { const element = getElement(id); element?.[hidden ? 'setAttribute' : 'removeAttribute']('hidden', 'hidden'); }); } if (isDaytime) { toggleNightElements(true); } else { toggleNightElements(false); let clockInterval; function updateClock() { const minutes = date.getMinutes(); const seconds = date.getSeconds(); const minutesDegrees = ((minutes / 60) * 360) + ((seconds/60)*6); const hourDegrees = ((hour / 12) * 360) + ((minutes/60)*30); const transforms = ['transform', 'webkitTransform', 'mozTransform', 'msTransform', 'oTransform']; const hands = { '#min': minutesDegrees, '#hour': hourDegrees }; Object.entries(hands).forEach(([selector, degrees]) => { const hand = document.querySelector(selector); transforms.forEach(transform => { hand.style[transform] = `rotate(${degrees}deg)`; }); }); } updateClock(); clockInterval = setInterval(updateClock, 10000); } // Overwrite browser search bar (canceled) // addEvent(document, 'keydown', function(e) { // if (e.ctrlKey && e.key === 'k') { // e.preventDefault(); // getElement('has-search')?.setAttribute('open', 'open'); // const searchInput = document.querySelector('.pagefind-ui__search-input'); // searchInput?.focus(); // } // }); // clashes with details handler, need workaround addEvent(window, 'beforeprint', function() { getElements('[name="redaction-history"]')?.forEach(e => { e.setAttribute('open', 'open'); }); });