From 3752a531f16ea331184a908166b0bad69bfb013d Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Sat, 17 Jan 2026 04:05:22 +0100 Subject: [PATCH] update --- README.md | 22 ++++++++++++-- README.txt | 4 ++- public/editor/bridge-core.js | 58 ++++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9ca00f3..4449c39 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # Mailadmin – Email Template System (R17 modular) -Stand: 2025-08-31 +Stand: 2026-01-17 + +## Kurzuebersicht +- Admin UI fuer Templates, Sections und Snippets +- GrapesJS Editor lokal eingebunden (kein CDN) +- Modularer Bridge-Core fuer Blöcke, Kategorien und Editor-Erweiterungen +- JSON API mit Dual-DB und Prefix-Support ## Struktur mailadmin/ @@ -23,8 +29,12 @@ mailadmin/ ui-editor.js # Editor-Dialog + Handshake editor/ editor-core.php # LÄDT NUR LOKAL (kein CDN) - bridge-core.js + bridge-core.js # Loader + Guards + Editor-Orchestrierung config.js # Bibliothek in Block-Leiste + public/assets/js/bridge/ + rte-editor.js # RichText-Editor (Modal) + table-builder.js # Table Builder (Modal) + blocks-*.js # Block-Definitionen ## Vendor (lokal bereitstellen) Lege die GrapesJS-Dateien lokal ab (kein CDN): @@ -36,10 +46,16 @@ Lege die GrapesJS-Dateien lokal ab (kein CDN): Nutze `schema.sql` (inkl. *NULL‑fähiger* Fremdschlüssel & ON DELETE SET NULL). Prefix standardmäßig: `emailtemplate_`. +## Editor-Flags (window.BridgeParts) +- ENABLE_EDITOR_EXTENSIONS +- ENABLE_EDITOR_BEHAVIOR +- ENABLE_PLACEHOLDERS +- ENABLE_TABLE_BUILDER +- ENABLE_RTE + ## Schnellstart 1) `mailadmin/inc/config.php` anlegen (siehe `config.example.php`). 2) `schema.sql` in deiner Templates-Datenbank ausführen. 3) Vendor-Dateien in `public/vendor/...` kopieren. 4) `public/tools/config-doctor.php` & `public/api.php?action=health` prüfen. 5) `public/index.php` öffnen → „Neu …“, „Vorschau“, „Im E‑Mail‑Editor öffnen“ etc. - diff --git a/README.txt b/README.txt index 6aba98d..1f03041 100644 --- a/README.txt +++ b/README.txt @@ -1 +1,3 @@ -This archive contains the R17 modular Email Template System. Fill inc/config.php and vendor libs. \ No newline at end of file +Mailadmin ist ein modulares Email-Template-System mit Admin-UI und lokal eingebundenem GrapesJS-Editor. +Es verwaltet Templates, Sections und Snippets, nutzt eine JSON-API mit Prefix-Support +und laesst sich ueber Bridge-Module (Blocks, RTE, Table Builder) erweitern. diff --git a/public/editor/bridge-core.js b/public/editor/bridge-core.js index cac327a..71cf083 100644 --- a/public/editor/bridge-core.js +++ b/public/editor/bridge-core.js @@ -32,13 +32,17 @@ window.__bridgeModalGuardsInstalled = true; window.__bridgeModalAllowClose = false; + const allowCloseOnce = () => { + window.__bridgeModalAllowClose = true; + setTimeout(() => { window.__bridgeModalAllowClose = false; }, 0); + }; + document.addEventListener('click', (evt) => { const closeHit = evt.target && evt.target.closest ? evt.target.closest('.gjs-mdl-btn-close,[data-bridge-modal-close="1"]') : null; if (closeHit) { - window.__bridgeModalAllowClose = true; - setTimeout(() => { window.__bridgeModalAllowClose = false; }, 0); + allowCloseOnce(); } const container = evt.target && evt.target.closest ? evt.target.closest('.gjs-mdl-container') @@ -53,6 +57,15 @@ } }, true); + document.addEventListener('mousedown', (evt) => { + const closeHit = evt.target && evt.target.closest + ? evt.target.closest('.gjs-mdl-btn-close,[data-bridge-modal-close="1"]') + : null; + if (closeHit) { + allowCloseOnce(); + } + }, true); + document.addEventListener('keydown', (evt) => { if (evt.key !== 'Escape') return; const hasModal = document.querySelector('.gjs-mdl-container'); @@ -603,9 +616,9 @@ try { const modalEl = ed.Modal && ed.Modal.el; if (!modalEl) return; - if (modalEl.querySelector('[data-bridge-viewcode-close]')) return; const contentEl = modalEl.querySelector('.gjs-mdl-content'); if (!contentEl) return; + if (modalEl.querySelector('[data-bridge-viewcode-close]')) return; const footer = document.createElement('div'); footer.style.display = 'flex'; footer.style.justifyContent = 'flex-end'; @@ -629,6 +642,45 @@ } catch {} }); } + + if (ed && ed.Modal && ed.Modal.getModel && !ed.Modal.__bridgeModelHooked) { + ed.Modal.__bridgeModelHooked = true; + const mdl = ed.Modal.getModel(); + if (mdl && typeof mdl.on === 'function') { + mdl.on('change:open', () => { + if (!mdl.get('open')) return; + setTimeout(() => { + try { + const modalEl = ed.Modal && ed.Modal.el; + if (!modalEl) return; + const contentEl = modalEl.querySelector('.gjs-mdl-content'); + if (!contentEl) return; + if (modalEl.querySelector('[data-bridge-viewcode-close]')) return; + const footer = document.createElement('div'); + footer.style.display = 'flex'; + footer.style.justifyContent = 'flex-end'; + footer.style.paddingTop = '12px'; + const btn = document.createElement('button'); + btn.type = 'button'; + btn.textContent = 'Schließen'; + btn.setAttribute('data-bridge-viewcode-close', '1'); + btn.setAttribute('data-bridge-modal-close', '1'); + btn.style.padding = '6px 12px'; + btn.style.border = '1px solid #cbd5f5'; + btn.style.borderRadius = '4px'; + btn.style.background = '#f8fafc'; + btn.style.cursor = 'pointer'; + btn.addEventListener('click', () => { + if (B.allowModalCloseOnce) B.allowModalCloseOnce(); + if (ed.Modal && ed.Modal.close) ed.Modal.close(); + }); + footer.appendChild(btn); + contentEl.appendChild(footer); + } catch {} + }, 0); + }); + } + }                  // 🛑 KRITISCHE KORREKTUR 1: Explizite Erstellung aller konfigurierten Kategorien         ensureConfiguredCategories(ed);