<commit_before>import { MailSettings } from '@proton/shared/lib/interfaces';
import { isPlainText } from '@proton/shared/lib/mail/messages';
import { message } from '@proton/shared/lib/sanitize';
import isTruthy from '@proton/shared/lib/helpers/isTruthy';
import { getProtonMailSignature } from '@proton/shared/lib/mail/signature';
import { dedentTpl } from '../dedent';
import { replaceLineBreaks } from '../string';
import { parseInDiv, isHTMLEmpty } from '../dom';
import { getPlainTextContent, exportPlainText } from './messageContent';
import { CLASSNAME_BLOCKQUOTE } from './messageDraft';
import { MESSAGE_ACTIONS } from '../../constants';
import { MessageState } from '../../logic/messages/messagesTypes';

export const CLASSNAME_SIGNATURE_CONTAINER = 'protonmail_signature_block';
export const CLASSNAME_SIGNATURE_USER = 'protonmail_signature_block-user';
export const CLASSNAME_SIGNATURE_PROTON = 'protonmail_signature_block-proton';
export const CLASSNAME_SIGNATURE_EMPTY = 'protonmail_signature_block-empty';

/**
 * Preformat the protonMail signature
 */
const getProtonSignature = (mailSettings: Partial<MailSettings> = {}) =>
    mailSettings.PMSignature === 0 ? '' : getProtonMailSignature();

/**
 * Generate a space tag, it can be hidden from the UX via a className
 */
const createSpace = (style?: string, className?: string) => {
    const tagOpen = [
        'div',
        style === undefined ? undefined : `style="${style}"`,
        className === undefined ? undefined : `class="${className}"`,
    ]
        .filter(isTruthy)
        .join(' ');
    return `<${tagOpen}><br /></div>`;
};

/**
 * Generate spaces for the signature
 *     No signature: 1 space
 *     addressSignature: 2 spaces + addressSignature
 *     protonSignature: 2 spaces + protonSignature
 *     user + proton signature: 2 spaces + addressSignature + 1 space + protonSignature
 */
const getSpaces = (signature: string, protonSignature: string, fontStyle: string | undefined, isReply = false) => {
    const isUserEmpty = isHTMLEmpty(signature);
    const isEmptySignature = isUserEmpty && !protonSignature;
    return {
        start: isEmptySignature ? createSpace(fontStyle) : createSpace(fontStyle) + createSpace(fontStyle),
        end: isReply ? createSpace(fontStyle) : '',
        between: !isUserEmpty && protonSignature ? createSpace(fontStyle) : '',
    };
};

/**
 * Generate a map of classNames used for the signature template
 */
const getClassNamesSignature = (signature: string, protonSignature: string) => {
    const isUserEmpty = isHTMLEmpty(signature);
    const isProtonEmpty = !protonSignature;
    return {
        userClass: isUserEmpty ? CLASSNAME_SIGNATURE_EMPTY : '',
        protonClass: isProtonEmpty ? CLASSNAME_SIGNATURE_EMPTY : '',
        containerClass: isUserEmpty && isProtonEmpty ? CLASSNAME_SIGNATURE_EMPTY : '',
    };
};

/**
 * Generate the template for a signature and clean it
 */
export const templateBuilder = (
    signature = '',
    mailSettings: Partial<MailSettings> | undefined = {},
    fontStyle: string | undefined,
    isReply = false,
    noSpace = false
) => {
    const protonSignature = getProtonSignature(mailSettings);
    const { userClass, protonClass, containerClass } = getClassNamesSignature(signature, protonSignature);
    const space = getSpaces(signature, protonSignature, fontStyle, isReply);

    const defaultStyle = fontStyle === undefined ? '' : `style="${fontStyle}" `;
    const template = dedentTpl`
        <div ${defaultStyle}class="${CLASSNAME_SIGNATURE_CONTAINER} ${containerClass}">
            <div class="${CLASSNAME_SIGNATURE_USER} ${userClass}">
                ${replaceLineBreaks(signature)}
            </div>
            ${space.between}
            <div class="${CLASSNAME_SIGNATURE_PROTON} ${protonClass}">
                ${replaceLineBreaks(protonSignature)}
            </div>
        </div>
    `;

    if (!noSpace) {
        return `${space.start}${message(template)}${space.end}`;
    }

    return message(template);
};

/**
 * Insert Signatures before the message
 *     - Always append a container signature with both user's and proton's
 *     - Theses signature can be empty but the dom remains
 */
export const insertSignature = (
    content = '',
    signature = '',
    action: MESSAGE_ACTIONS,
    mailSettings: MailSettings,
    fontStyle: string | undefined,
    isAfter = false
) => {
    const position = isAfter ? 'beforeend' : 'afterbegin';
    const template = templateBuilder(signature, mailSettings, fontStyle, action !== MESSAGE_ACTIONS.NEW);

    // Parse the current message and append before it the signature
    const element = parseInDiv(content);
    element.insertAdjacentHTML(position, template);

    return element.innerHTML;
};

/**
 * Return the content of the message with the signature switched from the old one to the new one
 */
export const changeSignature = (
    message: MessageState,
    mailSettings: Partial<MailSettings> | undefined,
    fontStyle: string | undefined,
    oldSignature: string,
    newSignature: string
) => {
    if (isPlainText(message.data)) {
        const oldTemplate = templateBuilder(oldSignature, mailSettings, fontStyle, false, true);
        const newTemplate = templateBuilder(newSignature, mailSettings, fontStyle, false, true);
        const content = getPlainTextContent(message);
        const oldSignatureText = exportPlainText(oldTemplate).trim();
        const newSignatureText = exportPlainText(newTemplate).trim();
        return content.replace(oldSignatureText, newSignatureText);
    }
    const document = message.messageDocument?.document as Element;

    const userSignature = [...document.querySelectorAll(`.${CLASSNAME_SIGNATURE_USER}`)].find(
        (element) => element.closest(`.${CLASSNAME_BLOCKQUOTE}`) === null
    );

    if (userSignature) {
        const protonSignature = getProtonSignature(mailSettings);<commit_msg>Add specific rules when switching signature in plain text and empty signatures<commit_after>import { MailSettings } from '@proton/shared/lib/interfaces';
import { isPlainText } from '@proton/shared/lib/mail/messages';
import { message } from '@proton/shared/lib/sanitize';
import isTruthy from '@proton/shared/lib/helpers/isTruthy';
import { getProtonMailSignature } from '@proton/shared/lib/mail/signature';
import { dedentTpl } from '../dedent';
import { replaceLineBreaks } from '../string';
import { parseInDiv, isHTMLEmpty } from '../dom';
import { getPlainTextContent, exportPlainText } from './messageContent';
import { CLASSNAME_BLOCKQUOTE } from './messageDraft';
import { MESSAGE_ACTIONS } from '../../constants';
import { MessageState } from '../../logic/messages/messagesTypes';

export const CLASSNAME_SIGNATURE_CONTAINER = 'protonmail_signature_block';
export const CLASSNAME_SIGNATURE_USER = 'protonmail_signature_block-user';
export const CLASSNAME_SIGNATURE_PROTON = 'protonmail_signature_block-proton';
export const CLASSNAME_SIGNATURE_EMPTY = 'protonmail_signature_block-empty';

/**
 * Preformat the protonMail signature
 */
const getProtonSignature = (mailSettings: Partial<MailSettings> = {}) =>
    mailSettings.PMSignature === 0 ? '' : getProtonMailSignature();

/**
 * Generate a space tag, it can be hidden from the UX via a className
 */
const createSpace = (style?: string, className?: string) => {
    const tagOpen = [
        'div',
        style === undefined ? undefined : `style="${style}"`,
        className === undefined ? undefined : `class="${className}"`,
    ]
        .filter(isTruthy)
        .join(' ');
    return `<${tagOpen}><br /></div>`;
};

/**
 * Generate spaces for the signature
 *     No signature: 1 space
 *     addressSignature: 2 spaces + addressSignature
 *     protonSignature: 2 spaces + protonSignature
 *     user + proton signature: 2 spaces + addressSignature + 1 space + protonSignature
 */
const getSpaces = (signature: string, protonSignature: string, fontStyle: string | undefined, isReply = false) => {
    const isUserEmpty = isHTMLEmpty(signature);
    const isEmptySignature = isUserEmpty && !protonSignature;
    return {
        start: isEmptySignature ? createSpace(fontStyle) : createSpace(fontStyle) + createSpace(fontStyle),
        end: isReply ? createSpace(fontStyle) : '',
        between: !isUserEmpty && protonSignature ? createSpace(fontStyle) : '',
    };
};

/**
 * Generate a map of classNames used for the signature template
 */
const getClassNamesSignature = (signature: string, protonSignature: string) => {
    const isUserEmpty = isHTMLEmpty(signature);
    const isProtonEmpty = !protonSignature;
    return {
        userClass: isUserEmpty ? CLASSNAME_SIGNATURE_EMPTY : '',
        protonClass: isProtonEmpty ? CLASSNAME_SIGNATURE_EMPTY : '',
        containerClass: isUserEmpty && isProtonEmpty ? CLASSNAME_SIGNATURE_EMPTY : '',
    };
};

/**
 * Generate the template for a signature and clean it
 */
export const templateBuilder = (
    signature = '',
    mailSettings: Partial<MailSettings> | undefined = {},
    fontStyle: string | undefined,
    isReply = false,
    noSpace = false
) => {
    const protonSignature = getProtonSignature(mailSettings);
    const { userClass, protonClass, containerClass } = getClassNamesSignature(signature, protonSignature);
    const space = getSpaces(signature, protonSignature, fontStyle, isReply);

    const defaultStyle = fontStyle === undefined ? '' : `style="${fontStyle}" `;
    const template = dedentTpl`
        <div ${defaultStyle}class="${CLASSNAME_SIGNATURE_CONTAINER} ${containerClass}">
            <div class="${CLASSNAME_SIGNATURE_USER} ${userClass}">
                ${replaceLineBreaks(signature)}
            </div>
            ${space.between}
            <div class="${CLASSNAME_SIGNATURE_PROTON} ${protonClass}">
                ${replaceLineBreaks(protonSignature)}
            </div>
        </div>
    `;

    if (!noSpace) {
        return `${space.start}${message(template)}${space.end}`;
    }

    return message(template);
};

/**
 * Insert Signatures before the message
 *     - Always append a container signature with both user's and proton's
 *     - Theses signature can be empty but the dom remains
 */
export const insertSignature = (
    content = '',
    signature = '',
    action: MESSAGE_ACTIONS,
    mailSettings: MailSettings,
    fontStyle: string | undefined,
    isAfter = false
) => {
    const position = isAfter ? 'beforeend' : 'afterbegin';
    const template = templateBuilder(signature, mailSettings, fontStyle, action !== MESSAGE_ACTIONS.NEW);

    // Parse the current message and append before it the signature
    const element = parseInDiv(content);
    element.insertAdjacentHTML(position, template);

    return element.innerHTML;
};

/**
 * Return the content of the message with the signature switched from the old one to the new one
 */
export const changeSignature = (
    message: MessageState,
    mailSettings: Partial<MailSettings> | undefined,
    fontStyle: string | undefined,
    oldSignature: string,
    newSignature: string
) => {
    if (isPlainText(message.data)) {
        const oldTemplate = templateBuilder(oldSignature, mailSettings, fontStyle, false, true);
        const newTemplate = templateBuilder(newSignature, mailSettings, fontStyle, false, true);
        const content = getPlainTextContent(message);
        const oldSignatureText = exportPlainText(oldTemplate).trim();
        const newSignatureText = exportPlainText(newTemplate).trim();

        // Special case when there was no signature before
        if (oldSignatureText === '') {
            return `${content}\n\n${newSignatureText}`;
        }

        return (
            content
                .replace(oldSignatureText, newSignatureText)
                // Remove empty lines at the end, remove all lines if no signatures
                .trimEnd()
        );
    }
    const document = message.messageDocument?.document as Element;

    const userSignature = [...document.querySelectorAll(`.${CLASSNAME_SIGNATURE_USER}`)].find(
        (element) => element.closest(`.${CLASSNAME_BLOCKQUOTE}`) === null
    );

    if (userSignature) {
        const protonSignature = getProtonSignature(mailSettings);
{'fraction_non_alphanumeric': 0.11774338819290919, 'fraction_numerical': 0.0009825595676737902, 'mean_word_length': 3.6958861976163013, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7658612', 'n_tokens_mistral': 3356, 'n_tokens_neox': 3310, 'n_words': 864}