update legal documents and minor code smells
Sonarqube Scanner / Build and analyze (push) Failing after 21s

This commit is contained in:
Florian Zumpe
2026-08-31 15:56:26 +02:00
parent 74dc6be93c
commit ac4f6ebafe
5 changed files with 732 additions and 652 deletions
+385 -298
View File
@@ -1,20 +1,32 @@
globalThis.Wegwichtel = globalThis.Wegwichtel || {};
(function (ns) {
'use strict';
const DROPDOWN_ANIMATION_MS = 180;
const pageTitles = Object.freeze({
privacy: 'Datenschutzerklärung',
imprint: 'Impressum',
technology: 'Cookies und Technik'
});
const menuEntries = Object.freeze([
['privacy', 'Datenschutzerklärung'],
['imprint', 'Impressum'],
['technology', 'Cookies und verwendete JavaScripts']
]);
const selectors = Object.freeze({
content: '.info-dialog-content',
cookieToggle: '.cookie-toggle',
infoControl: '.info-control',
infoDropdown: '.info-dropdown',
infoPage: '[data-info-page]',
infoTarget: '[data-info-target]',
progressToggle: '.progress-storage-toggle'
});
let elements = null;
let dropdownOpen = false;
let dropdownCloseTimer = null;
let documentEventsBound = false;
function ready(callback) {
@@ -30,54 +42,62 @@
}
function qs(selector, root = document) {
return root && typeof root.querySelector === 'function' ? root.querySelector(selector) : null;
return typeof root?.querySelector === 'function' ? root.querySelector(selector) : null;
}
function qsa(selector, root = document) {
if (root && typeof root.querySelectorAll === 'function') return Array.from(root.querySelectorAll(selector));
if (typeof root?.querySelectorAll === 'function') return Array.from(root.querySelectorAll(selector));
if (root !== document && typeof document.querySelectorAll === 'function') return Array.from(document.querySelectorAll(selector));
if (root === document && typeof document.querySelectorAll === 'function') return Array.from(document.querySelectorAll(selector));
return [];
}
function createElement(tagName, attributes = {}, text = '') {
if (typeof document.createElement !== 'function') return null;
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);
});
Object.entries(attributes).forEach(([name, value]) => assignAttribute(element, name, value));
if (text) element.textContent = text;
return element;
}
function setAttribute(element, name, value) {
if (!element || typeof element.setAttribute !== 'function') return;
function assignAttribute(element, 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);
}
function setAttribute(element, name, value) {
if (typeof element?.setAttribute !== 'function') return;
element.setAttribute(name, value);
}
function setHidden(element, hidden) {
if (!element) return;
element.hidden = Boolean(hidden);
}
function setSwitchState(toggle, checked) {
if (!toggle) return;
toggle.checked = Boolean(checked);
setAttribute(toggle, 'aria-checked', checked ? 'true' : 'false');
}
function toggleClass(element, className, enabled) {
if (!element || !element.classList) return;
if (typeof element.classList.toggle === 'function') {
if (typeof element?.classList?.toggle === 'function') {
element.classList.toggle(className, enabled);
return;
}
if (enabled && typeof element.classList.add === 'function') element.classList.add(className);
if (!enabled && typeof element.classList.remove === 'function') element.classList.remove(className);
}
function append(parent, child) {
if (!parent || !child || typeof parent.appendChild !== 'function') return false;
if (!child || typeof parent?.appendChild !== 'function') return false;
parent.appendChild(child);
return true;
}
@@ -95,238 +115,293 @@
return append(document.body, element);
}
function runNextFrame(callback) {
if (typeof globalThis.requestAnimationFrame === 'function') {
globalThis.requestAnimationFrame(callback);
return;
}
callback();
}
function schedule(callback, timeout) {
if (typeof globalThis.setTimeout !== 'function') {
callback();
return null;
}
return globalThis.setTimeout(callback, timeout);
}
function cancelSchedule(timer) {
if (timer !== null && typeof globalThis.clearTimeout === 'function') globalThis.clearTimeout(timer);
}
function ensureInfoControl() {
let control = qs('.info-control');
let infoButton = byId('info-button') || qs('.info-button');
let dropdown = byId('info-dropdown') || qs('.info-dropdown');
if (!control && typeof document.createElement === 'function') {
control = createElement('div', { className: 'info-control' });
prependToBody(control);
}
if (!infoButton && control) {
infoButton = createElement('button', {
id: 'info-button',
className: 'info-button',
type: 'button',
'aria-label': 'Informationsmenü öffnen',
title: 'Informationen'
});
append(infoButton, createElement('span', { 'aria-hidden': 'true' }, 'i'));
append(control, infoButton);
}
if (!dropdown && control) {
dropdown = createElement('nav', {
id: 'info-dropdown',
className: 'info-dropdown',
'aria-label': 'Rechtliche und technische Informationen'
});
append(control, dropdown);
}
if (infoButton) {
setAttribute(infoButton, 'type', 'button');
setAttribute(infoButton, 'aria-haspopup', 'true');
setAttribute(infoButton, 'aria-expanded', 'false');
setAttribute(infoButton, 'aria-controls', 'info-dropdown');
if (typeof infoButton.getAttribute !== 'function' || !infoButton.getAttribute('aria-label')) {
setAttribute(infoButton, 'aria-label', 'Informationsmenü öffnen');
}
if (!String(infoButton.textContent ?? '').trim()) {
append(infoButton, createElement('span', { 'aria-hidden': 'true' }, 'i'));
}
}
if (dropdown) {
setAttribute(dropdown, 'aria-label', 'Rechtliche und technische Informationen');
dropdown.hidden = true;
menuEntries.forEach(([target, label]) => {
let button = qs(`[data-info-target="${target}"]`, dropdown)
|| qsa('[data-info-target]', dropdown).find(item => item.dataset?.infoTarget === target);
if (!button) {
button = createElement('button', {
type: 'button',
dataset: { infoTarget: target }
}, label);
append(dropdown, button);
}
if (!button) return;
setAttribute(button, 'type', 'button');
button.dataset.infoTarget = target;
if (!String(button.textContent ?? '').trim()) button.textContent = label;
});
}
const control = ensureControlContainer();
const infoButton = ensureInfoButton(control);
const dropdown = ensureDropdown(control);
configureInfoButton(infoButton);
configureDropdown(dropdown);
return { control, infoButton, dropdown };
}
function ensureInfoPage(content, name) {
let page = qs(`[data-info-page="${name}"]`, content) || qs(`[data-info-page="${name}"]`);
if (!page && content) {
page = createElement('article', {
className: 'info-page',
dataset: { infoPage: name }
});
append(page, createElement('p', {}, `${pageTitles[name]} ist noch nicht hinterlegt.`));
append(content, page);
function ensureControlContainer() {
const existing = qs(selectors.infoControl);
if (existing || typeof document.createElement !== 'function') return existing;
const control = createElement('div', { className: 'info-control' });
prependToBody(control);
return control;
}
function ensureInfoButton(control) {
const existing = byId('info-button') || qs('.info-button');
if (existing || !control) return existing;
const infoButton = createElement('button', {
id: 'info-button',
className: 'info-button',
type: 'button',
'aria-label': 'Informationsmenü öffnen',
title: 'Informationen'
});
append(infoButton, createElement('span', { 'aria-hidden': 'true' }, 'i'));
append(control, infoButton);
return infoButton;
}
function ensureDropdown(control) {
const existing = byId('info-dropdown') || qs(selectors.infoDropdown);
if (existing || !control) return existing;
const dropdown = createElement('nav', {
id: 'info-dropdown',
className: 'info-dropdown',
'aria-label': 'Rechtliche und technische Informationen'
});
append(control, dropdown);
return dropdown;
}
function configureInfoButton(infoButton) {
if (!infoButton) return;
setAttribute(infoButton, 'type', 'button');
setAttribute(infoButton, 'aria-haspopup', 'true');
setAttribute(infoButton, 'aria-expanded', 'false');
setAttribute(infoButton, 'aria-controls', 'info-dropdown');
setInfoButtonLabel(infoButton);
ensureInfoButtonIcon(infoButton);
}
function setInfoButtonLabel(infoButton) {
if (typeof infoButton.getAttribute === 'function' && infoButton.getAttribute('aria-label')) return;
setAttribute(infoButton, 'aria-label', 'Informationsmenü öffnen');
}
function ensureInfoButtonIcon(infoButton) {
if (String(infoButton.textContent ?? '').trim()) return;
append(infoButton, createElement('span', { 'aria-hidden': 'true' }, 'i'));
}
function configureDropdown(dropdown) {
if (!dropdown) return;
setAttribute(dropdown, 'aria-label', 'Rechtliche und technische Informationen');
setHidden(dropdown, true);
menuEntries.forEach(([target, label]) => ensureMenuButton(dropdown, target, label));
}
function ensureMenuButton(dropdown, target, label) {
let button = qs(`[data-info-target="${target}"]`, dropdown);
button = button || qsa(selectors.infoTarget, dropdown).find(item => item.dataset?.infoTarget === target);
if (!button) {
button = createElement('button', { type: 'button', dataset: { infoTarget: target } }, label);
append(dropdown, button);
}
if (page) {
page.dataset.infoPage = name;
if (name !== 'privacy') page.hidden = true;
}
return page;
configureMenuButton(button, target, label);
}
function configureMenuButton(button, target, label) {
if (!button) return;
setAttribute(button, 'type', 'button');
button.dataset.infoTarget = target;
if (!String(button.textContent ?? '').trim()) button.textContent = label;
}
function ensureInfoDialog() {
let dialog = byId('info-dialog') || qs('#info-dialog');
let title = byId('info-dialog-title') || qs('#info-dialog-title', dialog);
let backButton = byId('info-back') || qs('#info-back', dialog);
let legacyMenu = byId('info-menu') || qs('#info-menu', dialog);
let closeButton = byId('info-close') || qs('#info-close', dialog);
let content = qs('.info-dialog-content', dialog) || qs('.info-dialog-content');
if (!dialog && typeof document.createElement === 'function') {
dialog = createElement('dialog', {
id: 'info-dialog',
className: 'info-dialog',
'aria-labelledby': 'info-dialog-title'
});
append(document.body, dialog);
}
if (dialog && (!title || !closeButton || !content) && typeof document.createElement === 'function') {
let shell = qs('.info-dialog-shell', dialog);
if (!shell) {
shell = createElement('div', { className: 'info-dialog-shell' });
append(dialog, shell);
}
let header = qs('.info-dialog-header', shell);
if (!header) {
header = createElement('header', { className: 'info-dialog-header' });
append(shell, header);
}
if (!title) {
title = createElement('h2', { id: 'info-dialog-title' }, pageTitles.privacy);
append(header, title);
}
if (!closeButton) {
closeButton = createElement('button', {
id: 'info-close',
type: 'button',
'aria-label': 'Informationsfenster schließen',
title: 'Schließen'
}, '×');
append(header, closeButton);
}
if (!content) {
content = createElement('div', { className: 'info-dialog-content' });
append(shell, content);
}
}
if (dialog) setAttribute(dialog, 'aria-labelledby', 'info-dialog-title');
if (backButton) {
setAttribute(backButton, 'type', 'button');
setAttribute(backButton, 'aria-label', 'Zurück zum Informationsmenü');
backButton.hidden = true;
}
if (legacyMenu) legacyMenu.hidden = true;
if (closeButton) {
setAttribute(closeButton, 'type', 'button');
setAttribute(closeButton, 'aria-label', 'Informationsfenster schließen');
if (!String(closeButton.textContent ?? '').trim()) closeButton.textContent = '×';
}
if (content) Object.keys(pageTitles).forEach(name => ensureInfoPage(content, name));
const dialog = ensureDialogElement();
const shell = ensureDialogShell(dialog);
const header = ensureDialogHeader(shell);
const title = ensureDialogTitle(dialog, header);
const backButton = configureBackButton(byId('info-back') || qs('#info-back', dialog));
const legacyMenu = configureLegacyMenu(byId('info-menu') || qs('#info-menu', dialog));
const closeButton = ensureCloseButton(dialog, header);
const content = ensureDialogContent(dialog, shell);
configureDialog(dialog);
ensurePages(content);
return { dialog, title, backButton, legacyMenu, closeButton, content };
}
function ensureDialogElement() {
const existing = byId('info-dialog') || qs('#info-dialog');
if (existing || typeof document.createElement !== 'function') return existing;
const dialog = createElement('dialog', {
id: 'info-dialog',
className: 'info-dialog',
'aria-labelledby': 'info-dialog-title'
});
append(document.body, dialog);
return dialog;
}
function ensureDialogShell(dialog) {
if (!dialog) return null;
const existing = qs('.info-dialog-shell', dialog);
if (existing || typeof document.createElement !== 'function') return existing;
const shell = createElement('div', { className: 'info-dialog-shell' });
append(dialog, shell);
return shell;
}
function ensureDialogHeader(shell) {
if (!shell) return null;
const existing = qs('.info-dialog-header', shell);
if (existing || typeof document.createElement !== 'function') return existing;
const header = createElement('header', { className: 'info-dialog-header' });
append(shell, header);
return header;
}
function ensureDialogTitle(dialog, header) {
const existing = byId('info-dialog-title') || qs('#info-dialog-title', dialog);
if (existing || !header) return existing;
const title = createElement('h2', { id: 'info-dialog-title' }, pageTitles.privacy);
append(header, title);
return title;
}
function configureBackButton(backButton) {
setAttribute(backButton, 'type', 'button');
setAttribute(backButton, 'aria-label', 'Zurück zum Informationsmenü');
setHidden(backButton, true);
return backButton;
}
function configureLegacyMenu(legacyMenu) {
setHidden(legacyMenu, true);
return legacyMenu;
}
function ensureCloseButton(dialog, header) {
const existing = byId('info-close') || qs('#info-close', dialog);
if (existing || !header) return configureCloseButton(existing);
const closeButton = createElement('button', {
id: 'info-close',
type: 'button',
'aria-label': 'Informationsfenster schließen',
title: 'Schließen'
}, '×');
append(header, closeButton);
return configureCloseButton(closeButton);
}
function configureCloseButton(closeButton) {
setAttribute(closeButton, 'type', 'button');
setAttribute(closeButton, 'aria-label', 'Informationsfenster schließen');
if (closeButton && !String(closeButton.textContent ?? '').trim()) closeButton.textContent = '×';
return closeButton;
}
function ensureDialogContent(dialog, shell) {
const existing = qs(selectors.content, dialog) || qs(selectors.content);
if (existing || !shell) return existing;
const content = createElement('div', { className: 'info-dialog-content' });
append(shell, content);
return content;
}
function configureDialog(dialog) {
setAttribute(dialog, 'aria-labelledby', 'info-dialog-title');
}
function ensurePages(content) {
if (!content) return;
Object.keys(pageTitles).forEach(name => ensureInfoPage(content, name));
}
function ensureInfoPage(content, name) {
const existing = qs(`[data-info-page="${name}"]`, content) || qs(`[data-info-page="${name}"]`);
const page = existing || createFallbackPage(content, name);
if (!page) return null;
page.dataset.infoPage = name;
setHidden(page, name !== 'privacy');
return page;
}
function createFallbackPage(content, name) {
const page = createElement('article', { className: 'info-page', dataset: { infoPage: name } });
append(page, createElement('p', {}, `${pageTitles[name]} ist noch nicht hinterlegt.`));
append(content, page);
return page;
}
function ensureInfoUi() {
return {
...ensureInfoControl(),
...ensureInfoDialog()
};
return { ...ensureInfoControl(), ...ensureInfoDialog() };
}
function isActivation(event) {
if (!event) return false;
if (event.type === 'pointerup') {
if (event.isPrimary === false) return false;
if (event.pointerType === 'mouse' && event.button !== 0) return false;
return true;
}
if (event.type === 'keydown') return event.key === 'Enter' || event.key === ' ';
return false;
if (event.type !== 'pointerup') return false;
if (event.isPrimary === false) return false;
return event.pointerType !== 'mouse' || event.button === 0;
}
function activate(element, handler) {
if (!element || typeof element.addEventListener !== 'function') return;
if (element.dataset) {
const key = handler.name ? `wegwichtelLegalUiBound${handler.name}` : 'wegwichtelLegalUiBound';
if (element.dataset[key] === 'true') return;
element.dataset[key] = 'true';
}
element.addEventListener('pointerup', event => {
if (!isActivation(event)) return;
if (typeof event.preventDefault === 'function') event.preventDefault();
if (typeof event.stopPropagation === 'function') event.stopPropagation();
handler(event);
});
element.addEventListener('keydown', event => {
if (!isActivation(event)) return;
if (typeof event.preventDefault === 'function') event.preventDefault();
if (typeof event.stopPropagation === 'function') event.stopPropagation();
handler(event);
});
if (typeof element?.addEventListener !== 'function') return;
if (!markBound(element, handler)) return;
element.addEventListener('pointerup', event => handleActivation(event, handler));
element.addEventListener('keydown', event => handleActivation(event, handler));
}
function markBound(element, handler) {
if (!element.dataset) return true;
const key = handler.name ? `wegwichtelLegalUiBound${handler.name}` : 'wegwichtelLegalUiBound';
if (element.dataset[key] === 'true') return false;
element.dataset[key] = 'true';
return true;
}
function handleActivation(event, handler) {
if (!isActivation(event)) return;
event.preventDefault?.();
event.stopPropagation?.();
handler(event);
}
function setDropdownOpen(open) {
if (!elements?.dropdown || !elements?.infoButton) return;
dropdownOpen = Boolean(open);
elements.dropdown.hidden = !dropdownOpen;
toggleClass(elements.dropdown, 'is-open', dropdownOpen);
setAttribute(elements.infoButton, 'aria-expanded', dropdownOpen ? 'true' : 'false');
cancelSchedule(dropdownCloseTimer);
dropdownCloseTimer = null;
if (dropdownOpen) openDropdown();
else closeDropdown();
}
function hidePages() {
qsa('[data-info-page]').forEach(item => {
item.hidden = true;
});
function openDropdown() {
setHidden(elements.dropdown, false);
runNextFrame(() => toggleClass(elements.dropdown, 'is-open', true));
}
function openLegacyMenu() {
if (!elements?.dialog) return;
hidePages();
if (elements.title) elements.title.textContent = 'Informationen';
if (elements.legacyMenu) elements.legacyMenu.hidden = false;
if (elements.backButton) elements.backButton.hidden = true;
if (!elements.dialog.open) {
if (typeof elements.dialog.showModal === 'function') elements.dialog.showModal();
else setAttribute(elements.dialog, 'open', '');
}
focusSafely(elements.closeButton ?? elements.dialog);
function closeDropdown() {
toggleClass(elements.dropdown, 'is-open', false);
dropdownCloseTimer = schedule(() => {
if (!dropdownOpen) setHidden(elements.dropdown, true);
}, DROPDOWN_ANIMATION_MS);
}
function handleInfoButton() {
if (elements?.dropdown) {
setDropdownOpen(!dropdownOpen);
return;
}
openLegacyMenu();
setDropdownOpen(!dropdownOpen);
}
function elementContains(element, target) {
if (!element || !target) return false;
if (element === target) return true;
return typeof element.contains === 'function' && element.contains(target);
return Boolean(element && target && (element === target || element.contains?.(target)));
}
function isInsideInfoControl(target) {
@@ -334,39 +409,38 @@
}
function isProgressStorageEnabled() {
if (!ns.PrivacyStorage || typeof ns.PrivacyStorage.isProgressStorageEnabled !== 'function') return false;
return ns.PrivacyStorage.isProgressStorageEnabled();
return ns?.PrivacyStorage?.isProgressStorageEnabled?.() === true;
}
function setProgressStorageEnabled(enabled) {
if (!ns.PrivacyStorage || typeof ns.PrivacyStorage.setProgressStorageEnabled !== 'function') return false;
return ns.PrivacyStorage.setProgressStorageEnabled(enabled);
return ns?.PrivacyStorage?.setProgressStorageEnabled?.(enabled) === true;
}
function syncStorageToggles() {
const enabled = isProgressStorageEnabled();
qsa('.progress-storage-toggle').forEach(toggle => {
toggle.checked = enabled;
});
qsa('.cookie-toggle').forEach(toggle => {
toggle.checked = false;
});
qsa(selectors.progressToggle).forEach(toggle => setSwitchState(toggle, enabled));
qsa(selectors.cookieToggle).forEach(toggle => setSwitchState(toggle, false));
}
function pageNameOrDefault(name) {
return Object.hasOwn(pageTitles, name) ? name : 'privacy';
}
function showPage(name) {
const pageName = Object.prototype.hasOwnProperty.call(pageTitles, name) ? name : 'privacy';
const pageName = pageNameOrDefault(name);
const page = qs(`[data-info-page="${pageName}"]`, elements?.content) || qs(`[data-info-page="${pageName}"]`);
if (!page) return;
if (elements?.title) elements.title.textContent = pageTitles[pageName] ?? 'Informationen';
qsa('[data-info-page]').forEach(item => {
item.hidden = item !== page;
});
updateDialogTitle(pageName);
qsa(selectors.infoPage).forEach(item => setHidden(item, item !== page));
if (elements?.content) elements.content.scrollTop = 0;
}
function updateDialogTitle(pageName) {
if (elements?.title) elements.title.textContent = pageTitles[pageName] ?? 'Informationen';
}
function focusSafely(element) {
if (!element || typeof element.focus !== 'function') return;
if (typeof element?.focus !== 'function') return;
try {
element.focus({ preventScroll: true });
} catch {
@@ -376,85 +450,99 @@
function openDialog(name = 'privacy') {
if (!elements?.dialog) return;
const pageName = Object.prototype.hasOwnProperty.call(pageTitles, name) ? name : 'privacy';
setDropdownOpen(false);
if (elements?.legacyMenu) elements.legacyMenu.hidden = true;
if (elements?.backButton) elements.backButton.hidden = !elements?.legacyMenu;
showPage(pageName);
setHidden(elements.legacyMenu, true);
setHidden(elements.backButton, true);
showPage(pageNameOrDefault(name));
syncStorageToggles();
if (!elements.dialog.open) {
if (typeof elements.dialog.showModal === 'function') elements.dialog.showModal();
else setAttribute(elements.dialog, 'open', '');
}
showDialog();
focusSafely(elements.closeButton ?? elements.dialog);
}
function showDialog() {
if (elements.dialog.open) return;
if (typeof elements.dialog.showModal === 'function') elements.dialog.showModal();
else setAttribute(elements.dialog, 'open', '');
}
function closeDialog() {
if (elements?.dialog) {
if (typeof elements.dialog.close === 'function') elements.dialog.close();
else if (typeof elements.dialog.removeAttribute === 'function') elements.dialog.removeAttribute('open');
}
closeNativeDialog();
setDropdownOpen(false);
focusSafely(elements?.infoButton);
}
function closeNativeDialog() {
if (!elements?.dialog) return;
if (typeof elements.dialog.close === 'function') elements.dialog.close();
else elements.dialog.removeAttribute?.('open');
}
function bindStorageToggles() {
qsa('.progress-storage-toggle').forEach(toggle => {
if (toggle.dataset?.wegwichtelStorageBound === 'true') return;
if (toggle.dataset) toggle.dataset.wegwichtelStorageBound = 'true';
toggle.addEventListener('change', event => {
const source = event.currentTarget || event.target || toggle;
const enabled = setProgressStorageEnabled(Boolean(source.checked));
syncStorageToggles();
document.dispatchEvent(new CustomEvent('wegwichtel:progress-storage-changed', {
detail: { enabled }
}));
});
});
qsa(selectors.progressToggle).forEach(bindStorageToggle);
}
function bindStorageToggle(toggle) {
if (toggle.dataset?.wegwichtelStorageBound === 'true') return;
if (toggle.dataset) toggle.dataset.wegwichtelStorageBound = 'true';
toggle.addEventListener('change', event => handleStorageToggleChange(event, toggle));
}
function handleStorageToggleChange(event, fallbackToggle) {
const source = event.currentTarget || event.target || fallbackToggle;
const enabled = setProgressStorageEnabled(Boolean(source.checked));
syncStorageToggles();
document.dispatchEvent(new CustomEvent('wegwichtel:progress-storage-changed', { detail: { enabled } }));
}
function infoTargetButtons() {
if (elements?.dropdown) return qsa('[data-info-target]', elements.dropdown);
if (elements?.legacyMenu) return qsa('[data-info-target]', elements.legacyMenu);
return qsa('[data-info-target]');
const root = elements?.dropdown || elements?.legacyMenu || document;
return qsa(selectors.infoTarget, root);
}
function bindDialog() {
activate(elements?.infoButton, handleInfoButton);
activate(elements?.closeButton, closeDialog);
activate(elements?.backButton, openLegacyMenu);
activate(elements?.backButton, () => setDropdownOpen(true));
infoTargetButtons().forEach(button => activate(button, () => openDialog(button.dataset?.infoTarget)));
bindDocumentEvents();
bindDialogEvents();
}
infoTargetButtons().forEach(button => {
activate(button, () => openDialog(button.dataset?.infoTarget));
});
function bindDocumentEvents() {
if (documentEventsBound) return;
documentEventsBound = true;
document.addEventListener('pointerup', closeDropdownOnOutsidePointer);
document.addEventListener('keydown', closeDropdownOnEscape);
}
if (!documentEventsBound) {
documentEventsBound = true;
document.addEventListener('pointerup', event => {
if (!dropdownOpen || isInsideInfoControl(event.target)) return;
setDropdownOpen(false);
});
document.addEventListener('keydown', event => {
if (!dropdownOpen || event.key !== 'Escape' || elements?.dialog?.open) return;
if (typeof event.preventDefault === 'function') event.preventDefault();
setDropdownOpen(false);
focusSafely(elements?.infoButton);
});
}
function closeDropdownOnOutsidePointer(event) {
if (dropdownOpen && !isInsideInfoControl(event.target)) setDropdownOpen(false);
}
if (elements?.dialog && elements.dialog.dataset?.wegwichtelLegalUiDialogBound !== 'true') {
if (elements.dialog.dataset) elements.dialog.dataset.wegwichtelLegalUiDialogBound = 'true';
elements.dialog.addEventListener('pointerup', event => {
if (event.target !== elements.dialog || !isActivation(event)) return;
if (typeof event.preventDefault === 'function') event.preventDefault();
if (typeof event.stopPropagation === 'function') event.stopPropagation();
closeDialog();
});
elements.dialog.addEventListener('cancel', event => {
if (typeof event.preventDefault === 'function') event.preventDefault();
closeDialog();
});
}
function closeDropdownOnEscape(event) {
if (!dropdownOpen || event.key !== 'Escape' || elements?.dialog?.open) return;
event.preventDefault?.();
setDropdownOpen(false);
focusSafely(elements?.infoButton);
}
function bindDialogEvents() {
if (!elements?.dialog || elements.dialog.dataset?.wegwichtelLegalUiDialogBound === 'true') return;
if (elements.dialog.dataset) elements.dialog.dataset.wegwichtelLegalUiDialogBound = 'true';
elements.dialog.addEventListener('pointerup', closeDialogOnBackdropPointer);
elements.dialog.addEventListener('cancel', closeDialogOnCancel);
}
function closeDialogOnBackdropPointer(event) {
if (event.target !== elements.dialog || !isActivation(event)) return;
event.preventDefault?.();
event.stopPropagation?.();
closeDialog();
}
function closeDialogOnCancel(event) {
event.preventDefault?.();
closeDialog();
}
function init() {
@@ -462,7 +550,6 @@
bindDialog();
bindStorageToggles();
syncStorageToggles();
ns.LegalUi = Object.freeze({
open: openDialog,
close: closeDialog,
@@ -473,4 +560,4 @@
}
ready(init);
}(globalThis.Wegwichtel = globalThis.Wegwichtel || {}));
}(globalThis.Wegwichtel));