From d67d8b373fab2a49129e1d0473177033265c96bd Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 11 Dec 2025 10:21:17 +0530 Subject: [PATCH] chore: Minor fix --- .../dashboard/helper/editorHelper.js | 47 +++++++++++++++---- package.json | 2 +- pnpm-lock.yaml | 10 ++-- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/app/javascript/dashboard/helper/editorHelper.js b/app/javascript/dashboard/helper/editorHelper.js index 933c8cc08..dd04da234 100644 --- a/app/javascript/dashboard/helper/editorHelper.js +++ b/app/javascript/dashboard/helper/editorHelper.js @@ -12,6 +12,23 @@ import { } from 'dashboard/constants/editor'; import camelcaseKeys from 'camelcase-keys'; +/** + * Removes zero-width spaces and related invisible characters from text. + * Also handles backslash-newline patterns from hard breaks (Shift+Enter). + * These characters can interfere with signature detection and content handling. + * + * @param {string} text - The text to clean + * @returns {string} - The cleaned text without zero-width spaces + */ +export function removeZeroWidthSpaces(text) { + if (!text) return ''; + return text + .replace(/\u200B\\\n/g, '\n') // Remove zero-width space + backslash + newline, keep newline + .replace(/\u200B\n/g, '\n') // Remove zero-width space + newline, keep newline + .replace(/\\\n/g, '\n') // Remove backslash before newline (hard break), keep newline + .replace(/\u200B/g, ''); // Remove standalone zero-width spaces +} + /** * Extract text from markdown, and remove all images, code blocks, links, headers, bold, italic, lists etc. * Links will be converted to text, and not removed. @@ -46,6 +63,9 @@ export const SIGNATURE_DELIMITER = '--'; */ export function cleanSignature(signature) { try { + // Remove zero-width spaces before processing + signature = removeZeroWidthSpaces(signature); + // remove any horizontal rule tokens signature = signature .replace(/^( *\* *){3,} *$/gm, '') @@ -55,14 +75,17 @@ export function cleanSignature(signature) { const nodes = new MessageMarkdownTransformer(messageSchema).parse( signature ); - return MessageMarkdownSerializer.serialize(nodes); + let result = MessageMarkdownSerializer.serialize(nodes); + + // Remove zero-width spaces after serialization as well + return removeZeroWidthSpaces(result); } catch (e) { // eslint-disable-next-line no-console console.warn(e); Sentry.captureException(e); // The parser can break on some cases // for example, Token type `hr` not supported by Markdown parser - return signature; + return removeZeroWidthSpaces(signature); } } @@ -85,7 +108,8 @@ function appendDelimiter(signature) { * @returns {number} - The index of the last occurrence of the signature in the body, or -1 if not found. */ export function findSignatureInBody(body, signature) { - const trimmedBody = body.trimEnd(); + // Remove zero-width spaces from body before comparison + const trimmedBody = removeZeroWidthSpaces(body).trimEnd(); const cleanedSignature = cleanSignature(signature); // check if body ends with signature @@ -116,6 +140,9 @@ export function supportsImageSignature(channelType) { * @returns {string} - The body with the signature appended. */ export function appendSignature(body, signature, channelType) { + // Remove zero-width spaces from body before processing + const cleanedBody = removeZeroWidthSpaces(body); + // For channels that don't support images, strip markdown formatting const shouldStripImages = channelType && !supportsImageSignature(channelType); const preparedSignature = shouldStripImages @@ -123,11 +150,11 @@ export function appendSignature(body, signature, channelType) { : signature; const cleanedSignature = cleanSignature(preparedSignature); // if signature is already present, return body - if (findSignatureInBody(body, cleanedSignature) > -1) { - return body; + if (findSignatureInBody(cleanedBody, cleanedSignature) > -1) { + return cleanedBody; } - return `${body.trimEnd()}\n\n${appendDelimiter(cleanedSignature)}`; + return `${cleanedBody.trimEnd()}\n\n${appendDelimiter(cleanedSignature)}`; } /** @@ -139,6 +166,9 @@ export function appendSignature(body, signature, channelType) { * @returns {string} - The body with the signature removed. */ export function removeSignature(body, signature) { + // Remove zero-width spaces from body before processing + let newBody = removeZeroWidthSpaces(body); + // Build list of signatures to try: original first, then stripped version // Always try both to handle cases where channelType is unknown or inbox is being removed const cleanedSignature = cleanSignature(signature); @@ -150,13 +180,10 @@ export function removeSignature(body, signature) { // Find the first matching signature const signatureIndex = signaturesToTry.reduce( - (index, sig) => (index === -1 ? findSignatureInBody(body, sig) : index), + (index, sig) => (index === -1 ? findSignatureInBody(newBody, sig) : index), -1 ); - // no need to trim the ends here, because it will simply be removed in the next method - let newBody = body; - // if signature is present, remove it and trim it // trimming will ensure any spaces or new lines before the signature are removed // This means we will have the delimiter at the end diff --git a/package.json b/package.json index 1113d4514..df7ed1163 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "dependencies": { "@breezystack/lamejs": "^1.2.7", "@chatwoot/ninja-keys": "1.2.3", - "@chatwoot/prosemirror-schema": "1.2.7", + "@chatwoot/prosemirror-schema": "1.2.8", "@chatwoot/utils": "^0.0.51", "@formkit/core": "^1.6.7", "@formkit/vue": "^1.6.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70f9a147d..0e7443873 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,8 +20,8 @@ importers: specifier: 1.2.3 version: 1.2.3 '@chatwoot/prosemirror-schema': - specifier: 1.2.7 - version: 1.2.7 + specifier: 1.2.8 + version: 1.2.8 '@chatwoot/utils': specifier: ^0.0.51 version: 0.0.51 @@ -421,8 +421,8 @@ packages: '@chatwoot/ninja-keys@1.2.3': resolution: {integrity: sha512-xM8d9P5ikDMZm2WbaCTk/TW5HFauylrU3cJ75fq5je6ixKwyhl/0kZbVN/vbbZN4+AUX/OaSIn6IJbtCgIF67g==} - '@chatwoot/prosemirror-schema@1.2.7': - resolution: {integrity: sha512-3Nt9aPNNmG6dJzAvH2iCM1EV/3ZWzSM1fMMoyHUlqIWmftJoW3Kss8h8+Dt/i5Rs7Hcx+FEl+3U4+lvup+q8Fw==} + '@chatwoot/prosemirror-schema@1.2.8': + resolution: {integrity: sha512-qQpj9UzAkE5YrfTIl1LPgyD959f0LCD1JznD7VN626TsoCv7h1oTuBd1oMl1vyxpY+Z3Z6Nve+7VhQmKrj+QGQ==} '@chatwoot/utils@0.0.51': resolution: {integrity: sha512-WlEmWfOTzR7YZRUWzn5Wpm15/BRudpwqoNckph8TohyDbiim1CP4UZGa+qjajxTbNGLLhtKlm0Xl+X16+5Wceg==} @@ -4862,7 +4862,7 @@ snapshots: hotkeys-js: 3.8.7 lit: 2.2.6 - '@chatwoot/prosemirror-schema@1.2.7': + '@chatwoot/prosemirror-schema@1.2.8': dependencies: markdown-it-sup: 2.0.0 prosemirror-commands: 1.6.0