import { apiAction, apiUpdate, toast } from './api.js';
function esc(s = '') {
return String(s)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function normalizeApiName(v = '') {
return String(v)
.trim()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^a-z0-9_-]+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
}
async function fetchContentList(sectionId) {
const res = await apiAction('content.list', { method: 'GET', data: { section_id: sectionId } });
return Array.isArray(res?.items) ? res.items : [];
}
async function fetchContentItem(id, sectionId) {
return await apiAction('content.get', { method: 'GET', data: { id, section_id: sectionId } });
}
async function openContentEditor(item, section) {
const id = Number(item?.id || 0);
const name = item?.name || '';
if (!id) return;
const detail = await fetchContentItem(id, section.id).catch(() => ({}));
const html = detail?.html ?? detail?.item?.html ?? detail?.content ?? '';
window.__currentItemId = id;
window.__currentEditorCtx = { id, mode: section.slug, section };
if (window.EditorUI && typeof window.EditorUI.open === 'function') {
window.EditorUI.open({ id, name, html, section }, 'content');
} else if (window.__openEditor) {
window.__openEditor({ resource: 'content', id, name, html, section });
} else {
toast('Editor ist nicht initialisiert.', false);
}
}
async function openTemplateEditor(item, section) {
const dlg = document.getElementById('editTemplateDialog');
const form = document.getElementById('editTemplateForm');
const inpName = document.getElementById('edit_tpl_name');
const inpApiName = document.getElementById('edit_tpl_api_name');
const apiWarn = document.getElementById('edit_tpl_api_warn');
const btnCancel = document.getElementById('editTemplateCancel');
const detail = await fetchContentItem(item.id, section.id).catch(() => ({}));
const row = detail?.item || detail?.data || detail || {};
const initialApi = row.api_name || '';
if (inpName) inpName.value = row.name || '';
if (inpApiName) inpApiName.value = initialApi;
if (apiWarn) apiWarn.classList.add('hidden');
const onApiInput = () => {
if (!inpApiName) return;
const next = normalizeApiName(inpApiName.value);
if (next !== inpApiName.value) inpApiName.value = next;
if (apiWarn) {
apiWarn.classList.toggle('hidden', inpApiName.value.trim() === initialApi);
}
};
function cleanup() {
form && form.removeEventListener('submit', onSubmit);
btnCancel && (btnCancel.onclick = null);
inpApiName && inpApiName.removeEventListener('input', onApiInput);
}
async function onSubmit(ev) {
ev.preventDefault();
try {
const res = await apiUpdate('content', item.id, {
name: inpName ? inpName.value : '',
api_name: inpApiName ? inpApiName.value : '',
section_id: section.id,
});
toast(res && res.ok ? 'Template gespeichert' : 'Speichern fehlgeschlagen', !!(res && res.ok));
dlg && dlg.close();
cleanup();
if (typeof window.loadList === 'function') window.loadList(section);
} catch {
toast('Speichern fehlgeschlagen', false);
}
}
inpApiName && inpApiName.addEventListener('input', onApiInput);
form && form.addEventListener('submit', onSubmit, { once: false });
btnCancel && (btnCancel.onclick = () => { dlg && dlg.close(); cleanup(); });
dlg && dlg.showModal();
}
export async function loadList(section) {
const el = document.getElementById('view-content');
if (typeof section === 'string') {
const sections = window.__sectionsConfig || [];
section = sections.find(s => String(s.slug || '').toLowerCase() === section.toLowerCase())
|| sections.find(s => String(s.name || '').toLowerCase() === section.toLowerCase())
|| null;
} else if (typeof section === 'number') {
const sections = window.__sectionsConfig || [];
section = sections.find(s => Number(s.id) === section) || null;
}
section = section || window.__activeSection || null;
if (!el || !section) return;
const label = section.name || 'Section';
const isTemplate = Number(section.is_template) === 1;
el.innerHTML = `
`;
let data = [];
try {
data = await fetchContentList(section.id);
} catch (err) {
list.innerHTML = `${esc(err.message || 'Laden fehlgeschlagen')}
`;
return;
}
const list = el.querySelector('#list-section');
const filterInput = el.querySelector('#filter-section');
const filterReset = el.querySelector('#filter-section-reset');
const sortSelect = el.querySelector('#sort-section');
if (!Array.isArray(data) || data.length === 0) {
list.innerHTML = `Keine Einträge
`;
return;
}
const sortDefault = (window.__listSortDefault || 'created_asc');
if (sortSelect) sortSelect.value = sortDefault;
function compareByName(a, b) {
const av = String(a?.name || '');
const bv = String(b?.name || '');
return av.localeCompare(bv, undefined, { numeric: true, sensitivity: 'base' });
}
function parseDate(value) {
const t = Date.parse(value || '');
return Number.isFinite(t) ? t : 0;
}
function sortItems(items, key) {
const listCopy = items.slice();
if (key === 'name_asc') {
return listCopy.sort(compareByName);
}
if (key === 'name_desc') {
return listCopy.sort((a, b) => compareByName(b, a));
}
if (key === 'updated_desc') {
return listCopy.sort((a, b) => parseDate(b.updated_at) - parseDate(a.updated_at));
}
return listCopy.sort((a, b) => parseDate(a.created_at) - parseDate(b.created_at));
}
function matchesQuery(item, query) {
if (!query) return true;
const q = query.toLowerCase();
const name = String(item?.name || '').toLowerCase();
const api = isTemplate ? String(item?.api_name || '').toLowerCase() : '';
return name.includes(q) || (api && api.includes(q));
}
function render(items) {
list.innerHTML = items.map(item => {
const name = esc(item.name || '');
const apiName = isTemplate ? esc(item.api_name || '') : '';
const apiLine = (isTemplate && apiName) ? `API: ${apiName}
` : '';
const nameCell = `
${name || '(ohne Name)'}
${apiLine}
`;
const openBtn = ``;
const editTplBtn = isTemplate ? `` : '';
const testBtn = isTemplate ? `` : '';
const prevBtn = ``;
const delBtn = ``;
return `
${nameCell}
#${item.id}
${[openBtn, editTplBtn, testBtn, prevBtn, delBtn].filter(Boolean).join('')}
`;
}).join('');
bindListHandlers(list);
}
function applyFilter() {
const query = (filterInput?.value || '').trim();
const sortKey = sortSelect?.value || sortDefault;
const filtered = data.filter(item => matchesQuery(item, query));
const sorted = sortItems(filtered, sortKey);
render(sorted);
}
async function persistSort(nextValue) {
window.__listSortDefault = nextValue;
try {
await apiAction('account.settings.update', { method: 'POST', data: { list_sort: nextValue } });
} catch {}
}
if (filterInput) filterInput.addEventListener('input', applyFilter);
if (filterReset) {
filterReset.addEventListener('click', () => {
if (filterInput) {
filterInput.value = '';
filterInput.focus();
}
applyFilter();
});
}
if (sortSelect) {
sortSelect.addEventListener('change', () => {
const next = sortSelect.value || sortDefault;
persistSort(next);
applyFilter();
});
}
applyFilter();
function bindListHandlers(scope) {
scope.querySelectorAll('[data-open]').forEach(btn => btn.addEventListener('click', () => {
const id = Number(btn.dataset.open || 0);
const item = data.find(it => Number(it.id) === id);
if (!item) return;
openContentEditor(item, section);
}));
scope.querySelectorAll('[data-edit]').forEach(btn => btn.addEventListener('click', () => {
const id = Number(btn.dataset.edit || 0);
const item = data.find(it => Number(it.id) === id);
if (item) openTemplateEditor(item, section);
}));
const prevDlg = document.getElementById('previewDialog');
const prevFrame = document.getElementById('previewFrame');
scope.querySelectorAll('[data-preview]').forEach(btn => btn.addEventListener('click', async () => {
const id = Number(btn.dataset.preview || 0);
const obj = await fetchContentItem(id, section.id);
const html = (obj?.html || obj?.content || '(leer)');
prevFrame.srcdoc = '' + html + '';
prevDlg.showModal();
}));
scope.querySelectorAll('[data-test]').forEach(btn => btn.addEventListener('click', () => {
const id = Number(btn.dataset.test || 0);
const nm = btn.dataset.name || '';
if (!id) {
toast('Testversand: Ungültige ID', false);
return;
}
if (window.AdminTestSend && typeof window.AdminTestSend.open === 'function') {
window.AdminTestSend.open({ id, name: nm });
} else {
toast('Testversand ist aktuell nicht verfügbar.', false);
}
}));
const delDlg = document.getElementById('deleteDialog');
const delText = document.getElementById('deleteText');
const delForm = document.getElementById('deleteForm');
const delCancel = document.getElementById('deleteCancel');
let pending = null;
delCancel && (delCancel.onclick = () => { pending = null; delDlg.close(); });
scope.querySelectorAll('[data-del]').forEach(btn => btn.addEventListener('click', () => {
const id = Number(btn.dataset.del || 0);
const nm = btn.dataset.name || '';
pending = { id, name: nm };
if (delText) {
delText.innerHTML = `Soll ${nm || '(ohne Name)'} #${id} wirklich gelöscht werden?`;
}
delDlg.showModal();
}));
delForm && (delForm.onsubmit = async (ev) => {
ev.preventDefault();
if (!pending) return delDlg.close();
const res = await apiAction('content.delete', { method: 'POST', data: { id: pending.id, section_id: section.id } });
delDlg.close();
toast(res && res.ok ? 'Gelöscht' : 'Löschen fehlgeschlagen', !!(res && res.ok), { duration: 3000 });
loadList(section);
});
}
}
export function initLists() {
if (window.__sectionsReady && typeof window.__sectionsReady.then === 'function') {
window.__sectionsReady.then(() => {
if (window.__activeSection) loadList(window.__activeSection);
});
} else if (window.__activeSection) {
loadList(window.__activeSection);
}
window.__reloadList = loadList;
window.loadList = loadList;
}