576 lines
23 KiB
JavaScript
576 lines
23 KiB
JavaScript
import { apiAction, apiUpdate, toast } from './api.js';
|
||
|
||
function esc(s = '') {
|
||
return String(s)
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(/"/g, '"')
|
||
.replace(/'/g, ''');
|
||
}
|
||
|
||
function formatVersionDate(value) {
|
||
if (!value) return '';
|
||
try {
|
||
const date = new Date(value);
|
||
if (Number.isNaN(date.getTime())) return value;
|
||
return date.toLocaleString('de-DE');
|
||
} catch {
|
||
return value;
|
||
}
|
||
}
|
||
|
||
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 versionId = Number(item?.version_id || 0);
|
||
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, version_id: versionId }, 'content');
|
||
} else if (window.__openEditor) {
|
||
window.__openEditor({ resource: 'content', id, name, html, section, version_id: versionId });
|
||
} else {
|
||
toast('Editor ist nicht initialisiert.', false);
|
||
}
|
||
}
|
||
|
||
async function openTemplateManager(item, section) {
|
||
const dlg = document.getElementById('manageTemplateDialog');
|
||
const inpName = document.getElementById('manage_tpl_name');
|
||
const inpApiName = document.getElementById('manage_tpl_api_name');
|
||
const apiWrap = document.getElementById('manage_tpl_api_wrap');
|
||
const apiWarn = document.getElementById('manage_tpl_api_warn');
|
||
const badge = document.getElementById('manage_tpl_badge');
|
||
const versionsWrap = document.getElementById('manage_tpl_versions');
|
||
const btnClose = document.getElementById('manageTemplateClose');
|
||
const btnDelete = document.getElementById('manageTemplateDelete');
|
||
const deleteHint = document.getElementById('manage_tpl_delete_hint');
|
||
const delDlg = document.getElementById('deleteDialog');
|
||
const delText = document.getElementById('deleteText');
|
||
const delForm = document.getElementById('deleteForm');
|
||
const delCancel = document.getElementById('deleteCancel');
|
||
|
||
const detail = await fetchContentItem(item.id, section.id).catch(() => ({}));
|
||
const row = detail?.item || detail?.data || detail || {};
|
||
const initialApi = row.api_name || '';
|
||
|
||
if (badge) badge.textContent = `ID ${item.id}`;
|
||
if (inpName) inpName.value = row.name || '';
|
||
if (inpApiName) inpApiName.value = initialApi;
|
||
if (apiWarn) apiWarn.classList.add('hidden');
|
||
if (apiWrap) apiWrap.classList.toggle('hidden', !section?.is_template);
|
||
|
||
let versions = [];
|
||
let activeId = 0;
|
||
|
||
const isTemplateSection = () => {
|
||
if (section?.is_template) return true;
|
||
const slug = (section?.slug || '').toString().toLowerCase();
|
||
return slug === 'emailtemplate' || slug.includes('template');
|
||
};
|
||
|
||
const fetchTemplateReferences = async () => {
|
||
if (!isTemplateSection()) return null;
|
||
const res = await apiAction('templates.references', { method: 'GET', data: { template_id: item.id } }).catch(() => null);
|
||
if (!res || res.ok === false) return null;
|
||
return Array.isArray(res?.references) ? res.references : [];
|
||
};
|
||
|
||
const confirmTemplateReferences = async (actionLabel) => {
|
||
if (!isTemplateSection()) return true;
|
||
const refs = await fetchTemplateReferences();
|
||
if (refs === null) {
|
||
return confirm(`Referenzen konnten nicht geprüft werden. ${actionLabel} trotzdem?`);
|
||
}
|
||
if (!refs.length) return true;
|
||
const preview = refs.slice(0, 6).map(r => `${r.name || 'Template'} #${r.id}`).join(', ');
|
||
const more = refs.length > 6 ? ` und ${refs.length - 6} weitere` : '';
|
||
return confirm(`Dieses Template wird in ${refs.length} anderen Template(s) verwendet (${preview}${more}). ${actionLabel} trotzdem?`);
|
||
};
|
||
|
||
const updateDeleteState = () => {
|
||
const hasActive = !!activeId;
|
||
if (btnDelete) btnDelete.disabled = hasActive;
|
||
if (deleteHint) {
|
||
deleteHint.textContent = hasActive
|
||
? 'Aktive Version vorhanden – Löschen deaktiviert.'
|
||
: 'Nur möglich, wenn keine aktive Version existiert.';
|
||
}
|
||
};
|
||
|
||
const loadVersions = async () => {
|
||
const res = await apiAction('content_versions.list', { method: 'GET', data: { content_id: item.id } }).catch(() => ({}));
|
||
versions = Array.isArray(res?.items) ? res.items : [];
|
||
activeId = 0;
|
||
versions.forEach(v => {
|
||
if (Number(v.is_active) === 1) activeId = Number(v.id || 0);
|
||
});
|
||
renderVersions();
|
||
updateDeleteState();
|
||
};
|
||
|
||
const renderVersions = () => {
|
||
if (!versionsWrap) return;
|
||
if (!versions.length) {
|
||
versionsWrap.innerHTML = '<div class=\"text-xs text-slate-500\">Keine Versionen vorhanden</div>';
|
||
return;
|
||
}
|
||
versionsWrap.innerHTML = versions.map(v => {
|
||
const isActive = Number(v.is_active) === 1;
|
||
const label = `${isActive ? '✓ ' : ''}#${v.version_no} – ${formatVersionDate(v.created_at)}` + (isActive ? ' (aktiv)' : '');
|
||
const deleteBtn = isActive ? '' : `<button class=\"btn btn-danger\" data-version-delete=\"${v.id}\">Löschen</button>`;
|
||
return `<div class=\"flex items-center gap-2 border rounded-lg px-3 py-2\" data-version-row=\"${v.id}\">
|
||
<div class=\"text-xs text-slate-600\">${label}</div>
|
||
<div class=\"ms-auto flex gap-2\">
|
||
<button class=\"btn\" data-version-edit=\"${v.id}\">Bearbeiten</button>
|
||
${isActive ? `<button class=\"btn\" data-version-deactivate=\"${v.id}\">Deaktivieren</button>` : `<button class=\"btn\" data-version-activate=\"${v.id}\">Aktivieren</button>`}
|
||
${deleteBtn}
|
||
</div>
|
||
</div>`;
|
||
}).join('');
|
||
};
|
||
|
||
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);
|
||
}
|
||
};
|
||
|
||
let autoSaveTimer = null;
|
||
const autoSave = async () => {
|
||
try {
|
||
const payload = {
|
||
name: inpName ? inpName.value : '',
|
||
section_id: section.id,
|
||
};
|
||
if (section?.is_template) {
|
||
payload.api_name = inpApiName ? inpApiName.value : '';
|
||
}
|
||
const res = await apiUpdate('content', item.id, payload);
|
||
if (res?.ok && typeof window.loadList === 'function') window.loadList(section);
|
||
if (!res?.ok) toast(res?.error || 'Speichern fehlgeschlagen', false);
|
||
} catch {
|
||
toast('Speichern fehlgeschlagen', false);
|
||
}
|
||
};
|
||
const scheduleAutoSave = () => {
|
||
if (autoSaveTimer) clearTimeout(autoSaveTimer);
|
||
autoSaveTimer = setTimeout(autoSave, 450);
|
||
};
|
||
|
||
const cleanup = () => {
|
||
inpApiName && inpApiName.removeEventListener('input', onApiInput);
|
||
inpName && inpName.removeEventListener('input', scheduleAutoSave);
|
||
inpApiName && inpApiName.removeEventListener('input', scheduleAutoSave);
|
||
versionsWrap && versionsWrap.removeEventListener('click', onVersionsClick);
|
||
if (btnClose) btnClose.onclick = null;
|
||
if (btnDelete) btnDelete.onclick = null;
|
||
if (autoSaveTimer) {
|
||
clearTimeout(autoSaveTimer);
|
||
autoSaveTimer = null;
|
||
}
|
||
};
|
||
|
||
const onDeleteItem = async () => {
|
||
if (activeId) return;
|
||
if (section?.is_template) {
|
||
const ok = await confirmTemplateReferences('Löschen');
|
||
if (!ok) return;
|
||
}
|
||
if (!delDlg || !delForm) {
|
||
const res = await apiAction('content.delete', { method: 'POST', data: { id: item.id, section_id: section.id } });
|
||
toast(res && res.ok ? 'Gelöscht' : 'Löschen fehlgeschlagen', !!(res && res.ok), { duration: 3000 });
|
||
dlg && dlg.close();
|
||
if (typeof window.loadList === 'function') window.loadList(section);
|
||
return;
|
||
}
|
||
if (delText) {
|
||
delText.innerHTML = `Soll <strong>${item.name || '(ohne Name)'} #${item.id}</strong> wirklich gelöscht werden?`;
|
||
}
|
||
const cleanupDelete = () => {
|
||
delForm.onsubmit = null;
|
||
if (delCancel) delCancel.onclick = null;
|
||
};
|
||
if (delCancel) delCancel.onclick = () => { delDlg.close(); cleanupDelete(); };
|
||
delForm.onsubmit = async (ev) => {
|
||
ev.preventDefault();
|
||
if (section?.is_template) {
|
||
const ok = await confirmTemplateReferences('Löschen');
|
||
if (!ok) return;
|
||
}
|
||
const res = await apiAction('content.delete', { method: 'POST', data: { id: item.id, section_id: section.id } });
|
||
delDlg.close();
|
||
cleanupDelete();
|
||
toast(res && res.ok ? 'Gelöscht' : 'Löschen fehlgeschlagen', !!(res && res.ok), { duration: 3000 });
|
||
dlg && dlg.close();
|
||
if (typeof window.loadList === 'function') window.loadList(section);
|
||
};
|
||
delDlg.showModal();
|
||
};
|
||
|
||
const onVersionsClick = async (ev) => {
|
||
const target = ev.target;
|
||
if (!target || !target.dataset) return;
|
||
const vid = Number(target.dataset.versionEdit || target.dataset.versionActivate || target.dataset.versionDeactivate || target.dataset.versionDelete || 0);
|
||
if (!vid) return;
|
||
|
||
if (target.dataset.versionEdit !== undefined) {
|
||
dlg && dlg.close();
|
||
const versionItem = { ...item, version_id: vid };
|
||
openContentEditor(versionItem, section);
|
||
return;
|
||
}
|
||
if (target.dataset.versionActivate !== undefined) {
|
||
const res = await apiAction('content_versions.activate', { method: 'POST', data: { id: vid } });
|
||
toast(res && res.ok ? 'Version aktiviert' : 'Aktivieren fehlgeschlagen', !!(res && res.ok));
|
||
await loadVersions();
|
||
if (typeof window.loadList === 'function') window.loadList(section);
|
||
return;
|
||
}
|
||
if (target.dataset.versionDeactivate !== undefined) {
|
||
if (section?.is_template) {
|
||
const ok = await confirmTemplateReferences('Deaktivieren');
|
||
if (!ok) return;
|
||
}
|
||
let res = await apiAction('content_versions.deactivate', { method: 'POST', data: { content_id: item.id } });
|
||
if (res && res.ok === false && Array.isArray(res.references) && res.references.length) {
|
||
const ok = confirm('Dieses Template wird in anderen Templates verwendet. Trotzdem deaktivieren?');
|
||
if (!ok) return;
|
||
res = await apiAction('content_versions.deactivate', { method: 'POST', data: { content_id: item.id, force: 1 } });
|
||
}
|
||
toast(res && res.ok ? 'Aktive Version deaktiviert' : 'Deaktivieren fehlgeschlagen', !!(res && res.ok));
|
||
await loadVersions();
|
||
if (typeof window.loadList === 'function') window.loadList(section);
|
||
return;
|
||
}
|
||
if (target.dataset.versionDelete !== undefined) {
|
||
const versionRow = versions.find(v => Number(v.id) === vid);
|
||
if (versionRow && Number(versionRow.is_active) === 1) return;
|
||
if (!confirm('Version wirklich löschen?')) return;
|
||
let res = await apiAction('content_versions.delete', { method: 'POST', data: { id: vid, content_id: item.id } });
|
||
if (res && res.ok === false && Array.isArray(res.references) && res.references.length) {
|
||
const ok = confirm('Dieses Template wird in anderen Templates verwendet. Trotzdem löschen?');
|
||
if (!ok) return;
|
||
res = await apiAction('content_versions.delete', { method: 'POST', data: { id: vid, content_id: item.id, force: 1 } });
|
||
}
|
||
toast(res && res.ok ? 'Version gelöscht' : 'Löschen fehlgeschlagen', !!(res && res.ok));
|
||
await loadVersions();
|
||
if (typeof window.loadList === 'function') window.loadList(section);
|
||
return;
|
||
}
|
||
};
|
||
|
||
inpApiName && inpApiName.addEventListener('input', onApiInput);
|
||
inpName && inpName.addEventListener('input', scheduleAutoSave);
|
||
inpApiName && inpApiName.addEventListener('input', scheduleAutoSave);
|
||
btnClose && (btnClose.onclick = () => { dlg && dlg.close(); cleanup(); });
|
||
btnDelete && (btnDelete.onclick = onDeleteItem);
|
||
versionsWrap && versionsWrap.addEventListener('click', onVersionsClick);
|
||
|
||
await loadVersions();
|
||
|
||
dlg && dlg.addEventListener('close', cleanup, { once: true });
|
||
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 = `<div class='rounded-2xl border bg-white overflow-hidden'>
|
||
<div class='px-4 py-2 border-b bg-gray-50 text-sm font-medium flex items-center gap-3'>
|
||
<span>${esc(label)}</span>
|
||
<div class='ms-auto flex items-center gap-2'>
|
||
<div class='flex items-center gap-1'>
|
||
<input id='filter-section' class='input text-sm' placeholder='Suche Name${isTemplate ? '/API' : ''}' />
|
||
<button id='filter-section-reset' class='btn' type='button' title='Suche zurücksetzen'>×</button>
|
||
</div>
|
||
<select id='sort-section' class='input text-sm'>
|
||
<option value='created_asc'>Erstelldatum (aufsteigend)</option>
|
||
<option value='name_asc'>Name A–Z</option>
|
||
<option value='name_desc'>Name Z–A</option>
|
||
<option value='updated_desc'>Zuletzt bearbeitet</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div id='list-section' class='divide-y'>Lade …</div></div>`;
|
||
|
||
let data = [];
|
||
try {
|
||
data = await fetchContentList(section.id);
|
||
} catch (err) {
|
||
list.innerHTML = `<div class='p-4 text-sm text-gray-500'>${esc(err.message || 'Laden fehlgeschlagen')}</div>`;
|
||
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 = `<div class='p-4 text-sm text-gray-500'>Keine Einträge</div>`;
|
||
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));
|
||
}
|
||
|
||
const versionCache = new Map();
|
||
|
||
async function loadVersionOptions(selectEl, itemId) {
|
||
if (!selectEl || !itemId) return;
|
||
if (versionCache.has(itemId)) {
|
||
const cached = versionCache.get(itemId);
|
||
renderVersionSelect(selectEl, cached.items, cached.activeId);
|
||
return;
|
||
}
|
||
try {
|
||
const res = await apiAction('content_versions.list', { method: 'GET', data: { content_id: itemId } });
|
||
const items = Array.isArray(res?.items) ? res.items : [];
|
||
const active = items.find(v => Number(v.is_active) === 1);
|
||
const activeId = active ? String(active.id) : (items[0] ? String(items[0].id) : '');
|
||
versionCache.set(itemId, { items, activeId });
|
||
renderVersionSelect(selectEl, items, activeId);
|
||
} catch {
|
||
renderVersionSelect(selectEl, [], '');
|
||
}
|
||
}
|
||
|
||
function renderVersionSelect(selectEl, items, activeId) {
|
||
selectEl.innerHTML = '';
|
||
if (!items.length) {
|
||
const opt = document.createElement('option');
|
||
opt.value = '';
|
||
opt.textContent = 'Keine Versionen';
|
||
opt.disabled = true;
|
||
selectEl.appendChild(opt);
|
||
selectEl.disabled = true;
|
||
return;
|
||
}
|
||
selectEl.disabled = false;
|
||
const sorted = items.slice().sort((a, b) => {
|
||
const aActive = Number(a.is_active) === 1 ? 1 : 0;
|
||
const bActive = Number(b.is_active) === 1 ? 1 : 0;
|
||
if (aActive !== bActive) return bActive - aActive;
|
||
return Number(b.id || 0) - Number(a.id || 0);
|
||
});
|
||
sorted.forEach(item => {
|
||
const opt = document.createElement('option');
|
||
const label = `${Number(item.is_active) === 1 ? '✓ ' : ''}#${item.version_no} – ${formatVersionDate(item.created_at)}` + (Number(item.is_active) === 1 ? ' (aktiv)' : '');
|
||
opt.value = String(item.id);
|
||
opt.textContent = label;
|
||
selectEl.appendChild(opt);
|
||
});
|
||
if (activeId) selectEl.value = activeId;
|
||
}
|
||
|
||
function render(items) {
|
||
list.innerHTML = items.map(item => {
|
||
const name = esc(item.name || '');
|
||
const apiName = isTemplate ? esc(item.api_name || '') : '';
|
||
const apiLine = (isTemplate && apiName) ? `<div class='text-xs text-slate-500'>API: ${apiName}</div>` : '';
|
||
const versionSelect = `<select class="input h-8 py-0 text-xs min-w-[160px]" data-version-select="${item.id}" disabled>
|
||
<option value="">Versionen laden…</option>
|
||
</select>`;
|
||
const nameCell = `<div class='min-w-48'>
|
||
<div class='font-medium truncate' title="${name}">${name || '(ohne Name)'}</div>
|
||
${apiLine}
|
||
</div>`;
|
||
const openBtn = `<button class='btn' data-open='${item.id}'>Bearbeiten</button>`;
|
||
const editTplBtn = `<button class='btn' data-edit='${item.id}'>Verwaltung</button>`;
|
||
const testBtn = isTemplate ? `<button class='btn' data-test='${item.id}' data-name='${name}'>Testversand</button>` : '';
|
||
const prevBtn = `<button class='btn' data-preview='${item.id}'>Vorschau</button>`;
|
||
return `<div class='p-3 flex items-center gap-3'>
|
||
${nameCell}
|
||
<div class='text-xs text-gray-500'>#${item.id}</div>
|
||
<div class='ms-auto flex gap-2 items-center'>
|
||
${openBtn}
|
||
${versionSelect}
|
||
${[testBtn, prevBtn, editTplBtn].filter(Boolean).join('')}
|
||
</div>
|
||
</div>`;
|
||
}).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-version-select]').forEach(sel => {
|
||
const id = Number(sel.getAttribute('data-version-select') || 0);
|
||
loadVersionOptions(sel, id);
|
||
sel.addEventListener('focus', () => loadVersionOptions(sel, id));
|
||
sel.addEventListener('click', () => loadVersionOptions(sel, id));
|
||
sel.addEventListener('change', () => {
|
||
const versionId = Number(sel.value || 0);
|
||
if (!versionId) return;
|
||
const item = data.find(it => Number(it.id) === id);
|
||
if (!item) return;
|
||
openContentEditor({ ...item, version_id: versionId }, section);
|
||
});
|
||
});
|
||
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) openTemplateManager(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 apiAction('content.get', { method: 'GET', data: { id, section_id: section.id, active_only: 1 } });
|
||
const html = (obj?.html || obj?.content || '<em>(leer)</em>');
|
||
prevFrame.srcdoc = '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head><body>' + html + '</body></html>';
|
||
prevDlg.showModal();
|
||
}));
|
||
|
||
scope.querySelectorAll('[data-test]').forEach(btn => btn.addEventListener('click', async () => {
|
||
const id = Number(btn.dataset.test || 0);
|
||
const nm = btn.dataset.name || '';
|
||
if (!id) {
|
||
toast('Testversand: Ungültige ID', false);
|
||
return;
|
||
}
|
||
const activeCheck = await apiAction('content.get', { method: 'GET', data: { id, section_id: section.id, active_only: 1 } }).catch(() => ({}));
|
||
if (!activeCheck?.active_version_id && !activeCheck?.item?.active_version_id) {
|
||
toast('Testversand nur mit aktiver Version möglich.', 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);
|
||
}
|
||
}));
|
||
|
||
// delete handling removed from overview
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|