fix: show one signature separator when the signature brings its own

This commit is contained in:
Linus Rath
2026-10-15 02:36:11 +02:00
parent cbc41c963b
commit 90170ea0e7
4 changed files with 53 additions and 9 deletions
+21
View File
@@ -12,6 +12,7 @@ import {
insertSignatureAboveQuote,
signatureIdentityFor,
signPlainTextReply,
signatureHasOwnDelimiter,
} from '../signature-utils';
describe('sanitizeSignatureHtml', () => {
@@ -115,3 +116,23 @@ describe('signPlainTextReply', () => {
expect(signPlainTextReply('Thanks', 'q', null, { position: 'above_quote', separator: true })).toBe('Thanks\n\nq');
});
});
describe('a signature with its own "-- " line', () => {
const own = { textSignature: '-- \nUser A\nstw-test' };
const plain = { textSignature: 'User A\nstw-test' };
it('is detected, also with a bare "--" or a leading blank line', () => {
expect(signatureHasOwnDelimiter(own)).toBe(true);
expect(signatureHasOwnDelimiter({ textSignature: '\n--\nUser A' })).toBe(true);
expect(signatureHasOwnDelimiter(plain)).toBe(false);
expect(signatureHasOwnDelimiter({ htmlSignature: '<p>-- </p><p>User A</p>' })).toBe(true);
});
it('gets no second separator in plain text or HTML', () => {
const delimiters = (text: string) => text.split('\n').filter((line) => /^--\s*$/.test(line)).length;
expect(delimiters(appendPlainTextSignature('Hi', own, { separator: true }))).toBe(1);
expect(appendPlainTextSignature('Hi', plain, { separator: true })).toBe('Hi\n\n-- \nUser A\nstw-test');
expect(buildEmbeddedSignatureHtml(own, { separator: true })).not.toContain('="separator"');
expect(buildEmbeddedSignatureHtml(plain, { separator: true })).toContain('="separator"');
});
});
+5 -3
View File
@@ -13,7 +13,7 @@ import { htmlToPlainText } from './compose-html';
import {
buildEmbeddedSignatureHtml, containsEmbeddedSignature, getPlainTextSignature,
plainTextBodyHasSignature, plainTextBodyWithoutSignature, spliceSignature,
type SignatureSource,
wantsSignatureSeparator, type SignatureSource,
} from './signature-utils';
/**
@@ -67,7 +67,9 @@ export function htmlComposeBodyToPlainText(
const head = text.slice(0, at).replace(/\s+$/, '');
const tail = text.slice(at + SIGNATURE_TOKEN.length).replace(/^\s+/, '');
const signature = getPlainTextSignature(identity);
const withSignature = signature ? `${head}${separatorText(options.separator)}${signature}` : head;
const withSignature = signature
? `${head}${separatorText(wantsSignatureSeparator(options.separator, identity))}${signature}`
: head;
return tail ? `${withSignature}\n\n${tail}` : withSignature;
}
@@ -86,7 +88,7 @@ export function plainComposeBodyToHtml(
const signature = getPlainTextSignature(identity);
const embedded = signature ? buildEmbeddedSignatureHtml(identity, options) : '';
if (embedded) {
const marker = `${separatorText(options.separator)}${signature}`;
const marker = `${separatorText(wantsSignatureSeparator(options.separator, identity))}${signature}`;
const at = text.indexOf(marker);
if (at !== -1) {
const before = plainTextToComposerHtml(text.slice(0, at).replace(/^\n+/, ''));
+24 -3
View File
@@ -90,6 +90,27 @@ export function signatureIdentityFor<T extends { textSignature?: string; htmlSig
return primary && hasSignature(primary) ? primary : null;
}
/**
* Whether the signature starts with its own "-- " delimiter line. Many do
* (imported from other clients, or set on the server), and the composer's
* own separator on top of it showed two delimiter lines (webmail
* lib/signature-delimiter.ts).
*/
export function signatureHasOwnDelimiter(signature?: SignatureSource | null): boolean {
const text = signature?.textSignature?.trim()
? signature.textSignature
: signature?.htmlSignature?.trim()
? htmlToPlainText(sanitizeSignatureHtml(signature.htmlSignature))
: '';
const firstLine = text.replace(/\r\n?/g, '\n').replace(/^\s*\n/, '').split('\n')[0];
return /^--[ \t ]*$/.test(firstLine);
}
/** Whether to add the "-- " separator line in front of this signature. */
export function wantsSignatureSeparator(enabled: boolean | undefined, signature?: SignatureSource | null): boolean {
return enabled !== false && !signatureHasOwnDelimiter(signature);
}
export function getPlainTextSignature(signature?: SignatureSource): string {
if (signature?.textSignature?.trim()) {
return normalizeSignatureLineBreaks(signature.textSignature);
@@ -112,7 +133,7 @@ export function appendPlainTextSignature(
return body;
}
const sep = options.separator === false ? '\n\n' : '\n\n-- \n';
const sep = wantsSignatureSeparator(options.separator, signature) ? '\n\n-- \n' : '\n\n';
return `${body}${sep}${plainTextSignature}`;
}
@@ -186,7 +207,7 @@ export function appendHtmlSignature(
signature?: SignatureSource,
options: { separator?: boolean } = {},
): string {
const sep = options.separator === false ? '<br><br>' : '<br><br>-- <br>';
const sep = wantsSignatureSeparator(options.separator, signature) ? '<br><br>-- <br>' : '<br><br>';
if (signature?.htmlSignature?.trim()) {
return `${htmlBody}${sep}${sanitizeSignatureHtml(signature.htmlSignature)}`;
@@ -208,7 +229,7 @@ export function buildEmbeddedSignatureHtml(
identity: SignatureSource,
options: { separator: boolean },
): string {
const startMarker = options.separator
const startMarker = wantsSignatureSeparator(options.separator, identity)
? `<p ${SIGNATURE_RANGE_MARKER}="separator">-- </p>`
: `<p ${SIGNATURE_RANGE_MARKER}="start"></p>`;
const endMarker = `<p ${SIGNATURE_RANGE_MARKER}="end"><br></p>`;
+3 -3
View File
@@ -67,7 +67,7 @@ import { shouldBlockEditorRemoteImages } from '../lib/editor-html';
import {
signatureIdentityFor, buildEmbeddedSignatureHtml, containsEmbeddedSignature, spliceSignature,
insertSignatureAboveQuote, getPlainTextSignature, appendPlainTextSignature,
plainTextBodyHasSignature, plainTextBodyWithoutSignature, SIGNATURE_RANGE_MARKER,
plainTextBodyHasSignature, plainTextBodyWithoutSignature, SIGNATURE_RANGE_MARKER, wantsSignatureSeparator,
} from '../lib/signature-utils';
import {
getAutoFilledPlaceholders, getPlaceholdersFromTemplate, substitutePlaceholders, templateBodyToHtml,
@@ -1083,7 +1083,7 @@ export default function ComposeScreen({ route, navigation }: Props) {
const placeSignaturePlain = React.useCallback((body: string, identity: Identity): string => {
const sig = getPlainTextSignature(identity);
if (!sig) return body;
const sep = signatureSeparatorEnabled ? '\n\n-- \n' : '\n\n';
const sep = wantsSignatureSeparator(signatureSeparatorEnabled, identity) ? '\n\n-- \n' : '\n\n';
if (isReplyLike && signaturePosition === 'above_quote') {
const idx = body.indexOf('\n\n');
const head = idx === -1 ? body : body.slice(0, idx);
@@ -1139,7 +1139,7 @@ export default function ComposeScreen({ route, navigation }: Props) {
stripped = plainTextBodyWithoutSignature(body, prev);
} else if (prev) {
const old = getPlainTextSignature(prev);
const marker = `${signatureSeparatorEnabled ? '\n\n-- \n' : '\n\n'}${old}`;
const marker = `${wantsSignatureSeparator(signatureSeparatorEnabled, prev) ? '\n\n-- \n' : '\n\n'}${old}`;
if (old && body.includes(marker)) stripped = body.replace(marker, '');
}
return signatureIdentity ? placeSignaturePlain(stripped, signatureIdentity) : stripped;