(function (ns) { 'use strict'; const dialog = document.getElementById('info-dialog'); const title = document.getElementById('info-dialog-title'); const menu = document.getElementById('info-menu'); const backButton = document.getElementById('info-back'); const closeButton = document.getElementById('info-close'); const infoButton = document.getElementById('info-button'); const pageTitles = Object.freeze({ privacy: 'Datenschutzerklärung', imprint: 'Impressum', technology: 'Cookies und Technik' }); function ready(callback) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', callback, { once: true }); return; } callback(); } function createElement(tagName, attributes = {}, text = '') { const element = document.createElement(tagName); Object.entries(attributes).forEach(([name, value]) => { if (value === null || value === undefined) return; if (name === 'className') { element.className = value; return; } if (name === 'dataset') { Object.entries(value).forEach(([key, dataValue]) => { element.dataset[key] = dataValue; }); return; } element.setAttribute(name, value); }); if (text) element.textContent = text; return element; } function ensureInfoControl() { let control = document.querySelector('.info-control'); let button = document.getElementById('info-button') ?? document.querySelector('[aria-controls="info-dropdown"], .info-button'); let dropdown = document.getElementById('info-dropdown') ?? document.querySelector('.info-dropdown'); if (!control) { control = createElement('div', { className: 'info-control' }); document.body.insertBefore(control, document.body.firstChild); } if (!button) { button = createElement('button', { id: 'info-button', className: 'info-button', type: 'button', 'aria-label': 'Informationsmenü öffnen', title: 'Informationen' }); const icon = createElement('span', { 'aria-hidden': 'true' }, 'i'); button.appendChild(icon); } if (button.parentElement !== control) { control.insertBefore(button, control.firstChild); } button.id = 'info-button'; button.classList.add('info-button'); button.setAttribute('type', 'button'); button.setAttribute('aria-haspopup', 'true'); button.setAttribute('aria-expanded', 'false'); button.setAttribute('aria-controls', 'info-dropdown'); if (!button.getAttribute('aria-label')) button.setAttribute('aria-label', 'Informationsmenü öffnen'); if (!button.textContent.trim()) { const icon = createElement('span', { 'aria-hidden': 'true' }, 'i'); button.appendChild(icon); } if (!dropdown) { dropdown = createElement('nav', { id: 'info-dropdown', className: 'info-dropdown', 'aria-label': 'Rechtliche und technische Informationen' }); } if (dropdown.parentElement !== control) { control.appendChild(dropdown); } dropdown.id = 'info-dropdown'; dropdown.classList.add('info-dropdown'); dropdown.setAttribute('aria-label', dropdown.getAttribute('aria-label') ?? 'Rechtliche und technische Informationen'); dropdown.hidden = true; menuEntries.forEach(([target, label]) => { let menuButton = dropdown.querySelector(`[data-info-target="${target}"]`); if (!menuButton) { menuButton = createElement('button', { type: 'button', dataset: { infoTarget: target } }, label); dropdown.appendChild(menuButton); } menuButton.setAttribute('type', 'button'); menuButton.dataset.infoTarget = target; if (!menuButton.textContent.trim()) menuButton.textContent = label; }); return { control, button, dropdown }; } function moveExistingPagesInto(content, dialog) { dialog.querySelectorAll('[data-info-page]').forEach(page => { if (page.parentElement !== content) content.appendChild(page); }); } function ensureInfoPage(content, name) { let page = content.querySelector(`[data-info-page="${name}"]`) ?? document.querySelector(`[data-info-page="${name}"]`); if (!page) { page = createElement('article', { className: 'info-page', dataset: { infoPage: name } }); page.appendChild(createElement('p', {}, `${pageTitles[name]} ist noch nicht hinterlegt.`)); content.appendChild(page); } page.classList.add('info-page'); page.dataset.infoPage = name; page.hidden = true; if (page.parentElement !== content) content.appendChild(page); return page; } function ensureInfoDialog() { let dialog = document.getElementById('info-dialog'); if (!dialog) { dialog = createElement('dialog', { id: 'info-dialog', className: 'info-dialog', 'aria-labelledby': 'info-dialog-title' }); document.body.appendChild(dialog); } dialog.id = 'info-dialog'; dialog.classList.add('info-dialog'); dialog.setAttribute('aria-labelledby', 'info-dialog-title'); let shell = dialog.querySelector('.info-dialog-shell'); if (!shell) { shell = createElement('div', { className: 'info-dialog-shell' }); while (dialog.firstChild) shell.appendChild(dialog.firstChild); dialog.appendChild(shell); } let header = shell.querySelector('.info-dialog-header'); if (!header) { header = createElement('header', { className: 'info-dialog-header' }); shell.insertBefore(header, shell.firstChild); } let title = document.getElementById('info-dialog-title') ?? header.querySelector('h1, h2, .info-dialog-title'); if (!title) { title = createElement('h2', { id: 'info-dialog-title' }, 'Informationen'); header.insertBefore(title, header.firstChild); } title.id = 'info-dialog-title'; if (!title.textContent.trim()) title.textContent = 'Informationen'; let closeButton = document.getElementById('info-close') ?? header.querySelector('[data-info-close], .info-close, .info-dialog-close, button[aria-label="Dialog schließen"], button[aria-label="Schließen"]'); if (!closeButton) { closeButton = createElement('button', { id: 'info-close', type: 'button', 'aria-label': 'Informationsfenster schließen', title: 'Schließen' }, '×'); header.appendChild(closeButton); } closeButton.id = 'info-close'; closeButton.setAttribute('type', 'button'); closeButton.setAttribute('aria-label', closeButton.getAttribute('aria-label') ?? 'Informationsfenster schließen'); closeButton.setAttribute('title', closeButton.getAttribute('title') ?? 'Schließen'); if (!closeButton.textContent.trim()) closeButton.textContent = '×'; if (closeButton.parentElement !== header) header.appendChild(closeButton); let content = shell.querySelector('.info-dialog-content'); if (!content) { content = createElement('div', { className: 'info-dialog-content' }); shell.appendChild(content); } moveExistingPagesInto(content, dialog); Object.keys(pageTitles).forEach(name => ensureInfoPage(content, name)); return { dialog, title, closeButton, content }; } function ensureInfoUi() { const control = ensureInfoControl(); const dialog = ensureInfoDialog(); return { control: control.control, infoButton: control.button, dropdown: control.dropdown, dialog: dialog.dialog, title: dialog.title, closeButton: dialog.closeButton, content: dialog.content }; } function isActivation(event) { if (event.type === 'keydown') return event.key === 'Enter' || event.key === ' '; if (event.type !== 'pointerup') return false; if (event.isPrimary === false) return false; return event.pointerType !== 'mouse' || event.button === 0; } function activate(element, handler) { element.addEventListener('pointerup', event => { if (!isActivation(event)) return; event.preventDefault(); event.stopPropagation(); handler(event); }); element.addEventListener('keydown', event => { if (!isActivation(event)) return; event.preventDefault(); event.stopPropagation(); handler(event); }); } function syncStorageToggles() { const enabled = isProgressStorageEnabled(); document.querySelectorAll('.progress-storage-toggle').forEach(toggle => { toggle.checked = enabled; }); document.querySelectorAll('.cookie-toggle').forEach(toggle => { toggle.checked = false; }); } function showMenu() { title.textContent = 'Informationen'; menu.hidden = false; backButton.hidden = true; document.querySelectorAll('[data-info-page]').forEach(page => { page.hidden = true; }); } function showPage(name) { const pageName = Object.prototype.hasOwnProperty.call(pageTitles, name) ? name : 'privacy'; const page = elements?.content?.querySelector(`[data-info-page="${pageName}"]`) ?? document.querySelector(`[data-info-page="${pageName}"]`); if (!page) return; title.textContent = pageTitles[name] ?? 'Informationen'; menu.hidden = true; backButton.hidden = false; document.querySelectorAll('[data-info-page]').forEach(item => { item.hidden = item !== page; }); if (elements?.content) elements.content.scrollTop = 0; } function focusSafely(element) { if (!element || typeof element.focus !== 'function') return; try { element.focus({ preventScroll: true }); } catch { element.focus(); } } function openDialog() { if (dialog.open) return; showMenu(); syncStorageToggles(); if (typeof dialog.showModal === 'function') dialog.showModal(); else dialog.setAttribute('open', ''); closeButton.focus(); } function closeDialog() { if (typeof dialog.close === 'function') dialog.close(); else dialog.removeAttribute('open'); infoButton.focus(); } function bindStorageToggles() { document.querySelectorAll('.progress-storage-toggle').forEach(toggle => { if (toggle.dataset.wegwichtelStorageBound === 'true') return; toggle.dataset.wegwichtelStorageBound = 'true'; toggle.addEventListener('change', event => { const enabled = setProgressStorageEnabled(event.currentTarget.checked); syncStorageToggles(); document.dispatchEvent(new CustomEvent('wegwichtel:progress-storage-changed', { detail: { enabled } })); }); }); } activate(infoButton, openDialog); activate(closeButton, closeDialog); activate(backButton, showMenu); document.querySelectorAll('[data-info-target]').forEach(button => { activate(button, () => showPage(button.dataset.infoTarget)); }); if (elements.dialog.dataset.wegwichtelLegalUiDialogBound !== 'true') { elements.dialog.dataset.wegwichtelLegalUiDialogBound = 'true'; elements.dialog.addEventListener('pointerup', event => { if (event.target !== elements.dialog || !isActivation(event)) return; event.preventDefault(); event.stopPropagation(); closeDialog(); }); elements.dialog.addEventListener('cancel', event => { event.preventDefault(); closeDialog(); }); } } function init() { elements = ensureInfoUi(); bindDialog(); bindStorageToggles(); syncStorageToggles(); ns.LegalUi = Object.freeze({ open: openDialog, close: closeDialog, toggleMenu: toggleDropdown, closeMenu: () => setDropdownOpen(false), syncStorageToggles }); } ns.LegalUi = Object.freeze({ open: openDialog, close: closeDialog, syncStorageToggles }); }(globalThis.Wegwichtel ??= {}));