asdasd
This commit is contained in:
@@ -15,7 +15,6 @@ export function initEditor() {
|
|||||||
const btnClear = document.getElementById('btn-clear-main');
|
const btnClear = document.getElementById('btn-clear-main');
|
||||||
const editorSelect = document.getElementById('editorTypeSelect');
|
const editorSelect = document.getElementById('editorTypeSelect');
|
||||||
const versionSelect = document.getElementById('versionSelect');
|
const versionSelect = document.getElementById('versionSelect');
|
||||||
const btnRestoreVersion = document.getElementById('btn-restore-version');
|
|
||||||
const craftEditor = initCraftEditor();
|
const craftEditor = initCraftEditor();
|
||||||
|
|
||||||
const prevDlg = document.getElementById('previewDialog');
|
const prevDlg = document.getElementById('previewDialog');
|
||||||
@@ -44,6 +43,9 @@ export function initEditor() {
|
|||||||
let versionItems = [];
|
let versionItems = [];
|
||||||
let savedSnapshot = '';
|
let savedSnapshot = '';
|
||||||
let lastVersionSelection = '';
|
let lastVersionSelection = '';
|
||||||
|
let isDirty = false;
|
||||||
|
let dirtyCleanup = null;
|
||||||
|
let dialogCancelBound = false;
|
||||||
|
|
||||||
const ok = (m) => toast(m, true);
|
const ok = (m) => toast(m, true);
|
||||||
const err = (m) => toast(m, false);
|
const err = (m) => toast(m, false);
|
||||||
@@ -88,7 +90,7 @@ export function initEditor() {
|
|||||||
|
|
||||||
function setVersionUiVisible(show) {
|
function setVersionUiVisible(show) {
|
||||||
if (versionSelect) versionSelect.classList.toggle('hidden', !show);
|
if (versionSelect) versionSelect.classList.toggle('hidden', !show);
|
||||||
if (btnRestoreVersion) btnRestoreVersion.classList.toggle('hidden', !show);
|
// restore button removed
|
||||||
}
|
}
|
||||||
|
|
||||||
setVersionUiVisible(false);
|
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() {
|
async function buildCurrentSnapshot() {
|
||||||
if (currentEditorType === 'craftjs') {
|
if (currentEditorType === 'craftjs') {
|
||||||
return buildSnapshot({
|
return buildSnapshot({
|
||||||
@@ -150,9 +184,11 @@ export function initEditor() {
|
|||||||
function setSavedSnapshotFromData(payload) {
|
function setSavedSnapshotFromData(payload) {
|
||||||
const fields = extractContentFields(payload);
|
const fields = extractContentFields(payload);
|
||||||
savedSnapshot = buildSnapshot(fields);
|
savedSnapshot = buildSnapshot(fields);
|
||||||
|
clearDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hasUnsavedChanges() {
|
async function hasUnsavedChanges() {
|
||||||
|
if (isDirty) return true;
|
||||||
if (!savedSnapshot) return false;
|
if (!savedSnapshot) return false;
|
||||||
const currentSnapshot = await buildCurrentSnapshot();
|
const currentSnapshot = await buildCurrentSnapshot();
|
||||||
return currentSnapshot !== savedSnapshot;
|
return currentSnapshot !== savedSnapshot;
|
||||||
@@ -245,6 +281,8 @@ export function initEditor() {
|
|||||||
if (targetType === 'craftjs') {
|
if (targetType === 'craftjs') {
|
||||||
craftEditor?.setContent(data.html || '', data.craftJson || '');
|
craftEditor?.setContent(data.html || '', data.craftJson || '');
|
||||||
setSavedSnapshotFromData(payload);
|
setSavedSnapshotFromData(payload);
|
||||||
|
if (dirtyCleanup) dirtyCleanup();
|
||||||
|
dirtyCleanup = attachCraftDirtyTracker();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const editor = await waitForEditor(3000);
|
const editor = await waitForEditor(3000);
|
||||||
@@ -254,12 +292,16 @@ export function initEditor() {
|
|||||||
const project = JSON.parse(jsonRaw);
|
const project = JSON.parse(jsonRaw);
|
||||||
editor.loadProjectData(project);
|
editor.loadProjectData(project);
|
||||||
setSavedSnapshotFromData(payload);
|
setSavedSnapshotFromData(payload);
|
||||||
|
if (dirtyCleanup) dirtyCleanup();
|
||||||
|
dirtyCleanup = attachGjsDirtyTracker(editor);
|
||||||
return;
|
return;
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
const html = normalizeSnapshotValue(data.html);
|
const html = normalizeSnapshotValue(data.html);
|
||||||
editor.setComponents(html);
|
editor.setComponents(html);
|
||||||
setSavedSnapshotFromData(payload);
|
setSavedSnapshotFromData(payload);
|
||||||
|
if (dirtyCleanup) dirtyCleanup();
|
||||||
|
dirtyCleanup = attachGjsDirtyTracker(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadLatestContentFromServer() {
|
async function loadLatestContentFromServer() {
|
||||||
@@ -553,6 +595,8 @@ export function initEditor() {
|
|||||||
if (editorType === 'craftjs') {
|
if (editorType === 'craftjs') {
|
||||||
const craftHtml = extractCraftHtml(craftJson, fresh);
|
const craftHtml = extractCraftHtml(craftJson, fresh);
|
||||||
craftEditor?.setContent(craftHtml, craftJson);
|
craftEditor?.setContent(craftHtml, craftJson);
|
||||||
|
if (dirtyCleanup) dirtyCleanup();
|
||||||
|
dirtyCleanup = attachCraftDirtyTracker();
|
||||||
hideVeil();
|
hideVeil();
|
||||||
if (dlg && typeof dlg.showModal === 'function') dlg.showModal();
|
if (dlg && typeof dlg.showModal === 'function') dlg.showModal();
|
||||||
if (!looksCraftSerialized(craftJson) && craftEditor?.serializeFromHtml) {
|
if (!looksCraftSerialized(craftJson) && craftEditor?.serializeFromHtml) {
|
||||||
@@ -633,10 +677,24 @@ export function initEditor() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Jetzt den Editor-Core laden (erst NACH about:blank)
|
// 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) ----------
|
// ---------- Speichern (DELEGIERT) ----------
|
||||||
// 🚨 KORRIGIERT: Delegiert Speichern an den iFrame, der die JSON-Daten holt!
|
// 🚨 KORRIGIERT: Delegiert Speichern an den iFrame, der die JSON-Daten holt!
|
||||||
@@ -740,6 +798,8 @@ export function initEditor() {
|
|||||||
async function close() {
|
async function close() {
|
||||||
const decision = await confirmUnsavedChanges();
|
const decision = await confirmUnsavedChanges();
|
||||||
if (decision === 'cancel') return;
|
if (decision === 'cancel') return;
|
||||||
|
if (dirtyCleanup) dirtyCleanup();
|
||||||
|
dirtyCleanup = null;
|
||||||
// nächstes Öffnen invalidiert laufende asyncs
|
// nächstes Öffnen invalidiert laufende asyncs
|
||||||
reqToken++;
|
reqToken++;
|
||||||
|
|
||||||
@@ -754,9 +814,10 @@ export function initEditor() {
|
|||||||
iframe.src = 'about:blank#' + Date.now();
|
iframe.src = 'about:blank#' + Date.now();
|
||||||
|
|
||||||
// Kontext leeren
|
// Kontext leeren
|
||||||
current = null;
|
current = null;
|
||||||
window.__currentItemId = undefined;
|
window.__currentItemId = undefined;
|
||||||
window.__currentEditorCtx = undefined;
|
window.__currentEditorCtx = undefined;
|
||||||
|
clearDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function switchEditor(nextType) {
|
async function switchEditor(nextType) {
|
||||||
@@ -841,23 +902,7 @@ export function initEditor() {
|
|||||||
versionSelect.value = previousSelection;
|
versionSelect.value = previousSelection;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
btnRestoreVersion && (btnRestoreVersion.onclick = async () => {
|
// restore button removed
|
||||||
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');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.AdminTestSend = window.AdminTestSend || {};
|
window.AdminTestSend = window.AdminTestSend || {};
|
||||||
window.AdminTestSend.open = (opts = {}) => {
|
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]">
|
<select id="versionSelect" class="input h-8 py-0 text-sm min-w-[200px]">
|
||||||
<option value="">Letzte Versionen</option>
|
<option value="">Letzte Versionen</option>
|
||||||
</select>
|
</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-clear-main" type="button" class="btn" title="Leeren">🧹</button>
|
||||||
<button id="btn-preview" type="button" class="btn">Vorschau</button>
|
<button id="btn-preview" type="button" class="btn">Vorschau</button>
|
||||||
<button id="btn-test" type="button" class="btn">Testversand</button>
|
<button id="btn-test" type="button" class="btn">Testversand</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user