// Copyright 2018-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; import * as GoogleChrome from '../util/GoogleChrome'; import { AttachmentType } from '../types/Attachment'; import { LocalizerType } from '../types/Util'; export type Props = { attachment: AttachmentType; i18n: LocalizerType; url: string; caption?: string; onSave?: (caption: string) => void; close?: () => void; }; type State = { caption: string; }; export class CaptionEditor extends React.Component { private readonly handleKeyDownBound: ( event: React.KeyboardEvent ) => void; private readonly setFocusBound: () => void; private readonly onChangeBound: ( event: React.FormEvent ) => void; private readonly onSaveBound: () => void; private readonly inputRef: React.RefObject; constructor(props: Props) { super(props); const { caption } = props; this.state = { caption: caption || '', }; this.handleKeyDownBound = this.handleKeyDown.bind(this); this.setFocusBound = this.setFocus.bind(this); this.onChangeBound = this.onChange.bind(this); this.onSaveBound = this.onSave.bind(this); this.inputRef = React.createRef(); } public componentDidMount(): void { // Forcing focus after a delay due to some focus contention with ConversationView setTimeout(() => { this.setFocus(); }, 200); } public handleKeyDown(event: React.KeyboardEvent): void { const { close, onSave } = this.props; if (close && event.key === 'Escape') { close(); event.stopPropagation(); event.preventDefault(); } if (onSave && event.key === 'Enter') { const { caption } = this.state; onSave(caption); event.stopPropagation(); event.preventDefault(); } } public setFocus(): void { if (this.inputRef.current) { this.inputRef.current.focus(); } } public onSave(): void { const { onSave } = this.props; const { caption } = this.state; if (onSave) { onSave(caption); } } public onChange(event: React.FormEvent): void { const { value } = event.target as HTMLInputElement; this.setState({ caption: value, }); } public renderObject(): JSX.Element { const { url, i18n, attachment } = this.props; const { contentType } = attachment || { contentType: null }; const isImageTypeSupported = GoogleChrome.isImageTypeSupported(contentType); if (isImageTypeSupported) { return ( {i18n('imageAttachmentAlt')} ); } const isVideoTypeSupported = GoogleChrome.isVideoTypeSupported(contentType); if (isVideoTypeSupported) { return ( ); } return
; } // Events handled by props /* eslint-disable jsx-a11y/click-events-have-key-events */ public render(): JSX.Element { const { i18n, close } = this.props; const { caption } = this.state; const onKeyDown = close ? this.handleKeyDownBound : undefined; return (
{this.renderObject()}
{caption ? ( ) : null}
); } /* eslint-enable jsx-a11y/click-events-have-key-events */ }