Remove caption editor
This commit is contained in:
parent
6e394a84d6
commit
37992715cd
14 changed files with 7 additions and 512 deletions
|
@ -1268,13 +1268,9 @@
|
||||||
"message": "Icon showing that this image has a caption",
|
"message": "Icon showing that this image has a caption",
|
||||||
"description": "Used for the icon layered on top of an image in message bubbles"
|
"description": "Used for the icon layered on top of an image in message bubbles"
|
||||||
},
|
},
|
||||||
"addACaption": {
|
|
||||||
"message": "Add a caption...",
|
|
||||||
"description": "Used as the placeholder text in the caption editor text field"
|
|
||||||
},
|
|
||||||
"save": {
|
"save": {
|
||||||
"message": "Save",
|
"message": "Save",
|
||||||
"description": "Used as a 'commit changes' button in the caption editor for outgoing image attachments"
|
"description": "Used on save buttons"
|
||||||
},
|
},
|
||||||
"reset": {
|
"reset": {
|
||||||
"message": "Reset",
|
"message": "Reset",
|
||||||
|
|
|
@ -24,7 +24,6 @@ const Util = require('../../ts/util');
|
||||||
const {
|
const {
|
||||||
AttachmentList,
|
AttachmentList,
|
||||||
} = require('../../ts/components/conversation/AttachmentList');
|
} = require('../../ts/components/conversation/AttachmentList');
|
||||||
const { CaptionEditor } = require('../../ts/components/CaptionEditor');
|
|
||||||
const { ChatColorPicker } = require('../../ts/components/ChatColorPicker');
|
const { ChatColorPicker } = require('../../ts/components/ChatColorPicker');
|
||||||
const {
|
const {
|
||||||
ConfirmationDialog,
|
ConfirmationDialog,
|
||||||
|
@ -329,7 +328,6 @@ exports.setup = (options = {}) => {
|
||||||
|
|
||||||
const Components = {
|
const Components = {
|
||||||
AttachmentList,
|
AttachmentList,
|
||||||
CaptionEditor,
|
|
||||||
ChatColorPicker,
|
ChatColorPicker,
|
||||||
ConfirmationDialog,
|
ConfirmationDialog,
|
||||||
ContactDetail,
|
ContactDetail,
|
||||||
|
|
|
@ -3326,129 +3326,6 @@ button.module-image__border-overlay:focus {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module: Caption Editor
|
|
||||||
|
|
||||||
.module-caption-editor {
|
|
||||||
background-color: $color-black;
|
|
||||||
z-index: 20;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__close-button {
|
|
||||||
z-index: 21;
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
top: 12px;
|
|
||||||
right: 16px;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
z-index: 2;
|
|
||||||
@include color-svg('../images/icons/v2/x-24.svg', $color-white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__media-container {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
background-color: $color-black;
|
|
||||||
text-align: center;
|
|
||||||
margin: 50px;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__image {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
}
|
|
||||||
.module-caption-editor__video {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
}
|
|
||||||
.module-caption-editor__placeholder {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__bottom-bar {
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
height: 52px;
|
|
||||||
padding: 8px;
|
|
||||||
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: middle;
|
|
||||||
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__input-container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__caption-input {
|
|
||||||
height: 36px;
|
|
||||||
width: 40em;
|
|
||||||
|
|
||||||
color: $color-white;
|
|
||||||
|
|
||||||
border: 1px solid $color-white;
|
|
||||||
border-radius: 18px;
|
|
||||||
background-color: $color-black;
|
|
||||||
padding: 9px;
|
|
||||||
padding-left: 12px;
|
|
||||||
padding-right: 65px;
|
|
||||||
|
|
||||||
&:placeholder {
|
|
||||||
color: $color-white-alpha-80;
|
|
||||||
}
|
|
||||||
&:focus {
|
|
||||||
border: 1px solid $color-ultramarine;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.module-caption-editor__save-button {
|
|
||||||
@include button-reset;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
background-color: $color-ultramarine;
|
|
||||||
color: $color-white;
|
|
||||||
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 15px;
|
|
||||||
|
|
||||||
padding: 5px;
|
|
||||||
padding-left: 12px;
|
|
||||||
padding-right: 12px;
|
|
||||||
|
|
||||||
right: 4px;
|
|
||||||
top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module: Staged Placeholder Attachment
|
// Module: Staged Placeholder Attachment
|
||||||
|
|
||||||
.module-staged-placeholder-attachment {
|
.module-staged-placeholder-attachment {
|
||||||
|
|
|
@ -1246,14 +1246,7 @@ export async function startApp(): Promise<void> {
|
||||||
const className = (target.attributes as any).class.value;
|
const className = (target.attributes as any).class.value;
|
||||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
// These want to handle events internally
|
// Search box wants to handle events internally
|
||||||
|
|
||||||
// CaptionEditor text box
|
|
||||||
if (className.includes('module-caption-editor__caption-input')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search box
|
|
||||||
if (className.includes('LeftPaneSearchInput__input')) {
|
if (className.includes('LeftPaneSearchInput__input')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
// Copyright 2020 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { storiesOf } from '@storybook/react';
|
|
||||||
import { text } from '@storybook/addon-knobs';
|
|
||||||
import { action } from '@storybook/addon-actions';
|
|
||||||
|
|
||||||
import type { Props } from './CaptionEditor';
|
|
||||||
import { CaptionEditor } from './CaptionEditor';
|
|
||||||
import { AUDIO_MP3, IMAGE_JPEG, VIDEO_MP4 } from '../types/MIME';
|
|
||||||
import { setupI18n } from '../util/setupI18n';
|
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
|
||||||
|
|
||||||
import { fakeAttachment } from '../test-both/helpers/fakeAttachment';
|
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
|
||||||
|
|
||||||
const stories = storiesOf('Components/Caption Editor', module);
|
|
||||||
|
|
||||||
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|
||||||
attachment: fakeAttachment({
|
|
||||||
contentType: IMAGE_JPEG,
|
|
||||||
fileName: '',
|
|
||||||
url: '',
|
|
||||||
...overrideProps.attachment,
|
|
||||||
}),
|
|
||||||
caption: text('caption', overrideProps.caption || ''),
|
|
||||||
close: action('close'),
|
|
||||||
i18n,
|
|
||||||
onSave: action('onSave'),
|
|
||||||
url: text('url', overrideProps.url || ''),
|
|
||||||
});
|
|
||||||
|
|
||||||
stories.add('Image', () => {
|
|
||||||
const props = createProps({
|
|
||||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
|
||||||
});
|
|
||||||
|
|
||||||
return <CaptionEditor {...props} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
stories.add('Image with Caption', () => {
|
|
||||||
const props = createProps({
|
|
||||||
caption:
|
|
||||||
'This is the user-provided caption. We show it overlaid on the image. If it is really long, then it wraps, but it does not get too close to the edges of the image.',
|
|
||||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
|
||||||
});
|
|
||||||
|
|
||||||
return <CaptionEditor {...props} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
stories.add('Video', () => {
|
|
||||||
const props = createProps({
|
|
||||||
attachment: fakeAttachment({
|
|
||||||
contentType: VIDEO_MP4,
|
|
||||||
fileName: 'pixabay-Soap-Bubble-7141.mp4',
|
|
||||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
|
||||||
}),
|
|
||||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
|
||||||
});
|
|
||||||
|
|
||||||
return <CaptionEditor {...props} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
stories.add('Video with Caption', () => {
|
|
||||||
const props = createProps({
|
|
||||||
attachment: fakeAttachment({
|
|
||||||
contentType: VIDEO_MP4,
|
|
||||||
fileName: 'pixabay-Soap-Bubble-7141.mp4',
|
|
||||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
|
||||||
}),
|
|
||||||
caption:
|
|
||||||
'This is the user-provided caption. We show it overlaid on the image. If it is really long, then it wraps, but it does not get too close to the edges of the image.',
|
|
||||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
|
||||||
});
|
|
||||||
|
|
||||||
return <CaptionEditor {...props} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
stories.add('Unsupported Attachment Type', () => {
|
|
||||||
const props = createProps({
|
|
||||||
attachment: fakeAttachment({
|
|
||||||
contentType: AUDIO_MP3,
|
|
||||||
fileName: 'incompetech-com-Agnus-Dei-X.mp3',
|
|
||||||
url: '/fixtures/incompetech-com-Agnus-Dei-X.mp3',
|
|
||||||
}),
|
|
||||||
url: '/fixtures/incompetech-com-Agnus-Dei-X.mp3',
|
|
||||||
});
|
|
||||||
|
|
||||||
return <CaptionEditor {...props} />;
|
|
||||||
});
|
|
|
@ -1,181 +0,0 @@
|
||||||
// Copyright 2018-2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import * as GoogleChrome from '../util/GoogleChrome';
|
|
||||||
|
|
||||||
import type { AttachmentType } from '../types/Attachment';
|
|
||||||
|
|
||||||
import type { 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<Props, State> {
|
|
||||||
private readonly handleKeyDownBound: (
|
|
||||||
event: React.KeyboardEvent<HTMLInputElement>
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
private readonly setFocusBound: () => void;
|
|
||||||
|
|
||||||
private readonly onChangeBound: (
|
|
||||||
event: React.FormEvent<HTMLInputElement>
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
private readonly onSaveBound: () => void;
|
|
||||||
|
|
||||||
private readonly inputRef: React.RefObject<HTMLInputElement>;
|
|
||||||
|
|
||||||
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<HTMLInputElement>): 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<HTMLInputElement>): 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 (
|
|
||||||
<img
|
|
||||||
className="module-caption-editor__image"
|
|
||||||
alt={i18n('imageAttachmentAlt')}
|
|
||||||
src={url}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isVideoTypeSupported = GoogleChrome.isVideoTypeSupported(contentType);
|
|
||||||
if (isVideoTypeSupported) {
|
|
||||||
return (
|
|
||||||
<video className="module-caption-editor__video" controls>
|
|
||||||
<source src={url} />
|
|
||||||
</video>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className="module-caption-editor__placeholder" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 (
|
|
||||||
<div
|
|
||||||
role="presentation"
|
|
||||||
onClick={this.setFocusBound}
|
|
||||||
className="module-caption-editor"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
// Okay that this isn't a button; the escape key can be used to close this view
|
|
||||||
role="button"
|
|
||||||
onClick={close}
|
|
||||||
className="module-caption-editor__close-button"
|
|
||||||
tabIndex={0}
|
|
||||||
aria-label={i18n('close')}
|
|
||||||
/>
|
|
||||||
<div className="module-caption-editor__media-container">
|
|
||||||
{this.renderObject()}
|
|
||||||
</div>
|
|
||||||
<div className="module-caption-editor__bottom-bar">
|
|
||||||
<div className="module-caption-editor__input-container">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
ref={this.inputRef}
|
|
||||||
value={caption}
|
|
||||||
maxLength={200}
|
|
||||||
placeholder={i18n('addACaption')}
|
|
||||||
className="module-caption-editor__caption-input"
|
|
||||||
onKeyDown={onKeyDown}
|
|
||||||
onChange={this.onChangeBound}
|
|
||||||
/>
|
|
||||||
{caption ? (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={this.onSaveBound}
|
|
||||||
className="module-caption-editor__save-button"
|
|
||||||
>
|
|
||||||
{i18n('save')}
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/* eslint-enable jsx-a11y/click-events-have-key-events */
|
|
||||||
}
|
|
|
@ -37,7 +37,6 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
// AttachmentList
|
// AttachmentList
|
||||||
draftAttachments: overrideProps.draftAttachments || [],
|
draftAttachments: overrideProps.draftAttachments || [],
|
||||||
onClearAttachments: action('onClearAttachments'),
|
onClearAttachments: action('onClearAttachments'),
|
||||||
onClickAttachment: action('onClickAttachment'),
|
|
||||||
// AudioCapture
|
// AudioCapture
|
||||||
cancelRecording: action('cancelRecording'),
|
cancelRecording: action('cancelRecording'),
|
||||||
completeRecording: action('completeRecording'),
|
completeRecording: action('completeRecording'),
|
||||||
|
|
|
@ -97,7 +97,6 @@ export type OwnProps = Readonly<{
|
||||||
linkPreviewResult?: LinkPreviewWithDomain;
|
linkPreviewResult?: LinkPreviewWithDomain;
|
||||||
messageRequestsEnabled?: boolean;
|
messageRequestsEnabled?: boolean;
|
||||||
onClearAttachments(): unknown;
|
onClearAttachments(): unknown;
|
||||||
onClickAttachment(att: AttachmentType): unknown;
|
|
||||||
onClickQuotedMessage(): unknown;
|
onClickQuotedMessage(): unknown;
|
||||||
onCloseLinkPreview(): unknown;
|
onCloseLinkPreview(): unknown;
|
||||||
processAttachments: (options: HandleAttachmentsProcessingArgsType) => unknown;
|
processAttachments: (options: HandleAttachmentsProcessingArgsType) => unknown;
|
||||||
|
@ -170,7 +169,6 @@ export const CompositionArea = ({
|
||||||
// AttachmentList
|
// AttachmentList
|
||||||
draftAttachments,
|
draftAttachments,
|
||||||
onClearAttachments,
|
onClearAttachments,
|
||||||
onClickAttachment,
|
|
||||||
// AudioCapture
|
// AudioCapture
|
||||||
cancelRecording,
|
cancelRecording,
|
||||||
completeRecording,
|
completeRecording,
|
||||||
|
@ -603,7 +601,6 @@ export const CompositionArea = ({
|
||||||
attachments={draftAttachments}
|
attachments={draftAttachments}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onAddAttachment={launchAttachmentPicker}
|
onAddAttachment={launchAttachmentPicker}
|
||||||
onClickAttachment={onClickAttachment}
|
|
||||||
onClose={onClearAttachments}
|
onClose={onClearAttachments}
|
||||||
onCloseAttachment={attachment => {
|
onCloseAttachment={attachment => {
|
||||||
if (attachment.path) {
|
if (attachment.path) {
|
||||||
|
|
|
@ -67,9 +67,6 @@ export const AttachmentList = ({
|
||||||
const isVideo = isVideoAttachment(attachment);
|
const isVideo = isVideoAttachment(attachment);
|
||||||
|
|
||||||
if (isImage || isVideo || attachment.pending) {
|
if (isImage || isVideo || attachment.pending) {
|
||||||
const clickCallback =
|
|
||||||
attachments.length > 1 ? onClickAttachment : undefined;
|
|
||||||
|
|
||||||
const imageUrl =
|
const imageUrl =
|
||||||
url || (isVideo ? BLANK_VIDEO_THUMBNAIL : undefined);
|
url || (isVideo ? BLANK_VIDEO_THUMBNAIL : undefined);
|
||||||
|
|
||||||
|
@ -88,7 +85,7 @@ export const AttachmentList = ({
|
||||||
width={IMAGE_WIDTH}
|
width={IMAGE_WIDTH}
|
||||||
url={imageUrl}
|
url={imageUrl}
|
||||||
closeButton
|
closeButton
|
||||||
onClick={clickCallback}
|
onClick={onClickAttachment}
|
||||||
onClickClose={onCloseAttachment}
|
onClickClose={onCloseAttachment}
|
||||||
onError={() => {
|
onError={() => {
|
||||||
onCloseAttachment(attachment);
|
onCloseAttachment(attachment);
|
||||||
|
|
|
@ -27,7 +27,6 @@ export type PropsType = {
|
||||||
| 'onCancelJoinRequest'
|
| 'onCancelJoinRequest'
|
||||||
| 'onClearAttachments'
|
| 'onClearAttachments'
|
||||||
| 'onClickAddPack'
|
| 'onClickAddPack'
|
||||||
| 'onClickAttachment'
|
|
||||||
| 'onCloseLinkPreview'
|
| 'onCloseLinkPreview'
|
||||||
| 'onDelete'
|
| 'onDelete'
|
||||||
| 'onEditorStateChange'
|
| 'onEditorStateChange'
|
||||||
|
|
|
@ -103,8 +103,10 @@ export type AttachmentDraftType =
|
||||||
| ({
|
| ({
|
||||||
url: string;
|
url: string;
|
||||||
screenshotPath?: string;
|
screenshotPath?: string;
|
||||||
caption?: string;
|
|
||||||
pending: false;
|
pending: false;
|
||||||
|
// Old draft attachments may have a caption, though they are no longer editable
|
||||||
|
// because we removed the caption editor.
|
||||||
|
caption?: string;
|
||||||
} & BaseAttachmentDraftType)
|
} & BaseAttachmentDraftType)
|
||||||
| {
|
| {
|
||||||
contentType: MIME.MIMEType;
|
contentType: MIME.MIMEType;
|
||||||
|
|
|
@ -10303,22 +10303,6 @@
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-07-30T16:57:33.618Z"
|
"updated": "2021-07-30T16:57:33.618Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"rule": "React-createRef",
|
|
||||||
"path": "ts/components/CaptionEditor.js",
|
|
||||||
"line": " this.inputRef = react_1.default.createRef();",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2019-03-09T00:08:44.242Z",
|
|
||||||
"reasonDetail": "Used only to set focus"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rule": "React-createRef",
|
|
||||||
"path": "ts/components/CaptionEditor.tsx",
|
|
||||||
"line": " this.inputRef = React.createRef();",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2019-03-09T00:08:44.242Z",
|
|
||||||
"reasonDetail": "Used only to set focus"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/ChatColorPicker.tsx",
|
"path": "ts/components/ChatColorPicker.tsx",
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { batch as batchDispatch } from 'react-redux';
|
||||||
import { debounce, flatten, omit, throttle } from 'lodash';
|
import { debounce, flatten, omit, throttle } from 'lodash';
|
||||||
import { render } from 'mustache';
|
import { render } from 'mustache';
|
||||||
|
|
||||||
import type { AttachmentDraftType, AttachmentType } from '../types/Attachment';
|
import type { AttachmentType } from '../types/Attachment';
|
||||||
import { isGIF } from '../types/Attachment';
|
import { isGIF } from '../types/Attachment';
|
||||||
import * as Attachment from '../types/Attachment';
|
import * as Attachment from '../types/Attachment';
|
||||||
import type { StickerPackType as StickerPackDBType } from '../sql/Interface';
|
import type { StickerPackType as StickerPackDBType } from '../sql/Interface';
|
||||||
|
@ -239,7 +239,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
private preview?: Array<LinkPreviewResult>;
|
private preview?: Array<LinkPreviewResult>;
|
||||||
|
|
||||||
// Sub-views
|
// Sub-views
|
||||||
private captionEditorView?: Backbone.View;
|
|
||||||
private contactModalView?: Backbone.View;
|
private contactModalView?: Backbone.View;
|
||||||
private conversationView?: BasicReactWrapperViewClass;
|
private conversationView?: BasicReactWrapperViewClass;
|
||||||
private forwardMessageModal?: Backbone.View;
|
private forwardMessageModal?: Backbone.View;
|
||||||
|
@ -730,7 +729,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onClickAttachment: this.onClickAttachment.bind(this),
|
|
||||||
onClearAttachments: this.clearAttachments.bind(this),
|
onClearAttachments: this.clearAttachments.bind(this),
|
||||||
onSelectMediaQuality: (isHQ: boolean) => {
|
onSelectMediaQuality: (isHQ: boolean) => {
|
||||||
window.reduxActions.composer.setMediaQualitySetting(isHQ);
|
window.reduxActions.composer.setMediaQualitySetting(isHQ);
|
||||||
|
@ -1364,9 +1362,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
|
|
||||||
this.conversationView?.remove();
|
this.conversationView?.remove();
|
||||||
|
|
||||||
if (this.captionEditorView) {
|
|
||||||
this.captionEditorView.remove();
|
|
||||||
}
|
|
||||||
if (this.contactModalView) {
|
if (this.contactModalView) {
|
||||||
this.contactModalView.remove();
|
this.contactModalView.remove();
|
||||||
}
|
}
|
||||||
|
@ -1474,72 +1469,6 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickAttachment(attachment: AttachmentDraftType): void {
|
|
||||||
if (attachment.pending) {
|
|
||||||
throw new Error(
|
|
||||||
'onClickAttachment: Cannot click to edit pending attachment'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getProps = () => {
|
|
||||||
if (attachment.pending) {
|
|
||||||
throw new Error(
|
|
||||||
'onClickAttachment/onSave: Cannot render pending attachment'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: attachment.url,
|
|
||||||
caption: attachment.caption,
|
|
||||||
attachment,
|
|
||||||
onSave,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSave = (caption?: string) => {
|
|
||||||
const attachments = this.model.get('draftAttachments') || [];
|
|
||||||
|
|
||||||
this.model.set({
|
|
||||||
draftAttachments: attachments.map((item: AttachmentType) => {
|
|
||||||
if (item.pending || attachment.pending) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(item.path && item.path === attachment.path) ||
|
|
||||||
(item.screenshotPath &&
|
|
||||||
item.screenshotPath === attachment.screenshotPath)
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
...attachment,
|
|
||||||
caption,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}),
|
|
||||||
draftChanged: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.captionEditorView) {
|
|
||||||
this.captionEditorView.remove();
|
|
||||||
this.captionEditorView = undefined;
|
|
||||||
}
|
|
||||||
window.Signal.Backbone.Views.Lightbox.hide();
|
|
||||||
|
|
||||||
this.updateAttachmentsView();
|
|
||||||
this.saveModel();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.captionEditorView = new Whisper.ReactWrapperView({
|
|
||||||
className: 'attachment-list-wrapper',
|
|
||||||
Component: window.Signal.Components.CaptionEditor,
|
|
||||||
props: getProps(),
|
|
||||||
onClose: () => window.Signal.Backbone.Views.Lightbox.hide(),
|
|
||||||
});
|
|
||||||
window.Signal.Backbone.Views.Lightbox.show(this.captionEditorView.el);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveModel(): Promise<void> {
|
async saveModel(): Promise<void> {
|
||||||
window.Signal.Data.updateConversation(this.model.attributes);
|
window.Signal.Data.updateConversation(this.model.attributes);
|
||||||
}
|
}
|
||||||
|
|
2
ts/window.d.ts
vendored
2
ts/window.d.ts
vendored
|
@ -79,7 +79,6 @@ import { ConversationModel } from './models/conversations';
|
||||||
import { combineNames } from './util';
|
import { combineNames } from './util';
|
||||||
import { BatcherType } from './util/batcher';
|
import { BatcherType } from './util/batcher';
|
||||||
import { AttachmentList } from './components/conversation/AttachmentList';
|
import { AttachmentList } from './components/conversation/AttachmentList';
|
||||||
import { CaptionEditor } from './components/CaptionEditor';
|
|
||||||
import { ChatColorPicker } from './components/ChatColorPicker';
|
import { ChatColorPicker } from './components/ChatColorPicker';
|
||||||
import { ConfirmationDialog } from './components/ConfirmationDialog';
|
import { ConfirmationDialog } from './components/ConfirmationDialog';
|
||||||
import { ContactDetail } from './components/conversation/ContactDetail';
|
import { ContactDetail } from './components/conversation/ContactDetail';
|
||||||
|
@ -389,7 +388,6 @@ declare global {
|
||||||
};
|
};
|
||||||
Components: {
|
Components: {
|
||||||
AttachmentList: typeof AttachmentList;
|
AttachmentList: typeof AttachmentList;
|
||||||
CaptionEditor: typeof CaptionEditor;
|
|
||||||
ChatColorPicker: typeof ChatColorPicker;
|
ChatColorPicker: typeof ChatColorPicker;
|
||||||
ConfirmationDialog: typeof ConfirmationDialog;
|
ConfirmationDialog: typeof ConfirmationDialog;
|
||||||
ContactDetail: typeof ContactDetail;
|
ContactDetail: typeof ContactDetail;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue