Fix unfocused paste handling and focus return for file uploads (#7625)

This commit is contained in:
Michael Telatynski 2022-01-26 09:04:19 +00:00 committed by GitHub
parent e53427fce3
commit 88cd2f8af7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 16 deletions

View file

@ -24,7 +24,7 @@ import encrypt from "browser-encrypt-attachment";
import extractPngChunks from "png-chunks-extract";
import { IAbortablePromise, IImageInfo } from "matrix-js-sdk/src/@types/partials";
import { logger } from "matrix-js-sdk/src/logger";
import { IEventRelation } from "matrix-js-sdk/src";
import { IEventRelation, ISendEventResponse } from "matrix-js-sdk/src";
import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent";
import dis from './dispatcher/dispatcher';
@ -46,6 +46,7 @@ import { IUpload } from "./models/IUpload";
import { BlurhashEncoder } from "./BlurhashEncoder";
import SettingsStore from "./settings/SettingsStore";
import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics";
import { TimelineRenderingType } from "./contexts/RoomContext";
const MAX_WIDTH = 800;
const MAX_HEIGHT = 600;
@ -421,14 +422,14 @@ export default class ContentMessages {
private inprogress: IUpload[] = [];
private mediaConfig: IMediaConfig = null;
sendStickerContentToRoom(
public sendStickerContentToRoom(
url: string,
roomId: string,
threadId: string | null,
info: IImageInfo,
text: string,
matrixClient: MatrixClient,
) {
): Promise<ISendEventResponse> {
const startTime = CountlyAnalytics.getTimestamp();
const prom = matrixClient.sendStickerMessage(roomId, threadId, url, info, text).catch((e) => {
logger.warn(`Failed to send content with URL ${url} to room ${roomId}`, e);
@ -438,7 +439,7 @@ export default class ContentMessages {
return prom;
}
getUploadLimit() {
public getUploadLimit(): number | null {
if (this.mediaConfig !== null && this.mediaConfig["m.upload.size"] !== undefined) {
return this.mediaConfig["m.upload.size"];
} else {
@ -446,12 +447,13 @@ export default class ContentMessages {
}
}
async sendContentListToRoom(
public async sendContentListToRoom(
files: File[],
roomId: string,
relation: IEventRelation | null,
matrixClient: MatrixClient,
) {
context = TimelineRenderingType.Room,
): Promise<void> {
if (matrixClient.isGuest()) {
dis.dispatch({ action: 'require_registration' });
return;
@ -530,9 +532,15 @@ export default class ContentMessages {
promBefore = this.sendContentToRoom(file, roomId, relation, matrixClient, promBefore);
}
// Focus the correct composer
dis.dispatch({
action: Action.FocusSendMessageComposer,
context,
});
}
getCurrentUploads(relation?: IEventRelation) {
public getCurrentUploads(relation?: IEventRelation): IUpload[] {
return this.inprogress.filter(upload => {
const noRelation = !relation && !upload.relation;
const matchingRelation = relation && upload.relation
@ -543,7 +551,7 @@ export default class ContentMessages {
});
}
cancelUpload(promise: Promise<any>, matrixClient: MatrixClient) {
public cancelUpload(promise: Promise<any>, matrixClient: MatrixClient): void {
let upload: IUpload;
for (let i = 0; i < this.inprogress.length; ++i) {
if (this.inprogress[i].promise === promise) {
@ -632,9 +640,6 @@ export default class ContentMessages {
this.inprogress.push(upload);
dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload });
// Focus the composer view
dis.fire(Action.FocusSendMessageComposer);
function onProgress(ev) {
upload.total = ev.total;
upload.loaded = ev.loaded;

View file

@ -69,6 +69,7 @@ import LegacyCommunityPreview from "./LegacyCommunityPreview";
import { UserTab } from "../views/dialogs/UserSettingsDialog";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
import RightPanelStore from '../../stores/right-panel/RightPanelStore';
import { TimelineRenderingType } from "../../contexts/RoomContext";
// We need to fetch each pinned message individually (if we don't already have it)
// so each pinned message may trigger a request. Limit the number per room for sanity.
@ -386,15 +387,20 @@ class LoggedInView extends React.Component<IProps, IState> {
private onPaste = (ev: ClipboardEvent) => {
const element = ev.target as HTMLElement;
const inputableElement = getInputableElement(element) || document.activeElement as HTMLElement;
const inputableElement = getInputableElement(element);
if (inputableElement === document.activeElement) return; // nothing to do
if (inputableElement?.focus) {
inputableElement.focus();
} else {
const inThread = !!document.activeElement.closest(".mx_ThreadView");
// refocusing during a paste event will make the
// paste end up in the newly focused element,
// so dispatch synchronously before paste happens
dis.fire(Action.FocusSendMessageComposer, true);
dis.dispatch({
action: Action.FocusSendMessageComposer,
context: inThread ? TimelineRenderingType.Thread : TimelineRenderingType.Room,
}, true);
}
};
@ -552,8 +558,12 @@ class LoggedInView extends React.Component<IProps, IState> {
// If the user is entering a printable character outside of an input field
// redirect it to the composer for them.
if (!isClickShortcut && isPrintable && !getInputableElement(ev.target as HTMLElement)) {
const inThread = !!document.activeElement.closest(".mx_ThreadView");
// synchronous dispatch so we focus before key generates input
dis.fire(Action.FocusSendMessageComposer, true);
dis.dispatch({
action: Action.FocusSendMessageComposer,
context: inThread ? TimelineRenderingType.Thread : TimelineRenderingType.Room,
}, true);
ev.stopPropagation();
// we should *not* preventDefault() here as that would prevent typing in the now-focused composer
}

View file

@ -160,7 +160,11 @@ class UploadButton extends React.Component<IUploadButtonProps> {
}
ContentMessages.sharedInstance().sendContentListToRoom(
tfiles, this.props.roomId, this.props.relation, MatrixClientPeg.get(),
tfiles,
this.props.roomId,
this.props.relation,
MatrixClientPeg.get(),
this.context.timelineRenderingType,
);
// This is the onChange handler for a file form control, but we're

View file

@ -560,7 +560,11 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
// it puts the filename in as text/plain which we want to ignore.
if (clipboardData.files.length && !clipboardData.types.includes("text/rtf")) {
ContentMessages.sharedInstance().sendContentListToRoom(
Array.from(clipboardData.files), this.props.room.roomId, this.props.relation, this.props.mxClient,
Array.from(clipboardData.files),
this.props.room.roomId,
this.props.relation,
this.props.mxClient,
this.context.timelineRenderingType,
);
return true; // to skip internal onPaste handler
}