asdasd
This commit is contained in:
@@ -15,7 +15,6 @@ export function initEditor() {
|
||||
const btnClear = document.getElementById('btn-clear-main');
|
||||
const editorSelect = document.getElementById('editorTypeSelect');
|
||||
const versionSelect = document.getElementById('versionSelect');
|
||||
const btnRestoreVersion = document.getElementById('btn-restore-version');
|
||||
const craftEditor = initCraftEditor();
|
||||
|
||||
const prevDlg = document.getElementById('previewDialog');
|
||||
@@ -44,6 +43,9 @@ export function initEditor() {
|
||||
let versionItems = [];
|
||||
let savedSnapshot = '';
|
||||
let lastVersionSelection = '';
|
||||
let isDirty = false;
|
||||
let dirtyCleanup = null;
|
||||
let dialogCancelBound = false;
|
||||
|
||||
const ok = (m) => toast(m, true);
|
||||
const err = (m) => toast(m, false);
|
||||
@@ -88,7 +90,7 @@ export function initEditor() {
|
||||
|
||||
function setVersionUiVisible(show) {
|
||||
if (versionSelect) versionSelect.classList.toggle('hidden', !show);
|
||||
if (btnRestoreVersion) btnRestoreVersion.classList.toggle('hidden', !show);
|
||||
// restore button removed
|
||||
}
|
||||
|
||||
setVersionUiVisible(false);
|
||||
@@ -117,6 +119,38 @@ export function initEditor() {
|
||||
};
|
||||
}
|
||||
|
||||
function markDirty() {
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
function clearDirty() {
|
||||
isDirty = false;
|
||||
}
|
||||
|
||||
function attachGjsDirtyTracker(editor) {
|
||||
if (!editor || typeof editor.on !== 'function') return () => {};
|
||||
const onUpdate = () => markDirty();
|
||||
editor.on('update', onUpdate);
|
||||
editor.on('component:update', onUpdate);
|
||||
return () => {
|
||||
try {
|
||||
editor.off('update', onUpdate);
|
||||
editor.off('component:update', onUpdate);
|
||||
} catch {}
|
||||
};
|
||||
}
|
||||
|
||||
function attachCraftDirtyTracker() {
|
||||
const host = document.getElementById('craftEditor');
|
||||
if (!host) return () => {};
|
||||
const handler = () => markDirty();
|
||||
const events = ['input', 'keydown', 'paste', 'drop'];
|
||||
events.forEach(evt => host.addEventListener(evt, handler, true));
|
||||
return () => {
|
||||
events.forEach(evt => host.removeEventListener(evt, handler, true));
|
||||
};
|
||||
}
|
||||
|
||||
async function buildCurrentSnapshot() {
|
||||
if (currentEditorType === 'craftjs') {
|
||||
return buildSnapshot({
|
||||
@@ -150,9 +184,11 @@ export function initEditor() {
|
||||
function setSavedSnapshotFromData(payload) {
|
||||
const fields = extractContentFields(payload);
|
||||
savedSnapshot = buildSnapshot(fields);
|
||||
clearDirty();
|
||||
}
|
||||
|
||||
async function hasUnsavedChanges() {
|
||||
if (isDirty) return true;
|
||||
if (!savedSnapshot) return false;
|
||||
const currentSnapshot = await buildCurrentSnapshot();
|
||||
return currentSnapshot !== savedSnapshot;
|
||||
@@ -245,6 +281,8 @@ export function initEditor() {
|
||||
if (targetType === 'craftjs') {
|
||||
craftEditor?.setContent(data.html || '', data.craftJson || '');
|
||||
setSavedSnapshotFromData(payload);
|
||||
if (dirtyCleanup) dirtyCleanup();
|
||||
dirtyCleanup = attachCraftDirtyTracker();
|
||||
return;
|
||||
}
|
||||
const editor = await waitForEditor(3000);
|
||||
@@ -254,12 +292,16 @@ export function initEditor() {
|
||||
const project = JSON.parse(jsonRaw);
|
||||
editor.loadProjectData(project);
|
||||
setSavedSnapshotFromData(payload);
|
||||
if (dirtyCleanup) dirtyCleanup();
|
||||
dirtyCleanup = attachGjsDirtyTracker(editor);
|
||||
return;
|
||||
} catch {}
|
||||
}
|
||||
const html = normalizeSnapshotValue(data.html);
|
||||
editor.setComponents(html);
|
||||
setSavedSnapshotFromData(payload);
|
||||
if (dirtyCleanup) dirtyCleanup();
|
||||
dirtyCleanup = attachGjsDirtyTracker(editor);
|
||||
}
|
||||
|
||||
async function loadLatestContentFromServer() {
|
||||
@@ -553,6 +595,8 @@ export function initEditor() {
|
||||
if (editorType === 'craftjs') {
|
||||
const craftHtml = extractCraftHtml(craftJson, fresh);
|
||||
craftEditor?.setContent(craftHtml, craftJson);
|
||||
if (dirtyCleanup) dirtyCleanup();
|
||||
dirtyCleanup = attachCraftDirtyTracker();
|
||||
hideVeil();
|
||||
if (dlg && typeof dlg.showModal === 'function') dlg.showModal();
|
||||
if (!looksCraftSerialized(craftJson) && craftEditor?.serializeFromHtml) {
|
||||
@@ -633,10 +677,24 @@ export function initEditor() {
|
||||
};
|
||||
|
||||
// Jetzt den Editor-Core laden (erst NACH about:blank)
|
||||
iframe.src = `editor/editor-core.php?mode=${encodeURIComponent(current.section.slug)}&id=${current.id}§ion_id=${current.section.id}&t=${Date.now()}`;
|
||||
iframe.src = `editor/editor-core.php?mode=${encodeURIComponent(current.section.slug)}&id=${current.id}§ion_id=${current.section.id}&t=${Date.now()}`;
|
||||
|
||||
dlg?.showModal?.();
|
||||
}
|
||||
dlg?.showModal?.();
|
||||
if (dlg && !dialogCancelBound) {
|
||||
dlg.addEventListener('cancel', async (ev) => {
|
||||
ev.preventDefault();
|
||||
await close();
|
||||
});
|
||||
dialogCancelBound = true;
|
||||
}
|
||||
|
||||
waitForEditor(6000)
|
||||
.then((ed) => {
|
||||
if (dirtyCleanup) dirtyCleanup();
|
||||
dirtyCleanup = attachGjsDirtyTracker(ed);
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
// ---------- Speichern (DELEGIERT) ----------
|
||||
// 🚨 KORRIGIERT: Delegiert Speichern an den iFrame, der die JSON-Daten holt!
|
||||
@@ -740,6 +798,8 @@ export function initEditor() {
|
||||
async function close() {
|
||||
const decision = await confirmUnsavedChanges();
|
||||
if (decision === 'cancel') return;
|
||||
if (dirtyCleanup) dirtyCleanup();
|
||||
dirtyCleanup = null;
|
||||
// nächstes Öffnen invalidiert laufende asyncs
|
||||
reqToken++;
|
||||
|
||||
@@ -754,9 +814,10 @@ export function initEditor() {
|
||||
iframe.src = 'about:blank#' + Date.now();
|
||||
|
||||
// Kontext leeren
|
||||
current = null;
|
||||
window.__currentItemId = undefined;
|
||||
window.__currentEditorCtx = undefined;
|
||||
current = null;
|
||||
window.__currentItemId = undefined;
|
||||
window.__currentEditorCtx = undefined;
|
||||
clearDirty();
|
||||
}
|
||||
|
||||
async function switchEditor(nextType) {
|
||||
@@ -841,23 +902,7 @@ export function initEditor() {
|
||||
versionSelect.value = previousSelection;
|
||||
}
|
||||
});
|
||||
btnRestoreVersion && (btnRestoreVersion.onclick = async () => {
|
||||
if (!current?.id) return;
|
||||
const versionId = Number(versionSelect?.value || 0);
|
||||
if (!versionId) {
|
||||
err('Bitte eine Version auswählen');
|
||||
return;
|
||||
}
|
||||
if (!confirm('Version wiederherstellen? Der aktuelle Stand wird überschrieben.')) return;
|
||||
try {
|
||||
const res = await apiAction('content_versions.restore', { method: 'POST', data: { id: versionId, content_id: current.id } });
|
||||
if (!res?.ok) throw new Error(res?.error || 'Wiederherstellen fehlgeschlagen');
|
||||
ok('Version wiederhergestellt');
|
||||
await open({ id: current.id, name: current.name, section: current.section }, null, current.section);
|
||||
} catch (e) {
|
||||
err(e.message || 'Wiederherstellen fehlgeschlagen');
|
||||
}
|
||||
});
|
||||
// restore button removed
|
||||
|
||||
window.AdminTestSend = window.AdminTestSend || {};
|
||||
window.AdminTestSend.open = (opts = {}) => {
|
||||
|
||||
@@ -62,7 +62,6 @@ require __DIR__ . '/../partials/structure/layout_start.php';
|
||||
<select id="versionSelect" class="input h-8 py-0 text-sm min-w-[200px]">
|
||||
<option value="">Letzte Versionen</option>
|
||||
</select>
|
||||
<button id="btn-restore-version" type="button" class="btn">Wiederherstellen</button>
|
||||
<button id="btn-clear-main" type="button" class="btn" title="Leeren">🧹</button>
|
||||
<button id="btn-preview" type="button" class="btn">Vorschau</button>
|
||||
<button id="btn-test" type="button" class="btn">Testversand</button>
|
||||
|
||||
Reference in New Issue
Block a user