Fix: keep signature when inserting a template #621

This commit is contained in:
Linus Rath
2026-07-16 20:13:07 +02:00
parent 739b72d251
commit 4a4950c3e5
3 changed files with 69 additions and 3 deletions
+37
View File
@@ -10,6 +10,7 @@ import {
filterTemplates,
exportTemplates,
importTemplates,
spliceTemplateAboveSignature,
} from '../template-utils';
import type { EmailTemplate } from '../template-types';
@@ -333,3 +334,39 @@ describe('filterTemplates', () => {
expect(filterTemplates(templates, 'xyz')).toHaveLength(0);
});
});
describe('spliceTemplateAboveSignature', () => {
const template = '<p>Template body</p>';
it('keeps the signature block below the template (separator marker)', () => {
const prev = '<p></p><p data-signature-block="separator">-- </p><div>My signature</div><p data-signature-block="end"></p>';
expect(spliceTemplateAboveSignature(prev, template)).toBe(
'<p>Template body</p><p data-signature-block="separator">-- </p><div>My signature</div><p data-signature-block="end"></p>'
);
});
it('keeps the signature block below the template (start marker, no separator)', () => {
const prev = '<p>old draft text</p><p data-signature-block="start"></p><div>My signature</div><p data-signature-block="end"></p>';
expect(spliceTemplateAboveSignature(prev, template)).toBe(
'<p>Template body</p><p data-signature-block="start"></p><div>My signature</div><p data-signature-block="end"></p>'
);
});
it('replaces the whole body when there is no signature block', () => {
expect(spliceTemplateAboveSignature('<p>old draft text</p>', template)).toBe(template);
});
it('keeps everything from the start marker onward when the end marker is missing', () => {
const prev = '<p>old</p><p data-signature-block="separator">-- </p><div>My signature</div>';
expect(spliceTemplateAboveSignature(prev, template)).toBe(
'<p>Template body</p><p data-signature-block="separator">-- </p><div>My signature</div>'
);
});
it('discards user edits above the signature', () => {
const prev = '<p>half-written draft</p><p data-signature-block="separator">-- </p><div>Sig</div><p data-signature-block="end"></p>';
const result = spliceTemplateAboveSignature(prev, template);
expect(result).not.toContain('half-written draft');
expect(result).toContain('Sig');
});
});
+20
View File
@@ -80,6 +80,26 @@ export function filterTemplates(templates: EmailTemplate[], query: string): Emai
);
}
// Compose bodies carry the embedded signature bracketed by
// data-signature-block markers (see email-composer's
// buildEmbeddedSignatureHtml). Applying a template must replace only the
// message content, so splice the template above the signature range instead
// of overwriting the whole body.
export function spliceTemplateAboveSignature(prevHtml: string, templateHtml: string): string {
const doc = new DOMParser().parseFromString(prevHtml, 'text/html');
const startEl = doc.querySelector('[data-signature-block="separator"], [data-signature-block="start"]');
if (!startEl) return templateHtml;
const endEl = doc.querySelector('[data-signature-block="end"]');
const host = doc.createElement('div');
let cursor: Node | null = startEl;
while (cursor) {
host.appendChild(cursor.cloneNode(true));
if (cursor === endEl) break;
cursor = cursor.nextSibling;
}
return templateHtml + host.innerHTML;
}
function sanitizeText(value: unknown): string {
return DOMPurify.sanitize(String(value || ''), STRIP_HTML_CONFIG);
}