change popup

This commit is contained in:
2026-02-03 03:38:30 +01:00
parent aedffcda2d
commit aaddd33e3b
3 changed files with 152 additions and 10 deletions

View File

@@ -60,8 +60,65 @@ export function initEditor() {
let currentVersionId = 0;
let currentVersionMeta = null;
  const ok  = (m) => toast(m, true);
  const err = (m) => toast(m, false);
const ok  = (m) => toast(m, true);
const err = (m) => toast(m, false);
const showConfirmDialog = (() => {
let dialog;
let titleEl;
let textEl;
let btnOk;
let btnCancel;
let pendingResolve = null;
const ensure = () => {
if (dialog) return;
dialog = document.createElement('dialog');
dialog.className = 'rounded-2xl p-0 w-[520px]';
dialog.innerHTML = `
<div class="p-4 bg-white rounded-2xl space-y-4">
<h3 class="text-lg font-semibold" data-confirm-title></h3>
<p class="text-sm text-slate-600" data-confirm-text></p>
<div class="flex justify-end gap-2">
<button type="button" class="btn" data-confirm-cancel>Abbrechen</button>
<button type="button" class="btn btn-danger" data-confirm-ok>Bestätigen</button>
</div>
</div>
`;
document.body.appendChild(dialog);
titleEl = dialog.querySelector('[data-confirm-title]');
textEl = dialog.querySelector('[data-confirm-text]');
btnOk = dialog.querySelector('[data-confirm-ok]');
btnCancel = dialog.querySelector('[data-confirm-cancel]');
btnOk?.addEventListener('click', () => {
if (pendingResolve) pendingResolve(true);
pendingResolve = null;
dialog.close();
});
btnCancel?.addEventListener('click', () => {
if (pendingResolve) pendingResolve(false);
pendingResolve = null;
dialog.close();
});
dialog.addEventListener('close', () => {
if (pendingResolve) pendingResolve(false);
pendingResolve = null;
});
};
return async ({ title, text, confirmLabel = 'Bestätigen', cancelLabel = 'Abbrechen' }) => {
ensure();
if (titleEl) titleEl.textContent = title || 'Bestätigung';
if (textEl) textEl.textContent = text || '';
if (btnOk) btnOk.textContent = confirmLabel;
if (btnCancel) btnCancel.textContent = cancelLabel;
if (!dialog.open) dialog.showModal();
return await new Promise(resolve => {
pendingResolve = resolve;
});
};
})();
  // ---------- Hilfen ----------
function activeMode() {
@@ -1107,13 +1164,21 @@ export function initEditor() {
if (!current?.id || !isTemplateSection()) return true;
const res = await apiAction('templates.references', { method: 'GET', data: { template_id: current.id } }).catch(() => null);
if (!res || res.ok === false) {
return confirm(`Referenzen konnten nicht geprüft werden. ${actionLabel} trotzdem?`);
return await showConfirmDialog({
title: 'Referenzen nicht geprüft',
text: `Referenzen konnten nicht geprüft werden. ${actionLabel} trotzdem?`,
confirmLabel: actionLabel,
});
}
const refs = Array.isArray(res?.references) ? res.references : [];
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?`);
return await showConfirmDialog({
title: 'Template wird verwendet',
text: `Dieses Template wird in ${refs.length} anderen Template(s) verwendet (${preview}${more}). ${actionLabel} trotzdem?`,
confirmLabel: actionLabel,
});
}
// Buttons
@@ -1146,7 +1211,11 @@ export function initEditor() {
if (!okRefs) return;
let res = await apiAction('content_versions.deactivate', { method: 'POST', data: { content_id: current.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?');
const ok = await showConfirmDialog({
title: 'Template wird verwendet',
text: 'Dieses Template wird in anderen Templates verwendet. Trotzdem deaktivieren?',
confirmLabel: 'Deaktivieren',
});
if (!ok) return;
res = await apiAction('content_versions.deactivate', { method: 'POST', data: { content_id: current.id, force: 1 } });
}

View File

@@ -9,6 +9,63 @@ function esc(s = '') {
.replace(/'/g, '&#39;');
}
const showConfirmDialog = (() => {
let dialog;
let titleEl;
let textEl;
let btnOk;
let btnCancel;
let pendingResolve = null;
const ensure = () => {
if (dialog) return;
dialog = document.createElement('dialog');
dialog.className = 'rounded-2xl p-0 w-[520px]';
dialog.innerHTML = `
<div class="p-4 bg-white rounded-2xl space-y-4">
<h3 class="text-lg font-semibold" data-confirm-title></h3>
<p class="text-sm text-slate-600" data-confirm-text></p>
<div class="flex justify-end gap-2">
<button type="button" class="btn" data-confirm-cancel>Abbrechen</button>
<button type="button" class="btn btn-danger" data-confirm-ok>Bestätigen</button>
</div>
</div>
`;
document.body.appendChild(dialog);
titleEl = dialog.querySelector('[data-confirm-title]');
textEl = dialog.querySelector('[data-confirm-text]');
btnOk = dialog.querySelector('[data-confirm-ok]');
btnCancel = dialog.querySelector('[data-confirm-cancel]');
btnOk?.addEventListener('click', () => {
if (pendingResolve) pendingResolve(true);
pendingResolve = null;
dialog.close();
});
btnCancel?.addEventListener('click', () => {
if (pendingResolve) pendingResolve(false);
pendingResolve = null;
dialog.close();
});
dialog.addEventListener('close', () => {
if (pendingResolve) pendingResolve(false);
pendingResolve = null;
});
};
return async ({ title, text, confirmLabel = 'Bestätigen', cancelLabel = 'Abbrechen' }) => {
ensure();
if (titleEl) titleEl.textContent = title || 'Bestätigung';
if (textEl) textEl.textContent = text || '';
if (btnOk) btnOk.textContent = confirmLabel;
if (btnCancel) btnCancel.textContent = cancelLabel;
if (!dialog.open) dialog.showModal();
return await new Promise(resolve => {
pendingResolve = resolve;
});
};
})();
function formatVersionDate(value) {
if (!value) return '';
try {
@@ -105,12 +162,20 @@ async function openTemplateManager(item, section) {
if (!isTemplateSection()) return true;
const refs = await fetchTemplateReferences();
if (refs === null) {
return confirm(`Referenzen konnten nicht geprüft werden. ${actionLabel} trotzdem?`);
return await showConfirmDialog({
title: 'Referenzen nicht geprüft',
text: `Referenzen konnten nicht geprüft werden. ${actionLabel} trotzdem?`,
confirmLabel: actionLabel,
});
}
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?`);
return await showConfirmDialog({
title: 'Template wird verwendet',
text: `Dieses Template wird in ${refs.length} anderen Template(s) verwendet (${preview}${more}). ${actionLabel} trotzdem?`,
confirmLabel: actionLabel,
});
};
const updateDeleteState = () => {
@@ -262,7 +327,11 @@ async function openTemplateManager(item, section) {
}
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?');
const ok = await showConfirmDialog({
title: 'Template wird verwendet',
text: 'Dieses Template wird in anderen Templates verwendet. Trotzdem deaktivieren?',
confirmLabel: 'Deaktivieren',
});
if (!ok) return;
res = await apiAction('content_versions.deactivate', { method: 'POST', data: { content_id: item.id, force: 1 } });
}
@@ -277,7 +346,11 @@ async function openTemplateManager(item, section) {
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?');
const ok = await showConfirmDialog({
title: 'Template wird verwendet',
text: 'Dieses Template wird in anderen Templates verwendet. Trotzdem löschen?',
confirmLabel: 'Löschen',
});
if (!ok) return;
res = await apiAction('content_versions.delete', { method: 'POST', data: { id: vid, content_id: item.id, force: 1 } });
}