Skip to content

feat: add more text formats to telegram editor - #1499

Open
SuperDrak wants to merge 12 commits into
gitroomhq:mainfrom
SuperDrak:feature/add-telegram-text-formats
Open

feat: add more text formats to telegram editor#1499
SuperDrak wants to merge 12 commits into
gitroomhq:mainfrom
SuperDrak:feature/add-telegram-text-formats

Conversation

@SuperDrak

@SuperDrak SuperDrak commented May 7, 2026

Copy link
Copy Markdown

Closes #1352

What kind of change does this PR introduce?

It adds following text formats to telegram editor

  • italic
  • strikethrough
  • blockquote
  • code
  • link insertion

Why was this change needed?

Currently, Postiz editor only provides underline and bold text format options. Telegram also supports italic, strikethough, blockquote, code and link insertion in text messages. The change will help user utilize all the formats supported by telegram in postiz editor.

Other information:

a working demo

Postiz.Calendar.-.7.May.2026.mp4

telegram result
telegramoutput

Checklist:

Put a "X" in the boxes below to indicate you have followed the checklist;

  • I have read the CONTRIBUTING guide.
  • I confirm I have not used AI to submit this PR or generate code for it.
  • I checked that there were no similar issues or PRs already open for this.
  • This PR fixes just ONE issue

@postiz-contribution postiz-contribution Bot added the contribution:approved Approved contributor label May 7, 2026
@SuperDrak
SuperDrak marked this pull request as ready for review May 7, 2026 10:16
Comment on lines +941 to +943
Link.extend({
inclusive: false,
}),

This comment was marked as outdated.

Comment on lines +581 to +586
.replace(/<blockquote>(.+?)<\/blockquote>/gi, (match, p1) => {
const replacer = p1.split('').map((char: string) => {
return blockquote?.[char] || char;
});
return match.replace(p1, replacer.join(''));
})

This comment was marked as outdated.

Comment on lines +7 to +9
editor?.commands?.unsetUnderline();
editor?.commands?.toggleCode();
editor?.commands?.focus();

This comment was marked as outdated.

const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedText, setSelectedText] = useState('');
// Get the currently selected text from the editor (if any)
const { from, to } = editor?.state?.selection ?? {};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The LinkText component fails to apply links because it captures the text selection at render time, and the selection is lost when the link modal opens.
Severity: HIGH

Suggested Fix

Before calling editor?.commands?.setLink(), the editor's focus and selection range should be restored. This can be achieved by calling editor?.chain()?.focus() and potentially extendMarkRange('link') to re-select the intended text, similar to the implementation in a.component.tsx.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: apps/frontend/src/components/new-launch/link.text.tsx#L103

Potential issue: The `LinkText` component captures the editor's selection state (`from`,
`to`) at the time the component renders, not when the link button is clicked. When the
button is clicked, a modal opens, which causes the editor to lose focus and its text
selection to be cleared. When the user confirms the link in the modal, the `handleApply`
function calls `editor?.commands?.setLink()`. This command operates on the editor's
current selection, which is now empty. As a result, the link is not applied to the
originally selected text.

@nevo-david

Copy link
Copy Markdown
Contributor

@pottycat since you added also an ascii version of it, I think we can enable it on all the providers no?

@postiz-contribution

This comment has been minimized.

@postiz-contribution postiz-contribution Bot added contribution:denied Application denied and removed contribution:approved Approved contributor labels May 9, 2026
@postiz-contribution postiz-contribution Bot reopened this May 9, 2026
@postiz-contribution

Copy link
Copy Markdown

@pottycat's application for Postiz was approved — reopening this PR.

@postiz-contribution postiz-contribution Bot added contribution:approved Approved contributor and removed contribution:denied Application denied labels May 9, 2026
@SuperDrak

Copy link
Copy Markdown
Author

@pottycat since you added also an ascii version of it, I think we can enable it on all the providers no?

I tested it. So, yes we can enable it on all platforms. I will make changes to enable it in all providers not just in telegram

@SuperDrak
SuperDrak force-pushed the feature/add-telegram-text-formats branch from 5af8474 to 143dd06 Compare May 14, 2026 05:58
Comment on lines 795 to 805
editor={editorRef?.current?.editor}
currentValue={props.value!}
/>
<ItalicText editor={editorRef?.current?.editor} />
<StrikeText editor={editorRef?.current?.editor} />
<BlockquoteText editor={editorRef?.current?.editor} />
<CodeText editor={editorRef?.current?.editor} />
<AComponent editor={editorRef?.current?.editor} />
</>
)}
{(editorType === 'markdown' || editorType === 'html') &&

This comment was marked as outdated.

Comment on lines +800 to +806
<BlockquoteText editor={editorRef?.current?.editor} />
<CodeText editor={editorRef?.current?.editor} />
</>
)}
{/* link insertion may not work on all providers e.g insta, x, facebook */}
{(editorType === 'html' || editorType === 'markdown') &&
identifier === 'telegram' && (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The blockquote button is incorrectly enabled for non-Telegram providers, causing text to be converted to full-width Unicode characters when posted.
Severity: HIGH

Suggested Fix

Conditionally render the blockquote button to only appear for editors where it is semantically supported, such as Telegram. This can be achieved by moving the button inside the identifier === 'telegram' check, similar to how the link insertion button is handled.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: apps/frontend/src/components/new-launch/editor.tsx#L800-L806

Potential issue: The blockquote formatting button has been made available for all editor
types, including 'normal' editors used for platforms like X, Instagram, and LinkedIn.
However, the underlying implementation for these platforms was not updated to support
blockquotes. When a user applies blockquote formatting, the content is processed by
`convertToAscii`, which converts the text within `<blockquote>` tags into full-width
Unicode characters (e.g., 'a' becomes 'a'). This results in posts with garbled,
unintended text on platforms that do not have native blockquote support, as the feature
was only intended to work for Telegram.

Also affects:

  • libraries/helpers/src/utils/strip.html.validation.ts:581~586

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nevo-david I am facing confusion about placement of text format buttons. I am thinking about placing Bold, Italic and Underline in global mode. Strikethrough, Blockquote, and Code in editorType html or mardown. The link insertion button on Telegram only.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nevo-david I am facing confusion about placement of text format buttons. I am thinking about placing Bold, Italic and Underline in global mode. Strikethrough, Blockquote, and Code in editorType html or mardown. The link insertion button on Telegram only.

I have placed all Bold, Italic, Underline, Strikethough, Blockquote and Code in global mode because it is converted into ASCII which is rendered well in all the platform. The link insertion is only available to Telegram for the moment. I am thinking about raising a separate PR for including link insertion options to all the platform that supports it in message.

Comment on lines +569 to +579
.replace(/<em>(.+?)<\/em>/gi, (match, p1) => {
const replacer = p1.split('').map((char: string) => {
return italic?.[char] || char;
});
return match.replace(p1, replacer.join(''));
})
.replace(/<s>(.+?)<\/s>/gi, (match, p1) => {
const replacer = p1.split('').map((char: string) => {
return strikethrough?.[char] || char;
});
return match.replace(p1, replacer.join(''));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The regex for <em>, <s>, and <code> tags in convertToAscii does not handle multiline content, unlike the regex for <blockquote>.
Severity: LOW

Suggested Fix

Update the regular expressions for <em>, <s>, and <code> tags to use [\s\S]+? instead of .+?. This will ensure consistency with the <blockquote> handling and correctly process multiline content within these tags.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: libraries/helpers/src/utils/strip.html.validation.ts#L569-L579

Potential issue: In the `convertToAscii` function, the regular expressions used to
capture content within `<em>`, `<s>`, and `<code>` tags use the pattern `.+?`. This
pattern does not match newline characters. This is inconsistent with the regex for
`<blockquote>`, which correctly uses `[\s\S]+?` to handle multiline content. While the
current editor configuration makes it unlikely for these inline tags to contain
newlines, this is a latent bug. If content with newlines is pasted into the editor or if
the editor's behavior changes in the future (e.g., to support soft breaks), formatting
will be silently lost for any multiline formatted text.

@SuperDrak
SuperDrak force-pushed the feature/add-telegram-text-formats branch from b4bac3d to 00a29cf Compare May 18, 2026 05:20
@egelhaus egelhaus added the contribution:evaluate Evaluate the PR again label May 30, 2026
@postiz-contribution

Copy link
Copy Markdown

Hi @pottycat! Before we can accept contributions to Postiz you need to sign the Contributor License Agreement. Sign here: https://contribute.postiz.com/p/postiz/cla. Your PR stays open and we'll re-check automatically once signed.

@postiz-contribution postiz-contribution Bot added contribution:cla-pending Awaiting CLA signature / DCO sign-off and removed contribution:approved Approved contributor contribution:evaluate Evaluate the PR again labels May 30, 2026
@postiz-contribution postiz-contribution Bot added contribution:approved Approved contributor and removed contribution:cla-pending Awaiting CLA signature / DCO sign-off labels May 31, 2026
@scrm77

scrm77 commented Jun 7, 2026

Copy link
Copy Markdown

Hey @SuperDrak 👋 Would love to see this land — Telegram inline links are a great addition.

Quick heads-up on the red CI: the production next build fails type-checking in libraries/helpers/src/utils/strip.html.validation.ts. The six format maps (bold, underlineMap, italic, strikethrough, blockquote, code) are indexed by a string-typed char, but they're inferred as object literals with no index signature, so strict TS errors:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ a: string; b: string; ... }'.

One line each — annotate the maps as Record<string, string>:

-const bold = {
+const bold: Record<string, string> = {

…same for underlineMap / italic / strikethrough / blockquote / code (the six declarations around lines 4–329).

Verified by building the Docker image off this branch + the patch — pnpm build compiles clean. Happy to send a PR into your branch if that's easier. Thanks for the work on this! 🙏

@SuperDrak

Copy link
Copy Markdown
Author

Hey @SuperDrak 👋 Would love to see this land — Telegram inline links are a great addition.

Quick heads-up on the red CI: the production next build fails type-checking in libraries/helpers/src/utils/strip.html.validation.ts. The six format maps (bold, underlineMap, italic, strikethrough, blockquote, code) are indexed by a string-typed char, but they're inferred as object literals with no index signature, so strict TS errors:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ a: string; b: string; ... }'.

One line each — annotate the maps as Record<string, string>:

-const bold = {
+const bold: Record<string, string> = {

…same for underlineMap / italic / strikethrough / blockquote / code (the six declarations around lines 4–329).

Verified by building the Docker image off this branch + the patch — pnpm build compiles clean. Happy to send a PR into your branch if that's easier. Thanks for the work on this! 🙏

I am happy to receive a PR into my branch. please go ahead!

@scrm77

scrm77 commented Jun 7, 2026

Copy link
Copy Markdown

Found one more missing piece for full formatting support: libraries/helpers/src/utils/sanitize.post.content.ts (the DOMPurify pass applied on save) strips em/s/code/blockquote because they're absent from ALLOWED_TAGS. So the editor + provider changes work, but the formatting never persists past save — only <p> and <a href="..."> survive into the DB (verified by inspecting the stored Post.content).

Adding the missing tags fixes it end-to-end:

 const ALLOWED_TAGS = [
   'p', 'br', 'strong', 'u', 'a', 'ul', 'li', 'h1', 'h2', 'h3', 'span',
+  'em', 'i', 's', 'code', 'pre', 'blockquote',
 ];

Verified live on a build off this branch (+ the earlier Record<string, string> type fix): italic / strikethrough / inline code / blockquote now persist and render correctly in Telegram. 🙏

@SuperDrak

Copy link
Copy Markdown
Author

Found one more missing piece for full formatting support: libraries/helpers/src/utils/sanitize.post.content.ts (the DOMPurify pass applied on save) strips em/s/code/blockquote because they're absent from ALLOWED_TAGS. So the editor + provider changes work, but the formatting never persists past save — only <p> and <a href="..."> survive into the DB (verified by inspecting the stored Post.content).

Adding the missing tags fixes it end-to-end:

 const ALLOWED_TAGS = [
   'p', 'br', 'strong', 'u', 'a', 'ul', 'li', 'h1', 'h2', 'h3', 'span',
+  'em', 'i', 's', 'code', 'pre', 'blockquote',
 ];

Verified live on a build off this branch (+ the earlier Record<string, string> type fix): italic / strikethrough / inline code / blockquote now persist and render correctly in Telegram. 🙏

i was totally unaware of this one 😅

@postiz-agent

postiz-agent Bot commented Aug 1, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

const text = striptags(message.message || '', ['u', 'strong', 'p', 'em', 's', 'blockquote', 'code', 'a'])
.replace(/<strong>/g, '<b>')
.replace(/<\/strong>/g, '</b>')
.replace(/<p>(.*?)<\/p>/g, '$1\n');

This comment was marked as outdated.


return match.replace(p1, replacer.join(''));
})
.replace(/<em>([\s\S]+?)<\/em>/gi, (match, p1) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: In convertToAscii, the string replacement logic can corrupt HTML tags if the inner text matches part of the tag name, such as with <em>em</em>.
Severity: MEDIUM

Suggested Fix

Update the replacement logic to only target the content within the tags, not the tags themselves. Instead of replacing within the match string, construct a new string by concatenating the opening tag, the new Unicode content, and the closing tag.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: libraries/helpers/src/utils/strip.html.validation.ts#L569

Potential issue: The `convertToAscii` function replaces HTML tags with Unicode character
equivalents for platforms that do not support HTML. The replacement logic uses
`match.replace(p1, replacer)`, where `match` is the full matched string (e.g.,
`<em>em</em>`) and `p1` is the captured inner text (e.g., `em`).
`String.prototype.replace()` only replaces the first occurrence. If the inner text is
also present in the tag name, the tag itself is corrupted. For example, `<em>em</em>`
incorrectly becomes `<𝘦𝘮>em</em>`. This affects posts to platforms like Bluesky,
Threads, and X.

Also affects:

  • libraries/helpers/src/utils/strip.html.validation.ts:574~574
  • libraries/helpers/src/utils/strip.html.validation.ts:579~579
  • libraries/helpers/src/utils/strip.html.validation.ts:584~584
  • libraries/helpers/src/utils/strip.html.validation.ts:589~592

Did we get this right? 👍 / 👎 to inform future reviews.

.replace(/<p>(.*?)<\/p>/g, '$1\n');
.replace(/<p>([\s\S]*?)<\/p>/g, '$1\n');

console.log(text);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A console.log(text) statement in the sendMessage method of the Telegram provider leaks the full content of every post and comment to the server logs.
Severity: HIGH

Suggested Fix

Remove the console.log(text) statement from line 183 in libraries/nestjs-libraries/src/integrations/social/telegram.provider.ts to prevent user content from being logged in production environments.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: libraries/nestjs-libraries/src/integrations/social/telegram.provider.ts#L183

Potential issue: The `sendMessage` method in `telegram.provider.ts` contains a
`console.log(text)` statement that logs the full content of every user post and comment
sent via Telegram. This method is called by the public `post()` and `comment()`
functions, which are part of the main production code path. Since there are no
conditional checks for the environment (e.g., `NODE_ENV`), this logging will occur in
production, exposing all user-generated content, which may be sensitive, to the server
logs. This appears to be a leftover debugging statement.

Comment on lines +804 to +814
editor={editorRef?.current?.editor}
currentValue={props.value!}
/>
<BlockquoteText
editor={editorRef?.current?.editor}
currentValue={props.value!}
/>
<CodeText
editor={editorRef?.current?.editor}
currentValue={props.value!}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: New text formatting buttons are incorrectly displayed for all providers, not just Telegram, causing unintended Unicode character transformations on platforms like Twitter/X.
Severity: MEDIUM

Suggested Fix

Update the visibility condition for the new formatting buttons in editor.tsx. Restrict their display to only the Telegram provider by changing the condition from {editorType !== 'none'} to a check like {identifier === 'telegram'}.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: apps/frontend/src/components/new-launch/editor.tsx#L796-L814

Potential issue: New text formatting buttons (Italic, Strike, Blockquote, Code) are
displayed for all social media providers, not just Telegram. The visibility is
controlled by `editorType !== 'none'`, making them appear universally. For providers
with `editor = 'normal'` (like Twitter/X), this results in the backend `convertToAscii`
function transforming the formatted text into Unicode characters, which may not be the
intended visual output on those platforms. This is inconsistent with the link insertion
button, which is correctly restricted to Telegram only.

Also affects:

  • libraries/helpers/src/utils/strip.html.validation.ts:550~593
  • libraries/helpers/src/utils/sanitize.post.content.ts:12~23

@SuperGrut

Copy link
Copy Markdown
Contributor

@nevo-david requesting review!

Comment on lines +581 to +586
.replace(/<blockquote>([\s\S]+?)<\/blockquote>/gi, (match, p1) => {
const replacer = p1.split('').map((char: string) => {
return blockquote?.[char] || char;
});
return match.replace(p1, replacer.join(''));
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The convertToAscii function incorrectly replaces the 'p' in <p> tags inside blockquotes with a full-width character, corrupting the HTML for posts on platforms like X and LinkedIn.
Severity: HIGH

Suggested Fix

Modify the convertToAscii function to avoid replacing characters that are part of HTML tags. The logic should process only the text nodes within the <blockquote> element while preserving the integrity of child HTML tags like <p>.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: libraries/helpers/src/utils/strip.html.validation.ts#L581-L586

Potential issue: The `convertToAscii` function, which is called when
`stripHtmlValidation` is used with `replaceBold: true` (e.g., for X and LinkedIn),
incorrectly processes HTML content within `<blockquote>` tags. The function performs a
character-by-character replacement on the entire content inside the blockquote,
including HTML tags. Because the character map includes a replacement for 'p', the `<p>`
and `</p>` tags generated by the Tiptap editor inside a blockquote are corrupted into
`<p>` and `</p>`. This malformed HTML can lead to incorrect rendering or visible tag
remnants in posts on affected platforms.

Comment on lines +575 to +579
.replace(/<s>([\s\S]+?)<\/s>/gi, (match, p1) => {
const replacer = p1.split('').map((char: string) => {
return strikethrough?.[char] || char;
});
return match.replace(p1, replacer.join(''));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The use of match.replace(p1, ...) can incorrectly modify an opening HTML tag if the tag's content also appears within the tag name, like in <s>s</s>.
Severity: MEDIUM

Suggested Fix

Instead of using match.replace(p1, ...), which can be ambiguous, construct the new string explicitly. A safer approach would be to return a new string literal like "<${tag}>${replacer.join('')}</${tag}>", where tag is the HTML tag name (e.g., 's', 'em'). This ensures only the content is replaced and the tags remain intact.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: libraries/helpers/src/utils/strip.html.validation.ts#L575-L579

Potential issue: In `convertToAscii`, HTML tags are processed using a regular expression
and `String.prototype.replace`. The inner replacement logic, `match.replace(p1,
replacer.join(''))`, is flawed because it replaces the first occurrence of the captured
content (`p1`) within the entire matched string (`match`). If the content also appears
in the opening tag (e.g., `<s>s</s>` or ``code``), the tag itself will be corrupted
(e.g., to `<s̶>s</s>` or `<𝚌𝚘𝚍𝚎>code</code>`). This produces malformed HTML, which can
lead to incorrect rendering or parsing downstream.

Also affects:

  • libraries/helpers/src/utils/strip.html.validation.ts:569~574
  • libraries/helpers/src/utils/strip.html.validation.ts:581~586
  • libraries/helpers/src/utils/strip.html.validation.ts:587~592

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution:approved Approved contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Telegram texts formatting and ability to make link of the text

5 participants