mirror of
https://github.com/element-hq/element-web
synced 2024-11-28 12:28:50 +03:00
Fix unfocused paste handling and focus return for file uploads (#7625)
This commit is contained in:
parent
e53427fce3
commit
88cd2f8af7
4 changed files with 39 additions and 16 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue