This commit is contained in:
2026-01-21 22:44:32 +01:00
parent 107de0b7db
commit a09a07bcfc
7 changed files with 324 additions and 32 deletions

View File

@@ -33,6 +33,11 @@ export function initEditor() {
const btnUnsavedCancel = document.getElementById('btn-unsaved-cancel');
const btnUnsavedDiscard = document.getElementById('btn-unsaved-discard');
const btnUnsavedSave = document.getElementById('btn-unsaved-save');
const btnDeactivateVersion = document.getElementById('btn-deactivate-version');
const activateDialog = document.getElementById('activateVersionDialog');
const btnActivateCancel = document.getElementById('btn-activate-cancel');
const btnActivateNo = document.getElementById('btn-activate-no');
const btnActivateYes = document.getElementById('btn-activate-yes');
let current = null; // { resource, id, name, section }
let bridgeListener = null;
@@ -49,6 +54,9 @@ export function initEditor() {
let suppressDirty = false;
let suppressTimer = null;
let baselineReady = false;
let versionMap = new Map();
let currentVersionId = 0;
let currentVersionMeta = null;
  const ok  = (m) => toast(m, true);
  const err = (m) => toast(m, false);
@@ -94,6 +102,7 @@ export function initEditor() {
function setVersionUiVisible(show) {
if (versionSelect) versionSelect.classList.toggle('hidden', !show);
// restore button removed
if (btnDeactivateVersion) btnDeactivateVersion.classList.toggle('hidden', !show);
}
setVersionUiVisible(false);
@@ -262,11 +271,49 @@ export function initEditor() {
return choice;
}
function showActivateDialog() {
return new Promise((resolve) => {
if (!activateDialog || typeof activateDialog.showModal !== 'function') {
resolve('no');
return;
}
const cleanup = () => {
btnActivateCancel && btnActivateCancel.removeEventListener('click', onCancel);
btnActivateNo && btnActivateNo.removeEventListener('click', onNo);
btnActivateYes && btnActivateYes.removeEventListener('click', onYes);
};
const closeWith = (choice) => {
cleanup();
activateDialog.close();
resolve(choice);
};
const onCancel = () => closeWith('cancel');
const onNo = () => closeWith('no');
const onYes = () => closeWith('yes');
btnActivateCancel && btnActivateCancel.addEventListener('click', onCancel);
btnActivateNo && btnActivateNo.addEventListener('click', onNo);
btnActivateYes && btnActivateYes.addEventListener('click', onYes);
activateDialog.showModal();
});
}
function updateVersionMeta(id) {
const key = id ? String(id) : '';
currentVersionId = id ? Number(id) : 0;
currentVersionMeta = key && versionMap.has(key) ? versionMap.get(key) : null;
if (btnDeactivateVersion) {
const isActive = !!(currentVersionMeta && Number(currentVersionMeta.is_active) === 1);
btnDeactivateVersion.classList.toggle('hidden', !isActive);
}
}
function renderVersionOptions(items) {
versionItems = items || [];
if (!versionSelect) return;
versionMap = new Map();
if (!versionSelect) return '';
const rows = Array.isArray(versionItems) ? versionItems : [];
versionSelect.innerHTML = '';
lastVersionSelection = '';
if (!rows.length) {
const opt = document.createElement('option');
opt.value = '';
@@ -274,33 +321,41 @@ export function initEditor() {
opt.disabled = true;
versionSelect.appendChild(opt);
versionSelect.disabled = true;
return;
updateVersionMeta(0);
return '';
}
versionSelect.disabled = false;
rows.forEach((item, idx) => {
let activeId = '';
rows.forEach((item) => {
const opt = document.createElement('option');
const label = `#${item.version_no} ${formatVersionDate(item.created_at)}`;
const label = `#${item.version_no} ${formatVersionDate(item.created_at)}` + (Number(item.is_active) === 1 ? ' (aktiv)' : '');
opt.value = String(item.id);
opt.textContent = label;
versionSelect.appendChild(opt);
if (!lastVersionSelection && idx === 0) {
lastVersionSelection = String(item.id);
}
versionMap.set(String(item.id), item);
if (Number(item.is_active) === 1 && !activeId) activeId = String(item.id);
});
if (lastVersionSelection) versionSelect.value = lastVersionSelection;
const fallbackId = activeId || (rows[0] ? String(rows[0].id) : '');
if (fallbackId) {
lastVersionSelection = fallbackId;
versionSelect.value = fallbackId;
updateVersionMeta(Number(fallbackId));
}
return lastVersionSelection;
}
async function loadVersionsForCurrent() {
if (!current?.id) {
renderVersionOptions([]);
return;
return '';
}
try {
const res = await apiAction('content_versions.list', { method: 'GET', data: { content_id: current.id, id: current.id } });
if (!res?.ok) throw new Error(res?.error || 'Versionen konnten nicht geladen werden');
renderVersionOptions(Array.isArray(res?.items) ? res.items : []);
return renderVersionOptions(Array.isArray(res?.items) ? res.items : []);
} catch {
renderVersionOptions([]);
return '';
}
}
@@ -594,9 +649,11 @@ export function initEditor() {
    // Overlay zeigen
    showVeil();
    // Daten parallel laden (fresh HTML + kontextgefilterte Snippets + Referenzen)
    let fresh = '';
    let snippets = [];
const requestedVersionId = Number(item?.version_id || item?.versionId || 0);
// Daten parallel laden (fresh HTML + kontextgefilterte Snippets + Referenzen)
let fresh = '';
let snippets = [];
let refLib = { sections: [], blocks: [] };
let hasJson = false;
let jsonState = '';
@@ -604,6 +661,7 @@ export function initEditor() {
let editorType = 'grapesjs';
let craftJson = '';
let defaultVersionId = '';
    await Promise.all([
      (async() => {
try {
@@ -624,9 +682,25 @@ export function initEditor() {
})(),
      (async() => { snippets = await buildSnippetsForContext(current); })(),
      (async() => { refLib   = await buildRefLibForContext(current); })(),
(async() => { await loadVersionsForCurrent(); })()
(async() => { defaultVersionId = await loadVersionsForCurrent(); })()
    ]);
const effectiveVersionId = requestedVersionId ? String(requestedVersionId) : defaultVersionId;
if (effectiveVersionId) {
try {
const res = await apiAction('content_versions.get', { method: 'GET', data: { id: effectiveVersionId, content_id: current.id } });
if (res?.ok && res?.item) {
const fields = extractContentFields(res.item);
fresh = fields.html || '';
jsonState = fields.json || '';
editorType = fields.editorType || editorType;
craftJson = fields.craftJson || '';
updateVersionMeta(Number(effectiveVersionId));
lastVersionSelection = String(effectiveVersionId);
}
} catch {}
}
editorType = editorType === 'craftjs' ? 'craftjs' : 'grapesjs';
setSavedSnapshotFromData({ html: fresh, content: jsonState, editor_type: editorType, craft_json: craftJson });
setEditorType(editorType);
@@ -744,12 +818,20 @@ export function initEditor() {
async function save() {
if (!current?.id) return err('Keine aktive ID');
let activateNext = false;
if (currentVersionMeta && (Number(currentVersionMeta.is_active) === 1 || Number(currentVersionMeta.was_active) === 1)) {
const decision = await showActivateDialog();
if (decision === 'cancel') return false;
activateNext = decision === 'yes';
}
if (currentEditorType === 'craftjs') {
const html = craftEditor ? craftEditor.getContent() : '';
const craftJson = craftEditor && craftEditor.getCraftJson
? craftEditor.getCraftJson()
: JSON.stringify({ html });
const payload = { html, craft_json: craftJson, editor_type: 'craftjs', section_id: current.section.id };
if (activateNext) payload.activate_version = 1;
const res = await apiUpdate('content', current.id, payload);
if (res?.ok) ok('Gespeichert');
else err(res?.error || 'Speichern fehlgeschlagen');
@@ -757,6 +839,14 @@ export function initEditor() {
return res?.ok;
}
if (activateNext) {
const win = iframe?.contentWindow;
if (win && win.BridgeParts) {
win.BridgeParts.NEXT_ACTIVATE_VERSION = 1;
} else if (win) {
win.NEXT_ACTIVATE_VERSION = 1;
}
}
const okSave = await delegateCommand('save-data');
if (okSave) {
setTimeout(async () => {
@@ -921,6 +1011,18 @@ export function initEditor() {
btnCancelSend&& (btnCancelSend.onclick= closeSend);
sendForm && (sendForm.onsubmit = doSend);
editorSelect && (editorSelect.onchange = () => switchEditor(editorSelect.value));
btnDeactivateVersion && (btnDeactivateVersion.onclick = async () => {
if (!current?.id) return;
if (!currentVersionMeta || Number(currentVersionMeta.is_active) !== 1) return;
try {
const res = await apiAction('content_versions.deactivate', { method: 'POST', data: { content_id: current.id } });
if (!res?.ok) throw new Error(res?.error || 'Deaktivieren fehlgeschlagen');
await loadVersionsForCurrent();
toast('Aktive Version deaktiviert', true);
} catch (e) {
err(e.message || 'Deaktivieren fehlgeschlagen');
}
});
versionSelect && (versionSelect.onchange = async () => {
if (!current?.id) return;
const previousSelection = lastVersionSelection;
@@ -939,6 +1041,7 @@ export function initEditor() {
if (!res?.ok) throw new Error(res?.error || 'Version konnte nicht geladen werden');
await applyVersionPayload(res?.item || res);
lastVersionSelection = String(versionId);
updateVersionMeta(versionId);
} catch (e) {
err(e.message || 'Version konnte nicht geladen werden');
versionSelect.value = previousSelection;