2 Commits

Author SHA1 Message Date
Kendrick Bollens
730d32ab29 Web-Editor: Farben/Inline-Styles beim Einfügen aus E-Mails behalten
TinyMCE registriert unter Chromium (Chrome/Edge) und Safari einen
PastePreProcess-Filter, der bei der Default-Einstellung
paste_webkit_styles:'none' ALLE inline-Styles (inkl. color) aus extern
eingefügtem Inhalt entfernt. Interner Copy/Paste ist ausgenommen — daher
ging webapp->webapp, aber E-Mail->Editor verlor die Farbe.

paste_webkit_styles:'all' schaltet den Stripper ab und behält die Styles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GkKJBbiNV421xfCbXikGV
2026-07-23 11:37:29 +02:00
Kendrick Bollens
3f792a6434 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
2026-07-23 11:21:51 +02:00

View File

@@ -364,7 +364,9 @@
valid_elements: '*[*]', extended_valid_elements: '*[*]', valid_children: '+body[style]', valid_elements: '*[*]', extended_valid_elements: '*[*]', valid_children: '+body[style]',
verify_html: false, convert_urls: false, verify_html: false, convert_urls: false,
content_style: 'body{font-family:Arial,Helvetica,sans-serif;font-size:14px;color:#1f2a30;line-height:1.6;padding:10px 12px;} img{max-width:100%;height:auto;} table{border-collapse:collapse;}', content_style: 'body{font-family:Arial,Helvetica,sans-serif;font-size:14px;color:#1f2a30;line-height:1.6;padding:10px 12px;} img{max-width:100%;height:auto;} table{border-collapse:collapse;}',
paste_data_images: true, automatic_uploads: false, file_picker_types: 'image', // Chrome/Edge/Safari entfernen sonst beim Einfügen aus externen Quellen (E-Mails)
// ALLE inline-Styles inkl. Farben ('paste_webkit_styles' default 'none'). 'all' behält sie.
paste_data_images: true, paste_webkit_styles: 'all', automatic_uploads: false, file_picker_types: 'image',
file_picker_callback: function (cb) { file_picker_callback: function (cb) {
const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*';
input.onchange = function () { const file = input.files[0]; if (!file) return; const r = new FileReader(); r.onload = function () { cb(r.result, { title: file.name }); }; r.readAsDataURL(file); }; input.onchange = function () { const file = input.files[0]; if (!file) return; const r = new FileReader(); r.onload = function () { cb(r.result, { title: file.name }); }; r.readAsDataURL(file); };
@@ -374,6 +376,38 @@
ed = editor; ed = editor;
editor.on('init', function () { edReady = true; }); editor.on('init', function () { edReady = true; });
editor.on('input ExecCommand Undo Redo SetContent paste', function () { if (!suppressDirty) markDirty(); }); 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; }); }).then(() => { edReady = true; });
} }