forked from fa/breadcrumb-the-shire
- Remove 2079 unused bootstrap-icons SVGs + min.css (~9.3 MB saved, app uses font approach only) - Remove unused editorjs.umd.js (only .mjs is imported) - Extract shared syncControlState into app-conditional-controls.js, deduplicate SSO/LDAP toggles - Add settingToBool() helper to DRY up repeated bool-parsing pattern across 6 call sites - Merge single-function auth.php into app.php, delete auth.php - Extract 9 branding functions from app.php into dedicated branding.php (app.php 709→528 lines) - Remove empty web/img/ directory Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
2.8 KiB
JavaScript
91 lines
2.8 KiB
JavaScript
/**
|
|
* 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 };
|
|
};
|