/** * Shared utilities for conditional-controls toggles. * * Several components follow the same pattern: a checkbox enables/disables * a block of form controls. This module centralises that logic so * individual toggles (SSO, LDAP, …) only contain their domain-specific * wiring. */ import { resolveHost } from './app-dom.js'; /** * Show or hide a container and sync the disabled state of all nested * form controls. Controls that were already disabled before the first * toggle are kept disabled regardless of the toggle state. * * @param {Element|null} container * @param {boolean} show */ export const syncControlState = (container, show) => { if (!(container instanceof HTMLElement)) { return; } container.hidden = !show; container.querySelectorAll('input, select, textarea, button').forEach((control) => { if ((control instanceof HTMLInputElement) && control.type === 'hidden') { return; } if (!control.dataset.initialDisabled) { control.dataset.initialDisabled = control.hasAttribute('disabled') ? '1' : '0'; } if (!show) { control.setAttribute('disabled', 'disabled'); return; } if (control.dataset.initialDisabled === '1') { control.setAttribute('disabled', 'disabled'); return; } control.removeAttribute('disabled'); }); }; /** * Create a reusable init function for conditional-controls toggles. * * The returned function matches the component-runtime signature * `init(root, options) → { destroy }` so it can be registered directly. * * @param {object} config * @param {string} config.rootSelector CSS selector for root elements * @param {string} config.boundKey dataset key to track bound state (camelCase) * @param {function} config.initRoot (rootElement) → cleanup function | null * @returns {function} init(root, options) → { destroy } */ export const createConditionalToggleInit = (config) => function init(root = document, options = {}) { const host = resolveHost(root); const selector = String(options.selector || config.rootSelector).trim() || config.rootSelector; const roots = Array.from(host.querySelectorAll(selector)); if (!roots.length) { return { destroy: () => {} }; } const cleanupFns = []; roots.forEach((item) => { if (!(item instanceof HTMLElement) || item.dataset[config.boundKey] === '1') { return; } item.dataset[config.boundKey] = '1'; const cleanup = config.initRoot(item); if (typeof cleanup === 'function') { cleanupFns.push(cleanup); } cleanupFns.push(() => { delete item.dataset[config.boundKey]; }); }); const destroy = () => { cleanupFns.forEach((cleanup) => cleanup()); }; return { destroy }; };