66 lines
2.4 KiB
JavaScript
66 lines
2.4 KiB
JavaScript
// Repeated rows (links, timeline entries, services ...) can be added, removed and moved.
|
|
// Their fields use "#" as index placeholder in data-name, the real names are set on submit.
|
|
|
|
document.addEventListener('click', (event) => {
|
|
const button = event.target.closest('[data-repeat-add], [data-repeat-remove], [data-repeat-up], [data-repeat-down]');
|
|
if (!button) return;
|
|
|
|
if (button.hasAttribute('data-repeat-add')) {
|
|
const repeat = button.closest('[data-repeat]');
|
|
const template = repeat.querySelector(':scope > template[data-repeat-template]');
|
|
const list = repeat.querySelector(':scope > [data-repeat-list]');
|
|
list.append(template.content.cloneNode(true));
|
|
list.lastElementChild?.querySelector('input:not([type="hidden"]), textarea, select')?.focus();
|
|
return;
|
|
}
|
|
|
|
const row = button.closest('[data-repeat-row]');
|
|
if (button.hasAttribute('data-repeat-remove')) row.remove();
|
|
else if (button.hasAttribute('data-repeat-up')) row.previousElementSibling?.before(row);
|
|
else row.nextElementSibling?.after(row);
|
|
});
|
|
|
|
function rowIndexes(field) {
|
|
const indexes = [];
|
|
for (let row = field.closest('[data-repeat-row]'); row; row = row.parentElement.closest('[data-repeat-row]')) {
|
|
const siblings = [...row.parentElement.children].filter((el) => el.matches('[data-repeat-row]'));
|
|
indexes.unshift(siblings.indexOf(row));
|
|
}
|
|
return indexes;
|
|
}
|
|
|
|
document.addEventListener('submit', (event) => {
|
|
const form = event.target;
|
|
if (form.dataset.confirm && !window.confirm(form.dataset.confirm)) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
for (const field of form.querySelectorAll('[data-name]')) {
|
|
const indexes = rowIndexes(field);
|
|
let i = 0;
|
|
field.name = field.dataset.name.replace(/#/g, () => indexes[i++] ?? 0);
|
|
}
|
|
});
|
|
|
|
// New project: fill the URL name from the German title until it is edited by hand
|
|
const slug = document.querySelector('[data-slug]');
|
|
const title = document.querySelector('[data-title]');
|
|
if (slug && title && !slug.value) {
|
|
let touched = false;
|
|
slug.addEventListener('input', () => (touched = true));
|
|
title.addEventListener('input', () => {
|
|
if (touched) return;
|
|
slug.value = title.value
|
|
.toLowerCase()
|
|
.replace(/ä/g, 'ae')
|
|
.replace(/ö/g, 'oe')
|
|
.replace(/ü/g, 'ue')
|
|
.replace(/ß/g, 'ss')
|
|
.normalize('NFKD')
|
|
.replace(/[̀-ͯ]/g, '')
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.slice(0, 60)
|
|
.replace(/^-+|-+$/g, '');
|
|
});
|
|
}
|