const _ = undefined // Select elements with the given selector const _$ = (s, e = document, a = true) => { const r = Array.from(e.querySelectorAll(s)); return a ? r : r[0]; } // Selects an element with the given id const id = s => document.getElementById(s); // Debounce utility const debounce = (f, t = 200) => { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(f, t, ...args); }; } // Returns the data received after a GET request const get = u => fetch(u).then(r => r.json()).catch(e => notify(e, 'danger')) // Returns the data received after a POST request const post = (u, d) => fetch(u, { method: 'POST', body: new FormData(d) }).then(r => r.json()).catch(e => notify(e, 'danger')) // Creates a new element const element = (t = 'template', c = [], h = '') => { const e = document.createElement(t); e.classList.add(...c); e.innerHTML = h; return e; } // Add a delete button to the given element const addDelete = e => { const b = element('button', ["delete"]); b.addEventListener('click', () => e.remove()); e.appendChild(b); } // Send a notification const notify = (m, c) => { const n = element('div', ['notification'], `${m}`); c ? n.classList.add(`is-${c}`) : _; id('notifications').insertBefore(n, id('notifications').firstChild) addDelete(n); setTimeout(() => { n.classList.add('fade-out'); setTimeout(() => n.remove(), 1000) }, 5000); } // Add a listener to remove the target const remove = d => d.addEventListener('click', () => { get(d.dataset.url).then(r => { if (r.success && r.action === 'delete') { id(d.dataset.target).remove() } r.message ? notify(r.message.content, r.message.class) : _; }); }) const openModal = b => b.addEventListener('click', () => { const m = id(b.dataset.target); if ('post_url' in b.dataset) { _$('form', m, false).action = b.dataset.post_url; }; if ('title' in b.dataset) { _$('.modal-card-title', m, false).innerHTML = b.dataset.title; }; document.documentElement.classList.add('is-clipped'); m.classList.add('is-active'); }) const closeModal = b => b.addEventListener('click', () => { document.documentElement.classList.remove('is-clipped'); id(b.dataset.closes).classList.remove('is-active') }) // Add error to input const addError = (i, e) => { const s = element('span', ['help', 'is-danger'], e); i.classList.add('is-danger'); i.insertAdjacentElement('afterend', s); }; // Remove error from input const removeError = i => { i.classList.remove('is-danger'); _$('span.help.is-danger', i.parentNode).forEach(e => e.remove()); } // Form autofill const autoFill = (d, f) => { for (const [k, v] of Object.entries(d)) { const fd = _$(`[name='${k}']`, f, false); if (typeof(v) === 'boolean') { fd.checked = v; } else { if (fd.value !== undefined) { fd.value = v; } else { fd.innerHTML = v; } } } } const initForm = b => b.addEventListener('click', () => { const f = _$('form', id(b.dataset.target), false); if (!f) { return; } f.dataset.next = b.dataset.next; f.dataset.origin = b.dataset.parent f.dataset.modal = b.dataset.target; _$('input,select', f).forEach(removeError); b.dataset.json ? autoFill(JSON.parse(b.dataset.json), f) : _; if (b.dataset.json_url) { f.classList.add('is-loading'); get(b.dataset.json_url).then(r => { if (r.success) { autoFill(r.data, f); f.classList.remove('is-loading'); } }); } }) // Form submission const submitForm = (f, i, s) => f.addEventListener('submit', event => { event.preventDefault(); event.submitter.classList.add('is-loading'); post(f.action, f).then(r => { event.submitter.classList.remove('is-loading'); // On enlève les erreurs _$('input,select', f).forEach(removeError); if (r.success) { // On crée le résultat const e = element('template', [], r.html).content; i(f, e); switch (r.action) { case 'create': id(f.dataset.next).appendChild(e); break; case 'update': const n = id(f.dataset.origin); n.parentNode.replaceChild(e, n); break; case 'delete': id(f.dataset.origin).remove(); break; } // On ferme le modal if (f.dataset.modal) { document.documentElement.classList.remove('is-clipped'); id(f.dataset.modal).classList.remove('is-active'); } } else { for (const [n, e] of Object.entries(r.errors)) { if (n === '__all__') { e.forEach(m => notify(m, 'danger')); } else { addError(_$(`[name='${n}']`, f, false), e); } } } s ? s(r) : _; // On affiche un message si besoin r.message.content ? notify(r.message.content, r.message.class) : _; }); }) // Modal initialisation const initModal = (f, e) => { _$('.modal-button', e).forEach(openModal); _$('.modal-button[json],.modal-button[json_url]', e).forEach(initForm); } // Element deletion const _dt = (d, f) => d.addEventListener('click', () => { get(d.dataset.url).then(r => { if (r.success && r.action == 'delete') { id(d.dataset.target).remove(); f ? f() : _; } r.message ? notify(r.message.content, r.message.class) : _; }); }) // Pluralization const pluralize = (s, n) => n == 1 ? s : `${s}s`