Composer: Respect no_webpage option when editing a message (#2804)
This commit is contained in:
parent
b41827d291
commit
4cbe9c1112
@ -4,9 +4,10 @@ import { getActions } from '../../../../global';
|
|||||||
import type { ApiFormattedText, ApiMessage } from '../../../../api/types';
|
import type { ApiFormattedText, ApiMessage } from '../../../../api/types';
|
||||||
import type { MessageListType } from '../../../../global/types';
|
import type { MessageListType } from '../../../../global/types';
|
||||||
import type { Signal } from '../../../../util/signals';
|
import type { Signal } from '../../../../util/signals';
|
||||||
|
import { ApiMessageEntityTypes } from '../../../../api/types';
|
||||||
|
|
||||||
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
|
||||||
import { EDITABLE_INPUT_CSS_SELECTOR } from '../../../../config';
|
import { EDITABLE_INPUT_CSS_SELECTOR } from '../../../../config';
|
||||||
|
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
||||||
import parseMessageInput from '../../../../util/parseMessageInput';
|
import parseMessageInput from '../../../../util/parseMessageInput';
|
||||||
import focusEditableElement from '../../../../util/focusEditableElement';
|
import focusEditableElement from '../../../../util/focusEditableElement';
|
||||||
import { hasMessageMedia } from '../../../../global/helpers';
|
import { hasMessageMedia } from '../../../../global/helpers';
|
||||||
@ -14,6 +15,11 @@ import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWit
|
|||||||
import { fastRaf } from '../../../../util/schedulers';
|
import { fastRaf } from '../../../../util/schedulers';
|
||||||
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
||||||
import useBeforeUnload from '../../../../hooks/useBeforeUnload';
|
import useBeforeUnload from '../../../../hooks/useBeforeUnload';
|
||||||
|
import { useDebouncedResolver } from '../../../../hooks/useAsyncResolvers';
|
||||||
|
import useDerivedSignal from '../../../../hooks/useDerivedSignal';
|
||||||
|
|
||||||
|
const URL_ENTITIES = new Set<string>([ApiMessageEntityTypes.TextUrl, ApiMessageEntityTypes.Url]);
|
||||||
|
const DEBOUNCE_MS = 300;
|
||||||
|
|
||||||
const useEditing = (
|
const useEditing = (
|
||||||
getHtml: Signal<string>,
|
getHtml: Signal<string>,
|
||||||
@ -28,7 +34,7 @@ const useEditing = (
|
|||||||
editingDraft?: ApiFormattedText,
|
editingDraft?: ApiFormattedText,
|
||||||
replyingToId?: number,
|
replyingToId?: number,
|
||||||
): [VoidFunction, VoidFunction, boolean] => {
|
): [VoidFunction, VoidFunction, boolean] => {
|
||||||
const { editMessage, setEditingDraft } = getActions();
|
const { editMessage, setEditingDraft, toggleMessageWebPage } = getActions();
|
||||||
const [shouldForceShowEditing, setShouldForceShowEditing] = useState<boolean>();
|
const [shouldForceShowEditing, setShouldForceShowEditing] = useState<boolean>();
|
||||||
|
|
||||||
useEffectWithPrevDeps(([prevEditedMessage, prevReplyingToId]) => {
|
useEffectWithPrevDeps(([prevEditedMessage, prevReplyingToId]) => {
|
||||||
@ -61,6 +67,21 @@ const useEditing = (
|
|||||||
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps -- `as const` not yet supported by linter
|
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps -- `as const` not yet supported by linter
|
||||||
}, [editedMessage, replyingToId, setHtml] as const);
|
}, [editedMessage, replyingToId, setHtml] as const);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!editedMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldSetNoWebPage = !('webPage' in editedMessage.content)
|
||||||
|
&& editedMessage.content.text?.entities?.some((entity) => URL_ENTITIES.has(entity.type));
|
||||||
|
|
||||||
|
toggleMessageWebPage({
|
||||||
|
chatId,
|
||||||
|
threadId,
|
||||||
|
noWebPage: shouldSetNoWebPage,
|
||||||
|
});
|
||||||
|
}, [chatId, threadId, editedMessage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editedMessage) return undefined;
|
if (!editedMessage) return undefined;
|
||||||
return () => {
|
return () => {
|
||||||
@ -73,6 +94,32 @@ const useEditing = (
|
|||||||
};
|
};
|
||||||
}, [chatId, editedMessage, getHtml, setEditingDraft, threadId, type]);
|
}, [chatId, editedMessage, getHtml, setEditingDraft, threadId, type]);
|
||||||
|
|
||||||
|
const detectLinkDebounced = useDebouncedResolver(() => {
|
||||||
|
if (!editedMessage) return false;
|
||||||
|
|
||||||
|
const edited = parseMessageInput(getHtml());
|
||||||
|
return !('webPage' in editedMessage.content)
|
||||||
|
&& editedMessage.content.text?.entities?.some((entity) => URL_ENTITIES.has(entity.type))
|
||||||
|
&& !(edited.entities?.some((entity) => URL_ENTITIES.has(entity.type)));
|
||||||
|
}, [editedMessage, getHtml], DEBOUNCE_MS, true);
|
||||||
|
|
||||||
|
const getShouldResetNoWebPageDebounced = useDerivedSignal(detectLinkDebounced, [detectLinkDebounced, getHtml], true);
|
||||||
|
|
||||||
|
useEffectWithPrevDeps(([prevEditedMessage]) => {
|
||||||
|
if (!editedMessage || prevEditedMessage?.id !== editedMessage.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getShouldResetNoWebPageDebounced()) {
|
||||||
|
toggleMessageWebPage({
|
||||||
|
chatId,
|
||||||
|
threadId,
|
||||||
|
noWebPage: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps -- `as const` not yet supported by linter
|
||||||
|
}, [editedMessage, chatId, getHtml, threadId] as const);
|
||||||
|
|
||||||
const restoreNewDraftAfterEditing = useCallback(() => {
|
const restoreNewDraftAfterEditing = useCallback(() => {
|
||||||
if (!draft) return;
|
if (!draft) return;
|
||||||
// Run 1 frame after editing draft reset
|
// Run 1 frame after editing draft reset
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user