90 lines
2.8 KiB
JavaScript
90 lines
2.8 KiB
JavaScript
function createRequiredProgress({ container, progress, onChange }) {
|
|
let total = 0;
|
|
let filled = 0;
|
|
|
|
const body = typeof container === 'string'
|
|
? document.querySelector(container)
|
|
: container;
|
|
|
|
const progressEl = typeof progress === 'string'
|
|
? document.querySelector(progress)
|
|
: progress;
|
|
|
|
if (!body || !progressEl) return;
|
|
|
|
function isElementVisible(el) {
|
|
const style = window.getComputedStyle(el);
|
|
return el.offsetParent !== null && style.opacity !== '0';
|
|
}
|
|
|
|
function updateRequiredProgress() {
|
|
const requiredElements = Array.from(
|
|
body.querySelectorAll('input[required], select[required], textarea[required]')
|
|
).filter(isElementVisible);
|
|
|
|
total = requiredElements.length;
|
|
filled = requiredElements.filter(el =>
|
|
el.classList.contains('is-required-filled')
|
|
).length;
|
|
|
|
progressEl.textContent = `${filled} / ${total} Pflichtfelder ausgefüllt`;
|
|
progressEl.classList.toggle('complete', filled === total);
|
|
progressEl.classList.toggle('incomplete', filled !== total);
|
|
}
|
|
|
|
function updateRequiredState(el) {
|
|
const isEmpty =
|
|
(el instanceof HTMLSelectElement && !el.value) ||
|
|
(el instanceof HTMLInputElement && el.type !== 'checkbox' && !el.value.trim()) ||
|
|
(el instanceof HTMLTextAreaElement && !el.value.trim());
|
|
|
|
el.classList.toggle('is-required-empty', isEmpty);
|
|
el.classList.toggle('is-required-filled', !isEmpty);
|
|
|
|
updateRequiredProgress();
|
|
|
|
if (typeof onChange === 'function') {
|
|
onChange({
|
|
element: el,
|
|
isEmpty,
|
|
isFilled: !isEmpty,
|
|
isFinished: total === filled
|
|
});
|
|
}
|
|
}
|
|
|
|
function initialize() {
|
|
const elements = Array.from(
|
|
body.querySelectorAll('input[required], select[required], textarea[required]')
|
|
).filter(isElementVisible);
|
|
|
|
elements.forEach(el => {
|
|
updateRequiredState(el);
|
|
|
|
el.addEventListener('input', () => updateRequiredState(el));
|
|
el.addEventListener('change', () => updateRequiredState(el));
|
|
});
|
|
|
|
updateRequiredProgress();
|
|
}
|
|
|
|
// 🔥 Reagiere auf Sichtbarkeitsänderungen
|
|
const observer = new MutationObserver(updateRequiredProgress);
|
|
observer.observe(body, {
|
|
attributes: true,
|
|
subtree: true,
|
|
attributeFilter: ['style', 'class', 'hidden']
|
|
});
|
|
|
|
initialize();
|
|
|
|
// Optional: API zurückgeben
|
|
return {
|
|
initialize: initialize,
|
|
refresh: updateRequiredProgress,
|
|
destroy() {
|
|
observer.disconnect();
|
|
}
|
|
};
|
|
}
|