Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export const GeneralPreviewComponent: FC<{
</div>
</div>
<div
dir="auto"
className={clsx('text-wrap whitespace-pre', 'preview')}
dangerouslySetInnerHTML={{
__html: value.text,
Expand Down
6 changes: 3 additions & 3 deletions apps/frontend/src/components/new-launch/add.edit.modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export const AddEditModalInnerInner: FC<AddEditModalProps> = (props) => {
existingData.posts.map((post) => ({
delay: post.delay,
content:
post.content.indexOf('<p>') > -1
/<p[\s>]/i.test(post.content)
? post.content
: post.content
.split('\n')
Comment on lines 150 to 156

This comment was marked as outdated.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fair point, tightened to a tag-shaped check: /<p[\s>]/i in both add.edit.modal.tsx and the strip.html.validation.ts guard. It matches

and

but ignores a stray <p followed by other characters in plain text. Note the same false positive class already existed with the original indexOf('

') check for text containing a literal

, so this is now stricter than the original code as well.

Expand All @@ -175,7 +175,7 @@ export const AddEditModalInnerInner: FC<AddEditModalProps> = (props) => {
props.onlyValues?.length
? props.onlyValues.map((p) => ({
content:
p.content.indexOf('<p>') > -1
/<p[\s>]/i.test(p.content)
? p.content
: p.content
.split('\n')
Expand All @@ -188,7 +188,7 @@ export const AddEditModalInnerInner: FC<AddEditModalProps> = (props) => {
? props.set.posts[0].value.map((p: any) => ({
id: makeId(10),
content:
p.content.indexOf('<p>') > -1
/<p[\s>]/i.test(p.content)
? p.content
: p.content
.split('\n')
Expand Down
9 changes: 8 additions & 1 deletion apps/frontend/src/components/new-launch/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,11 @@ export const OnlyEditor = forwardRef<
const editor = useEditor({
extensions: [
Document,
Paragraph,
Paragraph.configure({
HTMLAttributes: {
dir: 'auto',
},
}),
Text,
Underline,
Bold,
Comment on lines 907 to 917

This comment was marked as outdated.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, confirmed: sanitizePostContent stripped the per paragraph dir attribute before storage. The impact was partial (the editor re applies dir=auto from the extension config and the preview wrappers carry their own dir=auto), but stored content lost per paragraph granularity and the public share page rendered without it. Fixed in 179ba4d by adding dir to ALLOWED_ATTR.

Expand Down Expand Up @@ -1021,6 +1025,9 @@ export const OnlyEditor = forwardRef<
? [
Heading.configure({
levels: [1, 2, 3],
HTMLAttributes: {
dir: 'auto',
},
}),
]
: []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export const FacebookPreview: FC<{
</div>
{background ? (
<div
dir="auto"
className="-mx-[15px] min-h-[320px] flex items-center justify-center text-center px-[32px] py-[32px] text-[28px] font-[700] leading-[36px] whitespace-pre-line break-words"
style={{ background: background.background, color: background.text }}
dangerouslySetInnerHTML={{
Expand All @@ -161,6 +162,7 @@ export const FacebookPreview: FC<{
/>
) : (
<div
dir="auto"
className="text-[14px] font-[400] whitespace-pre-line"
dangerouslySetInnerHTML={{
__html: renderContent?.[0]?.text,
Expand Down Expand Up @@ -295,6 +297,7 @@ export const FacebookPreview: FC<{
</div>
</div>
<div
dir="auto"
className="whitespace-pre-line text-[14px] font-[400]"
dangerouslySetInnerHTML={{
__html: value.text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const InstagramPreview: FC<{

const finalValue =
`<strong class="text-[15px] font-[600]">${integration?.name} </strong>` +
`<span dir="auto">` +
newContent
.slice(start, end)
.replace(/\[\[\[([.\s\S]*?)]]]/, (match, match1) => {
Expand All @@ -43,7 +44,7 @@ export const InstagramPreview: FC<{
newContent.slice(end).replace(/\[\[\[([.\s\S]*?)]]]/, (match, match1) => {
return `<span class="font-bold font-[arial]" style="color: #ae8afc">${match1}</span>`;
}) +
`</mark>`;
`</mark></span>`;

return { text: finalValue, images: p.image };
});
Expand Down Expand Up @@ -82,6 +83,7 @@ export const InstagramPreview: FC<{
/>
)}
<div
dir="auto"
className="text-[14px] font-[400] whitespace-pre-line"
dangerouslySetInnerHTML={{
__html: renderContent?.[0]?.text,
Comment on lines 83 to 89

This comment was marked as outdated.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Confirmed with a minimal repro: the Latin username as first strong character forced the whole caption block LTR. Fixed in fd487c8 by wrapping the caption content in its own span with dir=auto, so the username stays inline (like on Instagram itself) while the content resolves its own direction. Verifying this also surfaced that the literal indexOf('

') checks in strip.html.validation.ts and add.edit.modal.tsx missed paragraphs carrying the new dir attribute, which made stripHtmlValidation return raw HTML at publish time; fixed in the same commit by matching '<p' instead.

Expand Down Expand Up @@ -181,6 +183,7 @@ export const InstagramPreview: FC<{
<div className="flex flex-col gap-[6px] flex-1">
<div className="flex gap-[4px] py-[8px]">
<div
dir="auto"
className="whitespace-pre-line text-[14px] font-[400] flex-1"
dangerouslySetInnerHTML={{
__html: value.text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export const LinkedinPreview: FC<{
</div>
</div>
<div
dir="auto"
className="text-[14px] font-[400] whitespace-pre-line"
dangerouslySetInnerHTML={{
__html: renderContent?.[0]?.text,
Expand Down Expand Up @@ -452,6 +453,7 @@ export const LinkedinPreview: FC<{
</div>
</div>
<div
dir="auto"
className="whitespace-pre-line text-[14px] font-[400]"
dangerouslySetInnerHTML={{
__html: value.text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export const PinterestPreview: FC<{
)}
</div>
<div
dir="auto"
className="mt-[13px] whitespace-pre-line"
dangerouslySetInnerHTML={{ __html: renderContent?.[0]?.text || '' }}
></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const RenderRedditComponent: FC<{
case 'self':
return (
<div
dir="auto"
dangerouslySetInnerHTML={{ __html: firstPost?.content }}
style={{
whiteSpace: 'pre-wrap',
Expand Down Expand Up @@ -139,6 +140,7 @@ const RedditPreview: FC = (props) => {
{integration?.name}
</div>
<div
dir="auto"
dangerouslySetInnerHTML={{ __html: p.text }}
style={{
whiteSpace: 'pre-wrap',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const TiktokPreview: FC<{
/>
<div className="absolute pointer-events-none w-full h-full start-0 top-0 px-[12px] py-[25px] justify-end items-start text-white flex flex-col">
<div className="text-[14px] font-[500]">@{integration?.name}</div>
<div className="text-[13px] font-[400] whitespace-pre-line line-clamp-6 w-full"
<div dir="auto" className="text-[13px] font-[400] whitespace-pre-line line-clamp-6 w-full"
dangerouslySetInnerHTML={{ __html: renderContent?.[0]?.text || '' }}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export const YoutubePreview: FC<{
</div>
</div>
<div
dir="auto"
className="bg-youtubeBgAction rounded-[12px] p-[12px] text-[12px] font-[400] whitespace-pre-line"
dangerouslySetInnerHTML={{ __html: renderContent?.[0]?.text }}
/>
Expand Down
1 change: 1 addition & 0 deletions libraries/helpers/src/utils/sanitize.post.content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const ALLOWED_TAGS = [
];

const ALLOWED_ATTR = [
'dir',
'href',
'target',
'rel',
Expand Down
10 changes: 5 additions & 5 deletions libraries/helpers/src/utils/strip.html.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,17 @@ export const stripHtmlValidation = (
return striptags(
convertMention(
value
.replace(/<h1>([.\s\S]*?)<\/h1>/g, (match, p1) => {
.replace(/<h1[^>]*>([.\s\S]*?)<\/h1>/g, (match, p1) => {
return `<h1># ${p1}</h1>\n`;
})
.replace(/&amp;/gi, '&')
.replace(/&nbsp;/gi, ' ')
.replace(/&quot;/gi, '"')
.replace(/&#39;/gi, "'")
.replace(/<h2>([.\s\S]*?)<\/h2>/g, (match, p1) => {
.replace(/<h2[^>]*>([.\s\S]*?)<\/h2>/g, (match, p1) => {
return `<h2>## ${p1}</h2>\n`;
})
.replace(/<h3>([.\s\S]*?)<\/h3>/g, (match, p1) => {
.replace(/<h3[^>]*>([.\s\S]*?)<\/h3>/g, (match, p1) => {
return `<h3>### ${p1}</h3>\n`;
})
.replace(/<u>([.\s\S]*?)<\/u>/g, (match, p1) => {
Expand All @@ -201,7 +201,7 @@ export const stripHtmlValidation = (
.replace(/<li.*?>([.\s\S]*?)<\/li.*?>/gm, (match, p1) => {
return `<li>- ${p1.replace(/\n/gm, '')}</li>`;
})
.replace(/<p>([.\s\S]*?)<\/p>/g, (match, p1) => {
.replace(/<p[^>]*>([.\s\S]*?)<\/p>/g, (match, p1) => {
return `<p>${p1}</p>\n`;
})
.replace(
Expand All @@ -217,7 +217,7 @@ export const stripHtmlValidation = (
.replace(/&lt;/gi, '<');
}

if (value.indexOf('<p>') === -1 && !none) {
if (!/<p[\s>]/i.test(value) && !none) {
return value;
}

Comment on lines 217 to 223

This comment was marked as outdated.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Confirmed and reproduced: markdown mode returned the paragraphs concatenated with no newlines, and the headings also lost their # prefixes since h1-h3 now carry dir=auto too. Fixed in the markdown branch by making the p and h1/h2/h3 regexes attribute-tolerant ([^>]*). Verified the output is now identical for content with and without the dir attribute.

Expand Down
Loading