// Bootstrap helpers
(() => {
'use strict';
// 1) Show Flask flash messages as Bootstrap toasts
const flashes = document.getElementById('_flash_msgs');
if (flashes) {
try{
const msgs = JSON.parse(flashes.dataset.msgs || "[]");
const stack = document.getElementById('toast-stack');
msgs.forEach((m) => {
const el = document.createElement('div');
el.className = 'toast align-items-center text-bg-primary border-0';
el.role = 'alert'; el.ariaLive = 'assertive'; el.ariaAtomic = 'true';
el.innerHTML = `
`;
stack.appendChild(el);
const t = new bootstrap.Toast(el, { delay: 3500 });
t.show();
});
}catch(e){ console.warn('Toast parse error', e); }
}
// 2) Client-side validation (Bootstrap)
const forms = document.querySelectorAll('form');
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
} else {
// 3) Micro-loader on submit
const submitBtn = form.querySelector('[type="submit"]');
if (submitBtn && !submitBtn.dataset.loading) {
submitBtn.dataset.loading = '1';
submitBtn.disabled = true;
const original = submitBtn.innerHTML;
submitBtn.dataset.original = original;
submitBtn.innerHTML = ` Przetwarzanie...`;
}
}
form.classList.add('was-validated');
}, false);
});
// 4) Auto-accordion for long forms:
// If a form contains multiple H2/H3 sections, group content between them.
const targetForms = document.querySelectorAll('form');
targetForms.forEach(form => {
const headers = Array.from(form.querySelectorAll(':scope h2, :scope h3')).filter(h => h.textContent.trim().length>0);
if (headers.length >= 2) {
const acc = document.createElement('div');
acc.className = 'accordion my-3'; acc.id = 'autoAccordion-' + Math.random().toString(36).slice(2);
let startIdx = 0;
headers.forEach((h, i) => {
const itemId = acc.id + '-item-' + i;
const headerId = itemId + '-hdr';
const bodyId = itemId + '-body';
const item = document.createElement('div'); item.className = 'accordion-item bg-body';
const btnText = h.textContent.trim();
// gather content until next header or end
const chunk = [];
let el = h.nextElementSibling;
while (el && !headers.includes(el)) {
chunk.push(el);
el = el.nextElementSibling;
}
h.remove();
const bodyInner = document.createElement('div');
chunk.forEach(c => bodyInner.appendChild(c));
item.innerHTML = `
`;
item.querySelector('.accordion-body').appendChild(bodyInner);
acc.appendChild(item);
});
// Insert at top of form
form.prepend(acc);
}
});
// Focus first control
const first = document.querySelector('form input, form select, form textarea');
if (first) first.focus({preventScroll:true});
})();