Upload new version
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/* /assets/js/ui-editor.js (KORRIGIERT: Speichern wird an iFrame-Editor delegiert) */
|
||||
// Öffnen, Befüllen, Speichern (mit Live-HTML), Preview – Race-Schutz & Lade-Overlay.
|
||||
|
||||
import { apiUpdate, apiList, apiGet, toast, apiAction } from './api.js';
|
||||
import { apiUpdate, toast, apiAction } from './api.js';
|
||||
import { initCraftEditor } from './craft-editor.js';
|
||||
|
||||
export function initEditor() {
|
||||
@@ -29,7 +29,7 @@ export function initEditor() {
|
||||
const prevFrame = document.getElementById('previewFrame');
|
||||
const btnPrevClose = document.getElementById('btn-close-preview');
|
||||
|
||||
let current = null; // { resource, id, name }
|
||||
let current = null; // { resource, id, name, section }
|
||||
let bridgeListener = null;
|
||||
let reqToken = 0; // steigender Token pro Öffnen -> ignoriert verspätete Events
|
||||
let senderOptions = [];
|
||||
@@ -40,12 +40,12 @@ export function initEditor() {
|
||||
const err = (m) => toast(m, false);
|
||||
|
||||
// ---------- Hilfen ----------
|
||||
function activeMode() {
|
||||
const b = document.querySelector('nav [data-tab].bg-sky-50, nav [data-tab].text-sky-700, nav [data-tab].active');
|
||||
return (b?.dataset?.tab) || (current?.resource) || 'templates';
|
||||
}
|
||||
function activeMode() {
|
||||
const activeSection = window.__activeSection || current?.section || null;
|
||||
return (activeSection?.slug) || (current?.resource) || 'emailtemplate';
|
||||
}
|
||||
|
||||
function setSendContext(id, name = '') {
|
||||
function setSendContext(id, name = '') {
|
||||
if (sendDlg) {
|
||||
if (id) {
|
||||
sendDlg.dataset.templateId = String(id);
|
||||
@@ -59,12 +59,12 @@ export function initEditor() {
|
||||
sendInfo.textContent = 'Kein Template ausgewählt.';
|
||||
sendInfo.classList.add('text-rose-600');
|
||||
} else {
|
||||
const label = name ? `${name} – Template #${id}` : `Template #${id}`;
|
||||
sendInfo.textContent = label;
|
||||
sendInfo.classList.remove('text-rose-600');
|
||||
}
|
||||
}
|
||||
}
|
||||
const label = name ? `${name} – Template #${id}` : `Template #${id}`;
|
||||
sendInfo.textContent = label;
|
||||
sendInfo.classList.remove('text-rose-600');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeHtmlToFrame(html) {
|
||||
iframe.srcdoc = `<!doctype html><html>
|
||||
@@ -210,67 +210,13 @@ export function initEditor() {
|
||||
function showVeil(){ ensureVeil().style.display = 'flex'; }
|
||||
function hideVeil(){ if (veilEl) veilEl.style.display = 'none'; }
|
||||
|
||||
// ... (Kontext-Filter-Ladung bleibt unverändert) ...
|
||||
async function listBlocksForTemplate(templateId){
|
||||
try {
|
||||
const direct = await apiList('blocks', { template_id: templateId });
|
||||
if (Array.isArray(direct) && direct.length) return direct;
|
||||
} catch {}
|
||||
const sections = await apiList('sections', { template_id: templateId }).catch(()=>[]);
|
||||
const out = [];
|
||||
for (const s of (sections || [])) {
|
||||
const b = await apiList('blocks', { section_id: s.id }).catch(()=>[]);
|
||||
if (b?.length) out.push(...b);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
// Snippets eines Templates (direkt oder via Sections->Blocks als Fallback)
|
||||
async function listSnippetsForTemplate(templateId){
|
||||
try {
|
||||
const direct = await apiList('snippets', { template_id: templateId });
|
||||
if (Array.isArray(direct) && direct.length) return direct;
|
||||
} catch {}
|
||||
const sections = await apiList('sections', { template_id: templateId }).catch(()=>[]);
|
||||
const blocksAll = [];
|
||||
for (const s of (sections || [])) {
|
||||
const b = await apiList('blocks', { section_id: s.id }).catch(()=>[]);
|
||||
if (b?.length) blocksAll.push(...b);
|
||||
}
|
||||
const out = [];
|
||||
for (const b of blocksAll) {
|
||||
const sn = await apiList('snippets', { block_id: b.id }).catch(()=>[]);
|
||||
if (sn?.length) out.push(...sn);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
// Referenz-Bibliothek (für „Custom – Fix“)
|
||||
async function buildRefLibForContext(ctx){
|
||||
const kind = (ctx.resource || 'templates').replace(/s$/,''); // template|section|block
|
||||
const id = ctx.id;
|
||||
if (kind === 'template'){
|
||||
const [sections, blocks] = await Promise.all([
|
||||
apiList('sections', { template_id: id }).catch(()=>[]),
|
||||
listBlocksForTemplate(id)
|
||||
]);
|
||||
return { sections, blocks };
|
||||
}
|
||||
if (kind === 'section'){
|
||||
const blocks = await apiList('blocks', { section_id: id }).catch(()=>[]);
|
||||
return { sections: [], blocks };
|
||||
}
|
||||
return { sections: [], blocks: [] }; // block -> keine Sections/Blocks in Fix
|
||||
}
|
||||
// Snippets (für „Custom – Flex“) kontextabhängig
|
||||
async function buildSnippetsForContext(ctx){
|
||||
const kind = (ctx.resource || 'templates').replace(/s$/,'');
|
||||
const id = ctx.id;
|
||||
let rows = [];
|
||||
if (kind === 'template') rows = await listSnippetsForTemplate(id);
|
||||
else if (kind === 'section') rows = await apiList('snippets', { section_id: id }).catch(()=>[]);
|
||||
else if (kind === 'block') rows = await apiList('snippets', { block_id: id }).catch(()=>[]);
|
||||
else rows = await apiList('snippets').catch(()=>[]);
|
||||
return (rows || []).map(r => ({ id: r.id, name: r.name, html: r.content || r.html || '' }));
|
||||
}
|
||||
async function buildRefLibForContext() {
|
||||
return { sections: [], blocks: [] };
|
||||
}
|
||||
|
||||
async function buildSnippetsForContext() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async function loadSenderOptions(force = false) {
|
||||
if (!sendSender) return;
|
||||
@@ -338,19 +284,22 @@ export function initEditor() {
|
||||
}
|
||||
|
||||
// ---------- Öffnen ----------
|
||||
async function open(item, resource) {
|
||||
async function open(item, resource, sectionOverride) {
|
||||
const section = item?.section || sectionOverride || window.__activeSection || null;
|
||||
current = {
|
||||
resource: String(resource || activeMode() || 'templates').toLowerCase(),
|
||||
resource: 'content',
|
||||
id: Number(item?.id || 0),
|
||||
name: item?.name || ''
|
||||
name: item?.name || '',
|
||||
section: section,
|
||||
};
|
||||
if (!current.id) return err('Ungültige ID');
|
||||
if (!current.section) return err('Section nicht gefunden');
|
||||
|
||||
// globaler Kontext
|
||||
window.__currentItemId = current.id;
|
||||
window.__currentEditorCtx = { id: current.id, mode: current.resource };
|
||||
setSendContext(current.id, current.name);
|
||||
if (btnTest) btnTest.classList.toggle('hidden', current.resource !== 'templates');
|
||||
window.__currentEditorCtx = { id: current.id, mode: current.section.slug, section: current.section };
|
||||
setSendContext(current.section?.is_template ? current.id : 0, current.name);
|
||||
if (btnTest) btnTest.classList.toggle('hidden', !current.section?.is_template);
|
||||
|
||||
// Neuen Token erzeugen & alten Listener entfernen
|
||||
reqToken++;
|
||||
@@ -374,7 +323,7 @@ export function initEditor() {
|
||||
await Promise.all([
|
||||
(async() => {
|
||||
try {
|
||||
const row = await apiGet(current.resource, current.id);
|
||||
const row = await apiAction('content.get', { method: 'GET', data: { id: current.id, section_id: current.section.id } });
|
||||
const rawContent = row?.content ?? row?.item?.content ?? '';
|
||||
const trimmed = String(rawContent || '').trim();
|
||||
const looksJson = trimmed.startsWith('{') || trimmed.startsWith('[');
|
||||
@@ -403,10 +352,11 @@ export function initEditor() {
|
||||
if (!looksCraftSerialized(craftJson) && craftEditor?.serializeFromHtml) {
|
||||
const seed = craftEditor.serializeFromHtml(craftHtml);
|
||||
try {
|
||||
await apiUpdate(current.resource, current.id, {
|
||||
await apiUpdate('content', current.id, {
|
||||
editor_type: 'craftjs',
|
||||
html: craftHtml,
|
||||
craft_json: seed
|
||||
craft_json: seed,
|
||||
section_id: current.section.id,
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
@@ -436,7 +386,7 @@ export function initEditor() {
|
||||
ok('Gespeichert');
|
||||
try {
|
||||
if (typeof window.reloadActiveList === 'function') window.reloadActiveList();
|
||||
else if (typeof window.__reloadList === 'function') window.__reloadList(current.resource);
|
||||
else if (typeof window.__reloadList === 'function') window.__reloadList(current.section);
|
||||
} catch {}
|
||||
return;
|
||||
}
|
||||
@@ -444,7 +394,7 @@ export function initEditor() {
|
||||
// neue Bridge meldet gjs:ready; ältere evtl. core-ready/bridge:ready
|
||||
if (d.type === 'gjs:ready' || d.type === 'core-ready' || d.type === 'bridge:ready' || d.type === 'bridge:booted') {
|
||||
pushInitialHtmlToEditor({
|
||||
mode: current.resource,
|
||||
mode: current.section.slug,
|
||||
html: fresh,
|
||||
snippets,
|
||||
ref: {
|
||||
@@ -462,7 +412,7 @@ export function initEditor() {
|
||||
// Fallback, falls kein Ready ankommt
|
||||
setTimeout(() => {
|
||||
pushInitialHtmlToEditor({
|
||||
mode: current.resource,
|
||||
mode: current.section.slug,
|
||||
html: fresh,
|
||||
snippets,
|
||||
ref: {
|
||||
@@ -474,10 +424,10 @@ export function initEditor() {
|
||||
json: jsonState
|
||||
});
|
||||
}, 1200);
|
||||
};
|
||||
};
|
||||
|
||||
// Jetzt den Editor-Core laden (erst NACH about:blank)
|
||||
iframe.src = `editor/editor-core.php?mode=${encodeURIComponent(current.resource)}&id=${current.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?.();
|
||||
}
|
||||
@@ -492,8 +442,8 @@ export function initEditor() {
|
||||
const craftJson = craftEditor && craftEditor.getCraftJson
|
||||
? craftEditor.getCraftJson()
|
||||
: JSON.stringify({ html });
|
||||
const payload = { html, craft_json: craftJson, editor_type: 'craftjs' };
|
||||
const res = await apiUpdate(current.resource, current.id, payload);
|
||||
const payload = { html, craft_json: craftJson, editor_type: 'craftjs', section_id: current.section.id };
|
||||
const res = await apiUpdate('content', current.id, payload);
|
||||
if (res?.ok) ok('Gespeichert');
|
||||
else err(res?.error || 'Speichern fehlgeschlagen');
|
||||
return res?.ok;
|
||||
@@ -525,7 +475,11 @@ export function initEditor() {
|
||||
}
|
||||
|
||||
async function openSend(ctx = null) {
|
||||
const ctxId = ctx?.id ? Number(ctx.id) : (window.__currentItemId || current?.id || 0);
|
||||
if (!current?.section?.is_template) {
|
||||
err('Kein Template geladen');
|
||||
return;
|
||||
}
|
||||
const ctxId = ctx?.id ? Number(ctx.id) : (window.__currentItemId || current?.id || 0);
|
||||
if (!ctxId) {
|
||||
err('Kein Template geladen');
|
||||
return;
|
||||
@@ -600,10 +554,11 @@ export function initEditor() {
|
||||
const craftJson = craftEditor && craftEditor.serializeFromHtml
|
||||
? craftEditor.serializeFromHtml(html)
|
||||
: JSON.stringify({ html });
|
||||
const res = await apiUpdate(current.resource, current.id, {
|
||||
const res = await apiUpdate('content', current.id, {
|
||||
editor_type: 'craftjs',
|
||||
html,
|
||||
craft_json: craftJson
|
||||
craft_json: craftJson,
|
||||
section_id: current.section.id,
|
||||
});
|
||||
if (!res?.ok) {
|
||||
err(res?.error || 'Editorwechsel fehlgeschlagen');
|
||||
@@ -618,9 +573,10 @@ export function initEditor() {
|
||||
}
|
||||
if (currentEditorType === 'craftjs' && target === 'grapesjs') {
|
||||
const html = craftEditor ? craftEditor.getContent() : '';
|
||||
const res = await apiUpdate(current.resource, current.id, {
|
||||
const res = await apiUpdate('content', current.id, {
|
||||
editor_type: 'grapesjs',
|
||||
html
|
||||
html,
|
||||
section_id: current.section.id,
|
||||
});
|
||||
if (!res?.ok) {
|
||||
err(res?.error || 'Editorwechsel fehlgeschlagen');
|
||||
@@ -628,7 +584,7 @@ export function initEditor() {
|
||||
return;
|
||||
}
|
||||
ok('Editor gewechselt');
|
||||
await open({ id: current.id, name: current.name }, current.resource);
|
||||
await open({ id: current.id, name: current.name, section: current.section }, 'content', current.section);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,17 +599,21 @@ export function initEditor() {
|
||||
sendForm && (sendForm.onsubmit = doSend);
|
||||
editorSelect && (editorSelect.onchange = () => switchEditor(editorSelect.value));
|
||||
|
||||
window.AdminTestSend = window.AdminTestSend || {};
|
||||
window.AdminTestSend.open = (opts = {}) => {
|
||||
const targetId = Number(opts.id || window.__currentItemId || 0);
|
||||
if (!targetId) {
|
||||
err('Testversand: Keine ID vorhanden');
|
||||
return;
|
||||
}
|
||||
window.__currentItemId = targetId;
|
||||
setSendContext(targetId, opts.name || '');
|
||||
openSend({ id: targetId, name: opts.name || '' });
|
||||
};
|
||||
window.AdminTestSend = window.AdminTestSend || {};
|
||||
window.AdminTestSend.open = (opts = {}) => {
|
||||
const targetId = Number(opts.id || window.__currentItemId || 0);
|
||||
if (!targetId) {
|
||||
err('Testversand: Keine ID vorhanden');
|
||||
return;
|
||||
}
|
||||
if (!current?.section?.is_template) {
|
||||
err('Kein Template geladen');
|
||||
return;
|
||||
}
|
||||
window.__currentItemId = targetId;
|
||||
setSendContext(targetId, opts.name || '');
|
||||
openSend({ id: targetId, name: opts.name || '' });
|
||||
};
|
||||
|
||||
// Public API
|
||||
window.EditorUI = { open, save, close, clear: clearEditor, preview: openPreview };
|
||||
|
||||
Reference in New Issue
Block a user