From 616a266cc4ee0ecf3800342074cf00fe6e4c8ee3 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 28 Jan 2022 02:11:09 +0100 Subject: [PATCH] Text Formatter: Full support for spoilers --- .../common/helpers/renderMessageText.tsx | 9 +++- src/components/middle/composer/Composer.scss | 12 +++++ .../middle/composer/TextFormatter.tsx | 47 +++++++++++++++---- src/util/parseMessageInput.ts | 3 -- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/components/common/helpers/renderMessageText.tsx b/src/components/common/helpers/renderMessageText.tsx index 8e482e33..c69ec2f8 100644 --- a/src/components/common/helpers/renderMessageText.tsx +++ b/src/components/common/helpers/renderMessageText.tsx @@ -18,7 +18,9 @@ import SafeLink from '../SafeLink'; import Spoiler from '../spoiler/Spoiler'; import { LangFn } from '../../../hooks/useLang'; -export type TextPart = string | Element; +export type TextPart = + string + | Element; export function renderMessageSummary( lang: LangFn, @@ -500,7 +502,10 @@ function processEntityAsHtml( dir="auto" >${renderedContent}`; case ApiMessageEntityTypes.Spoiler: - return `||${renderedContent}||`; + return `${renderedContent}`; default: return renderedContent; } diff --git a/src/components/middle/composer/Composer.scss b/src/components/middle/composer/Composer.scss index bfc551b0..21201d4f 100644 --- a/src/components/middle/composer/Composer.scss +++ b/src/components/middle/composer/Composer.scss @@ -399,6 +399,18 @@ } } + .spoiler { + background-image: url('../../../assets/spoiler-dots-black.png'); + background-size: auto min(100%, 1.125rem); + border-radius: 0.5rem; + padding: 0 0.3125rem 0.125rem 0.3125rem; + text-shadow: -2px -2px 0 var(--color-background), 2px -2px 0 var(--color-background), -2px 2px 0 var(--color-background), 2px 2px 0 var(--color-background); + } + + html.theme-dark & .spoiler { + background-image: url('../../../assets/spoiler-dots-white.png'); + } + .clone { position: absolute; top: 0; diff --git a/src/components/middle/composer/TextFormatter.tsx b/src/components/middle/composer/TextFormatter.tsx index 190b421c..171b1cd1 100644 --- a/src/components/middle/composer/TextFormatter.tsx +++ b/src/components/middle/composer/TextFormatter.tsx @@ -3,6 +3,7 @@ import React, { } from '../../../lib/teact/teact'; import { IAnchorPosition } from '../../../types'; +import { ApiMessageEntityTypes } from '../../../api/types'; import { EDITABLE_INPUT_ID } from '../../../config'; import buildClassName from '../../../util/buildClassName'; @@ -32,6 +33,7 @@ interface ISelectedTextFormats { underline?: boolean; strikethrough?: boolean; monospace?: boolean; + spoiler?: boolean; } const TEXT_FORMAT_BY_TAG_NAME: Record = { @@ -42,6 +44,7 @@ const TEXT_FORMAT_BY_TAG_NAME: Record = { U: 'underline', DEL: 'strikethrough', CODE: 'monospace', + SPAN: 'spoiler', }; const fragmentEl = document.createElement('div'); @@ -188,6 +191,34 @@ const TextFormatter: FC = ({ return undefined; } + const handleSpoilerText = useCallback(() => { + if (selectedTextFormats.spoiler) { + const element = getSelectedElement(); + if ( + !selectedRange + || !element + || element.dataset.entityType !== ApiMessageEntityTypes.Spoiler + || !element.textContent + ) { + return; + } + + element.replaceWith(element.textContent); + setSelectedTextFormats((selectedFormats) => ({ + ...selectedFormats, + spoiler: false, + })); + + return; + } + + const text = getSelectedText(); + document.execCommand( + 'insertHTML', false, `${text}`, + ); + onClose(); + }, [getSelectedElement, getSelectedText, onClose, selectedRange, selectedTextFormats.spoiler]); + const handleBoldText = useCallback(() => { setSelectedTextFormats((selectedFormats) => { // Somehow re-applying 'bold' command to already bold text doesn't work @@ -249,16 +280,9 @@ const TextFormatter: FC = ({ document.execCommand('insertHTML', false, `${text}`); onClose(); }, [ - getSelectedElement, getSelectedText, onClose, - selectedRange, selectedTextFormats.strikethrough, + getSelectedElement, getSelectedText, onClose, selectedRange, selectedTextFormats.strikethrough, ]); - const handleSpoilerText = useCallback(() => { - const text = getSelectedText(); - document.execCommand('insertHTML', false, `||${text}||`); - onClose(); - }, [getSelectedText, onClose]); - const handleMonospaceText = useCallback(() => { if (selectedTextFormats.monospace) { const element = getSelectedElement(); @@ -276,6 +300,7 @@ const TextFormatter: FC = ({ ...selectedFormats, monospace: false, })); + return; } @@ -283,8 +308,7 @@ const TextFormatter: FC = ({ document.execCommand('insertHTML', false, `${text}`); onClose(); }, [ - getSelectedElement, getSelectedText, onClose, - selectedRange, selectedTextFormats.monospace, + getSelectedElement, getSelectedText, onClose, selectedRange, selectedTextFormats.monospace, ]); function handleLinkUrlConfirm() { @@ -299,6 +323,7 @@ const TextFormatter: FC = ({ (element as HTMLAnchorElement).href = formattedLinkUrl; onClose(); + return; } @@ -389,10 +414,12 @@ const TextFormatter: FC = ({ +