Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
730d32ab29 | ||
|
|
3f792a6434 | ||
|
|
8057870f8b | ||
|
|
2b6e2267c2 |
@@ -276,31 +276,50 @@ async function handleInsertTemplate(msg) {
|
|||||||
const newBody = msg.text + (old ? '\n' + old : '');
|
const newBody = msg.text + (old ? '\n' + old : '');
|
||||||
await browser.compose.setComposeDetails(tab.id, { plainTextBody: newBody });
|
await browser.compose.setComposeDetails(tab.id, { plainTextBody: newBody });
|
||||||
} else {
|
} else {
|
||||||
// HTML mode: use insertText API to go through the editor's rendering pipeline
|
// HTML mode: wrap the template in a marker element (id=hps-vorlage) and
|
||||||
|
// replace any previously inserted one — so durchswitchen ersetzt statt stapelt.
|
||||||
const htmlContent = isHtmlTemplate ? msg.text : msg.text.replace(/\n/g, '<br>');
|
const htmlContent = isHtmlTemplate ? msg.text : msg.text.replace(/\n/g, '<br>');
|
||||||
|
|
||||||
// Move cursor to beginning of body first via script injection
|
// Directly manipulate the editor DOM: remove the old template block (if any),
|
||||||
await browser.tabs.executeScript(tab.id, {
|
// then insert the new one at the top of the body. Returns true on success.
|
||||||
|
const injected = await browser.tabs.executeScript(tab.id, {
|
||||||
code: `
|
code: `
|
||||||
|
(function () {
|
||||||
const editor = document.getElementById('messageEditor');
|
const editor = document.getElementById('messageEditor');
|
||||||
const editorDoc = editor ? editor.contentDocument : document;
|
const editorDoc = editor ? editor.contentDocument : document;
|
||||||
const body = editorDoc.body;
|
const body = editorDoc && editorDoc.body;
|
||||||
if (body) {
|
if (!body) return false;
|
||||||
|
|
||||||
|
// Remove a previously inserted template block, so switching replaces it
|
||||||
|
const prev = editorDoc.getElementById('hps-vorlage');
|
||||||
|
if (prev) prev.remove();
|
||||||
|
|
||||||
|
// Wrap the new template in a marker element with a stable id
|
||||||
|
const wrapper = editorDoc.createElement('div');
|
||||||
|
wrapper.id = 'hps-vorlage';
|
||||||
|
wrapper.innerHTML = ${JSON.stringify(htmlContent)};
|
||||||
|
|
||||||
|
// Insert at the very top of the body (above quote/signature/typed text)
|
||||||
|
body.insertBefore(wrapper, body.firstChild);
|
||||||
|
|
||||||
|
// Place the cursor right after the inserted block
|
||||||
const range = editorDoc.createRange();
|
const range = editorDoc.createRange();
|
||||||
range.setStart(body, 0);
|
range.setStartAfter(wrapper);
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
const sel = editorDoc.getSelection();
|
const sel = editorDoc.getSelection();
|
||||||
sel.removeAllRanges();
|
sel.removeAllRanges();
|
||||||
sel.addRange(range);
|
sel.addRange(range);
|
||||||
}
|
return true;
|
||||||
|
})();
|
||||||
`
|
`
|
||||||
}).catch(() => {
|
}).then(r => (Array.isArray(r) ? r[0] : r)).catch(() => false);
|
||||||
// Fallback: some TB versions structure the editor differently
|
|
||||||
});
|
|
||||||
|
|
||||||
// Insert HTML at cursor position - this goes through the editor's render pipeline
|
if (!injected) {
|
||||||
|
// Fallback: editor DOM not reachable (TB version differences) — use the
|
||||||
|
// insertText pipeline. Note: this variant cannot replace, only prepend.
|
||||||
await browser.compose.insertText(tab.id, htmlContent + '<br>', { insertAsText: false });
|
await browser.compose.insertText(tab.id, htmlContent + '<br>', { insertAsText: false });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('background.js error:', e);
|
console.error('background.js error:', e);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "HPS Vorlagen & Signaturen",
|
"name": "HPS Vorlagen & Signaturen",
|
||||||
"version": "2.5.0",
|
"version": "2.6.0",
|
||||||
"description": "Vorlagen- und Signaturverwaltung für Hotel Park Soltau mit Git-Sync",
|
"description": "Vorlagen- und Signaturverwaltung für Hotel Park Soltau mit Git-Sync",
|
||||||
"browser_specific_settings": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
|
|||||||
Binary file not shown.
10
updates.json
10
updates.json
@@ -2,6 +2,16 @@
|
|||||||
"addons": {
|
"addons": {
|
||||||
"it@hotel-park-soltau.de": {
|
"it@hotel-park-soltau.de": {
|
||||||
"updates": [
|
"updates": [
|
||||||
|
{
|
||||||
|
"version": "2.6.0",
|
||||||
|
"update_link": "https://git.hotel-park-soltau.de/hps/hps-thunderbird-templates/releases/download/v2.6.0/templates-reply-hotel.xpi",
|
||||||
|
"update_hash": "sha256:563e65f7686db7be30712fbc2be934f51c9ce8f4d35bb37f07046d8da40b562d",
|
||||||
|
"applications": {
|
||||||
|
"gecko": {
|
||||||
|
"strict_min_version": "109.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"update_link": "https://git.hotel-park-soltau.de/hps/hps-thunderbird-templates/releases/download/v2.5.0/templates-reply-hotel.xpi",
|
"update_link": "https://git.hotel-park-soltau.de/hps/hps-thunderbird-templates/releases/download/v2.5.0/templates-reply-hotel.xpi",
|
||||||
|
|||||||
@@ -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; });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user