big restructure
This commit is contained in:
98
web/js/components/app-multiselect-cascade.js
Normal file
98
web/js/components/app-multiselect-cascade.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import { getMultiSelectInstance } from './app-multiselect-init.js';
|
||||
import { warnOnce } from '../core/app-dom.js';
|
||||
|
||||
const parseValueList = (value) =>
|
||||
String(value || '')
|
||||
.split(',')
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const setDisabledState = (option, disabled) => {
|
||||
option.dataset.disabled = disabled ? '1' : '0';
|
||||
option.classList.toggle('is-disabled', disabled);
|
||||
option.setAttribute('aria-disabled', disabled ? 'true' : 'false');
|
||||
option.style.pointerEvents = disabled ? 'none' : '';
|
||||
if (!option._cascadeGuard) {
|
||||
option.addEventListener(
|
||||
'click',
|
||||
(event) => {
|
||||
if (option.dataset.disabled === '1') {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
option._cascadeGuard = true;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSelectAll = (instance, disabled) => {
|
||||
const selectAll = instance?.element?.querySelector('.multi-select-all');
|
||||
if (!selectAll) return;
|
||||
selectAll.classList.toggle('is-disabled', disabled);
|
||||
selectAll.setAttribute('aria-disabled', disabled ? 'true' : 'false');
|
||||
selectAll.style.pointerEvents = disabled ? 'none' : '';
|
||||
};
|
||||
|
||||
export const initMultiSelectCascade = ({
|
||||
parent,
|
||||
child,
|
||||
map = {},
|
||||
mode = 'disable',
|
||||
clearInvalid = true,
|
||||
}) => {
|
||||
const parentInput = typeof parent === 'string' ? document.querySelector(parent) : parent;
|
||||
const childInput = typeof child === 'string' ? document.querySelector(child) : child;
|
||||
if (!parentInput || !childInput) {
|
||||
if (!parentInput) {
|
||||
warnOnce('UI_EL_MISSING', `Missing multiselect parent: ${parent}`, { module: 'multiselect-cascade' });
|
||||
}
|
||||
if (!childInput) {
|
||||
warnOnce('UI_EL_MISSING', `Missing multiselect child: ${child}`, { module: 'multiselect-cascade' });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const childInstance = getMultiSelectInstance(childInput);
|
||||
if (!childInstance) {
|
||||
warnOnce('UI_INIT_MISSING', 'Missing multiselect instance for child', { module: 'multiselect-cascade' });
|
||||
return;
|
||||
}
|
||||
|
||||
const apply = () => {
|
||||
const selectedParents = parseValueList(parentInput.value);
|
||||
const allowAll = selectedParents.length === 0;
|
||||
const allowed = new Set();
|
||||
|
||||
if (!allowAll) {
|
||||
selectedParents.forEach((id) => {
|
||||
const entries = map[id] || [];
|
||||
entries.forEach((entry) => allowed.add(String(entry)));
|
||||
});
|
||||
}
|
||||
|
||||
if (clearInvalid && !allowAll) {
|
||||
const selected = childInstance.selectedValues || [];
|
||||
selected.forEach((value) => {
|
||||
if (!allowed.has(String(value))) {
|
||||
childInstance.unselect(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const options = childInstance.element.querySelectorAll('.multi-select-option');
|
||||
let disabledCount = 0;
|
||||
options.forEach((option) => {
|
||||
const isAllowed = allowAll || allowed.has(String(option.dataset.value || ''));
|
||||
const disabled = mode === 'disable' ? !isAllowed : false;
|
||||
if (disabled) disabledCount += 1;
|
||||
setDisabledState(option, disabled);
|
||||
});
|
||||
|
||||
toggleSelectAll(childInstance, disabledCount > 0);
|
||||
};
|
||||
|
||||
parentInput.addEventListener('change', apply);
|
||||
apply();
|
||||
};
|
||||
Reference in New Issue
Block a user