Web-Editor: robustes Einfügen aus externen Quellen (E-Mails)

TinyMCEs Standard-Paste nutzt bei externem Inhalt einen fragilen
Pastebin-Fallback, der bei manchen Quellen (E-Mail-Clients) still
fehlschlägt → "nichts passiert". Interner Copy/Paste ging, weil TinyMCE
dabei text/html selbst auf die Zwischenablage setzt.

Eigener paste-Handler liest text/html bzw. text/plain direkt aus und
fügt es deterministisch ein (Formatierung bleibt erhalten, Office/Outlook-
Fragment wird ausgeschnitten). Interner Paste und Bild-Paste bleiben dem
Standard-Handler überlassen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GkKJBbiNV421xfCbXikGV
This commit is contained in:
Kendrick Bollens
2026-07-23 11:21:51 +02:00
parent 8057870f8b
commit 3f792a6434

View File

@@ -374,6 +374,38 @@
ed = editor;
editor.on('init', function () { edReady = true; });
editor.on('input ExecCommand Undo Redo SetContent paste', function () { if (!suppressDirty) markDirty(); });
// Robustes Einfügen aus externen Quellen (z.B. E-Mails). TinyMCEs eigener
// Fallback (verstecktes „Pastebin"-Feld) schlägt bei manchen Quellen still
// fehl → „nichts passiert". Wir lesen die Zwischenablage direkt aus und
// fügen HTML mitsamt Formatierung ein. Interner Copy/Paste (funktioniert
// bereits) und Bild-Paste bleiben dem Standard-Handler überlassen.
editor.on('paste', function (e) {
const cd = e.clipboardData;
if (!cd) return; // keine Zwischenablage → Standard-Handler versuchen lassen
let html = '';
try { html = cd.getData('text/html') || ''; } catch (_) {}
// TinyMCE-interner Inhalt trägt diesen Marker → Standard-Pfad übernehmen.
if (html.indexOf('x-tinymce/html') !== -1) return;
let text = '';
try { text = cd.getData('text/plain') || ''; } catch (_) {}
// Reines Bild (Screenshot o.ä.) → TinyMCEs Bildverarbeitung übernehmen.
const hasImage =
(cd.types && Array.prototype.indexOf.call(cd.types, 'Files') !== -1) ||
(cd.items && Array.prototype.some.call(cd.items, function (it) { return it.kind === 'file' && /^image\//.test(it.type); }));
if (!html && !text && hasImage) return;
if (!html && !text) return; // nichts Brauchbares → Standard-Fallback lassen
e.preventDefault(); // unterdrückt den fragilen TinyMCE-Standard-Handler
let content;
if (html) {
// Office/Outlook markieren die eigentliche Auswahl per Fragment-Kommentar.
const frag = /<!--\s*StartFragment\s*-->([\s\S]*?)<!--\s*EndFragment\s*-->/i.exec(html);
content = frag ? frag[1] : html;
} else {
content = editor.dom.encode(text).replace(/\r\n?|\n/g, '<br>');
}
editor.insertContent(content);
markDirty();
});
},
}).then(() => { edReady = true; });
}