Load overlay helper globally
This commit is contained in:
@@ -275,6 +275,7 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src="/scripts/help-icon-overlays.js"></script>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>OTC-Verkauf</h1>
|
<h1>OTC-Verkauf</h1>
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ function render_auth_home_page(array $user, array $otcProducts = []): void
|
|||||||
echo '</div>';
|
echo '</div>';
|
||||||
echo '</article>';
|
echo '</article>';
|
||||||
echo '</section>';
|
echo '</section>';
|
||||||
|
echo '<script src="/scripts/help-icon-overlays.js"></script>';
|
||||||
echo '<script>';
|
echo '<script>';
|
||||||
echo 'const portalModuleNavigation = ' . $moduleNavigation . ';';
|
echo 'const portalModuleNavigation = ' . $moduleNavigation . ';';
|
||||||
echo 'const portalModuleContentCards = ' . $moduleContentCards . ';';
|
echo 'const portalModuleContentCards = ' . $moduleContentCards . ';';
|
||||||
@@ -261,6 +262,16 @@ function render_auth_home_page(array $user, array $otcProducts = []): void
|
|||||||
echo " button.setAttribute('aria-expanded', String(nextState));";
|
echo " button.setAttribute('aria-expanded', String(nextState));";
|
||||||
echo " });";
|
echo " });";
|
||||||
echo "});";
|
echo "});";
|
||||||
|
echo "document.addEventListener('click', (event) => {";
|
||||||
|
echo " if (event.target.closest('.sg-sandwich-menu-wrap')) {";
|
||||||
|
echo " return;";
|
||||||
|
echo " }";
|
||||||
|
echo " document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {";
|
||||||
|
echo " const button = wrap.querySelector('.sg-sandwich-button');";
|
||||||
|
echo " wrap.dataset.open = 'false';";
|
||||||
|
echo " if (button) { button.setAttribute('aria-expanded', 'false'); }";
|
||||||
|
echo " });";
|
||||||
|
echo "});";
|
||||||
echo "(() => {";
|
echo "(() => {";
|
||||||
echo " const mediaQuery = window.matchMedia('(max-width: 767px)');";
|
echo " const mediaQuery = window.matchMedia('(max-width: 767px)');";
|
||||||
echo " const toggle = document.querySelector('[data-left-navigation-toggle]');";
|
echo " const toggle = document.querySelector('[data-left-navigation-toggle]');";
|
||||||
@@ -475,6 +486,12 @@ function render_auth_home_page(array $user, array $otcProducts = []): void
|
|||||||
echo " });";
|
echo " });";
|
||||||
echo " updateFormState();";
|
echo " updateFormState();";
|
||||||
echo "})();";
|
echo "})();";
|
||||||
|
echo "if (window.sgInitHelpIconOverlays) {";
|
||||||
|
echo " window.sgInitHelpIconOverlays({";
|
||||||
|
echo " closeOnOpenSelectors: ['.sg-sandwich-menu-wrap'],";
|
||||||
|
echo " outsideClickIgnoreSelectors: ['.sg-sandwich-menu-wrap'],";
|
||||||
|
echo " });";
|
||||||
|
echo "}";
|
||||||
echo "renderMainHeading('ERP');";
|
echo "renderMainHeading('ERP');";
|
||||||
echo "renderLeftNavigation('ERP');";
|
echo "renderLeftNavigation('ERP');";
|
||||||
echo '</script>';
|
echo '</script>';
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ function render_auth_login_page(array $state): void
|
|||||||
echo '<link rel="stylesheet" href="/assets/styles.css">';
|
echo '<link rel="stylesheet" href="/assets/styles.css">';
|
||||||
echo '</head>';
|
echo '</head>';
|
||||||
echo '<body class="sg-vsf-register-step-1-page">';
|
echo '<body class="sg-vsf-register-step-1-page">';
|
||||||
|
echo '<script src="/scripts/help-icon-overlays.js"></script>';
|
||||||
|
|
||||||
echo '<main class="sg-vsf-register-step-1">';
|
echo '<main class="sg-vsf-register-step-1">';
|
||||||
echo '<article class="sg-card sg-object-card sg-object-card--variable-height sg-vsf-register-step-1__card" data-pattern="object-card" aria-label="Anmeldung">';
|
echo '<article class="sg-card sg-object-card sg-object-card--variable-height sg-vsf-register-step-1__card" data-pattern="object-card" aria-label="Anmeldung">';
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
(function initHelpIconOverlayModule() {
|
||||||
|
const CLOSE_HANDLERS = {
|
||||||
|
'.sg-pulldown-demo': (root) => {
|
||||||
|
root.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
|
||||||
|
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
|
||||||
|
demo.dataset.open = 'false';
|
||||||
|
if (trigger) {
|
||||||
|
trigger.setAttribute('aria-expanded', 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'.sg-sandwich-menu-wrap': (root) => {
|
||||||
|
root.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
|
||||||
|
const button = wrap.querySelector('.sg-sandwich-button');
|
||||||
|
wrap.dataset.open = 'false';
|
||||||
|
if (button) {
|
||||||
|
button.setAttribute('aria-expanded', 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const getViewportWidth = () => {
|
||||||
|
if (window.visualViewport && typeof window.visualViewport.width === 'number') {
|
||||||
|
return window.visualViewport.width;
|
||||||
|
}
|
||||||
|
return window.innerWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getViewportHeight = () => {
|
||||||
|
if (window.visualViewport && typeof window.visualViewport.height === 'number') {
|
||||||
|
return window.visualViewport.height;
|
||||||
|
}
|
||||||
|
return window.innerHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSafeInsetPx = () => {
|
||||||
|
const rootStyles = getComputedStyle(document.documentElement);
|
||||||
|
const spacingSmallRaw = rootStyles.getPropertyValue('--spacing-small').trim();
|
||||||
|
const rootFontSize = parseFloat(rootStyles.fontSize) || 16;
|
||||||
|
const spacingSmallValue = parseFloat(spacingSmallRaw);
|
||||||
|
if (Number.isNaN(spacingSmallValue)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (spacingSmallRaw.endsWith('rem')) {
|
||||||
|
return spacingSmallValue * rootFontSize;
|
||||||
|
}
|
||||||
|
return spacingSmallValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeAllHelpIcons = (root) => {
|
||||||
|
root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
|
||||||
|
const button = wrap.querySelector('.sg-help-icon');
|
||||||
|
const panel = wrap.querySelector('.sg-help-icon-panel');
|
||||||
|
wrap.dataset.open = 'false';
|
||||||
|
if (panel) {
|
||||||
|
panel.style.removeProperty('transform');
|
||||||
|
panel.style.removeProperty('max-height');
|
||||||
|
panel.style.removeProperty('overflow-y');
|
||||||
|
}
|
||||||
|
if (button) {
|
||||||
|
button.setAttribute('aria-expanded', 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const positionHelpPanel = (wrap, panel) => {
|
||||||
|
wrap.dataset.align = 'left';
|
||||||
|
wrap.dataset.vertical = 'bottom';
|
||||||
|
panel.style.removeProperty('transform');
|
||||||
|
panel.style.removeProperty('max-height');
|
||||||
|
panel.style.removeProperty('overflow-y');
|
||||||
|
|
||||||
|
const viewportWidth = getViewportWidth();
|
||||||
|
const panelRect = panel.getBoundingClientRect();
|
||||||
|
if (panelRect.right > viewportWidth) {
|
||||||
|
wrap.dataset.align = 'right';
|
||||||
|
}
|
||||||
|
const alignedPanelRect = panel.getBoundingClientRect();
|
||||||
|
if (alignedPanelRect.left < 0) {
|
||||||
|
wrap.dataset.align = 'left';
|
||||||
|
}
|
||||||
|
|
||||||
|
const clampedRect = panel.getBoundingClientRect();
|
||||||
|
const safeInset = getSafeInsetPx();
|
||||||
|
let shiftX = 0;
|
||||||
|
if (clampedRect.right > (viewportWidth - safeInset)) {
|
||||||
|
shiftX -= clampedRect.right - (viewportWidth - safeInset);
|
||||||
|
}
|
||||||
|
if ((clampedRect.left + shiftX) < safeInset) {
|
||||||
|
shiftX += safeInset - (clampedRect.left + shiftX);
|
||||||
|
}
|
||||||
|
if (shiftX !== 0) {
|
||||||
|
panel.style.transform = `translateX(${shiftX}px)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewportHeight = getViewportHeight();
|
||||||
|
const verticalSafeInset = getSafeInsetPx();
|
||||||
|
const bottomRect = panel.getBoundingClientRect();
|
||||||
|
if (bottomRect.bottom > (viewportHeight - verticalSafeInset)) {
|
||||||
|
wrap.dataset.vertical = 'top';
|
||||||
|
const topRect = panel.getBoundingClientRect();
|
||||||
|
if (topRect.top < verticalSafeInset) {
|
||||||
|
const wrapRect = wrap.getBoundingClientRect();
|
||||||
|
const spaceAbove = Math.max(0, wrapRect.top - verticalSafeInset);
|
||||||
|
const spaceBelow = Math.max(0, viewportHeight - verticalSafeInset - wrapRect.bottom);
|
||||||
|
const useTop = spaceAbove >= spaceBelow;
|
||||||
|
wrap.dataset.vertical = useTop ? 'top' : 'bottom';
|
||||||
|
const availableHeight = Math.max(96, Math.floor((useTop ? spaceAbove : spaceBelow) - verticalSafeInset));
|
||||||
|
panel.style.maxHeight = `${availableHeight}px`;
|
||||||
|
panel.style.overflowY = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.sgInitHelpIconOverlays = (options = {}) => {
|
||||||
|
const root = options.root || document;
|
||||||
|
const closeOnOpenSelectors = options.closeOnOpenSelectors || [];
|
||||||
|
const outsideClickIgnoreSelectors = options.outsideClickIgnoreSelectors || [];
|
||||||
|
|
||||||
|
root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
|
||||||
|
if (wrap.dataset.helpIconInit === 'true') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wrap.dataset.helpIconInit = 'true';
|
||||||
|
|
||||||
|
const button = wrap.querySelector('.sg-help-icon');
|
||||||
|
const panel = wrap.querySelector('.sg-help-icon-panel');
|
||||||
|
if (!button || !panel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.addEventListener('click', (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
const nextState = wrap.dataset.open !== 'true';
|
||||||
|
|
||||||
|
closeAllHelpIcons(root);
|
||||||
|
closeOnOpenSelectors.forEach((selector) => {
|
||||||
|
const handler = CLOSE_HANDLERS[selector];
|
||||||
|
if (handler) {
|
||||||
|
handler(root);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!nextState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap.dataset.open = 'true';
|
||||||
|
button.setAttribute('aria-expanded', 'true');
|
||||||
|
positionHelpPanel(wrap, panel);
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
if (wrap.dataset.open === 'true') {
|
||||||
|
positionHelpPanel(wrap, panel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const refreshOpenPanels = () => {
|
||||||
|
root.querySelectorAll('.sg-help-icon-wrap[data-open="true"]').forEach((wrap) => {
|
||||||
|
const panel = wrap.querySelector('.sg-help-icon-panel');
|
||||||
|
if (panel) {
|
||||||
|
positionHelpPanel(wrap, panel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!window.sgHelpIconOverlayResizeBound) {
|
||||||
|
window.addEventListener('resize', refreshOpenPanels);
|
||||||
|
if (window.visualViewport && typeof window.visualViewport.addEventListener === 'function') {
|
||||||
|
window.visualViewport.addEventListener('resize', refreshOpenPanels);
|
||||||
|
}
|
||||||
|
window.sgHelpIconOverlayResizeBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('click', (event) => {
|
||||||
|
const isInsideIgnoredZone = ['.sg-help-icon-wrap', ...outsideClickIgnoreSelectors]
|
||||||
|
.some((selector) => event.target.closest(selector));
|
||||||
|
if (isInsideIgnoredZone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeAllHelpIcons(root);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user