Files
Personal-Website/client/js/admin.js
T
2026-10-25 20:29:26 +01:00

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, '');
});
}