mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 12:45:11 +08:00
Enable @typescript-eslint/explicit-function-return-type
in /src (#9788)
* Enable `@typescript-eslint/explicit-member-accessibility` on /src * Prettier * Enable `@typescript-eslint/explicit-function-return-type` in /src * Fix types * tsc strict fixes * Delint * Fix test * Fix bad merge
This commit is contained in:
parent
7a36ba0fde
commit
030b7e90bf
@ -100,8 +100,12 @@ module.exports = {
|
||||
files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "cypress/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
|
||||
rules: {
|
||||
// temporary disabled
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{
|
||||
allowExpressions: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
|
8
src/@types/diff-dom.d.ts
vendored
8
src/@types/diff-dom.d.ts
vendored
@ -20,10 +20,10 @@ declare module "diff-dom" {
|
||||
name: string;
|
||||
text?: string;
|
||||
route: number[];
|
||||
value: string;
|
||||
element: unknown;
|
||||
oldValue: string;
|
||||
newValue: string;
|
||||
value: HTMLElement | string;
|
||||
element: HTMLElement | string;
|
||||
oldValue: HTMLElement | string;
|
||||
newValue: HTMLElement | string;
|
||||
}
|
||||
|
||||
interface IOpts {}
|
||||
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
// This is intended to fix re-resizer because of its unguarded `instanceof TouchEvent` checks.
|
||||
export function polyfillTouchEvent() {
|
||||
export function polyfillTouchEvent(): void {
|
||||
// Firefox doesn't have touch events without touch devices being present, so create a fake
|
||||
// one we can rely on lying about.
|
||||
if (!window.TouchEvent) {
|
||||
|
@ -47,7 +47,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
|
||||
error: null,
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
// XXX: temporary logging to try to diagnose
|
||||
// https://github.com/vector-im/element-web/issues/3148
|
||||
logger.log("Starting load of AsyncWrapper for modal");
|
||||
@ -69,15 +69,15 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
}
|
||||
|
||||
private onWrapperCancelClick = () => {
|
||||
private onWrapperCancelClick = (): void => {
|
||||
this.props.onFinished(false);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
if (this.state.component) {
|
||||
const Component = this.state.component;
|
||||
return <Component {...this.props} />;
|
||||
|
@ -137,7 +137,12 @@ export function getInitialLetter(name: string): string {
|
||||
return split(name, "", 1)[0].toUpperCase();
|
||||
}
|
||||
|
||||
export function avatarUrlForRoom(room: Room, width: number, height: number, resizeMethod?: ResizeMethod) {
|
||||
export function avatarUrlForRoom(
|
||||
room: Room,
|
||||
width: number,
|
||||
height: number,
|
||||
resizeMethod?: ResizeMethod,
|
||||
): string | null {
|
||||
if (!room) return null; // null-guard
|
||||
|
||||
if (room.getMxcAvatarUrl()) {
|
||||
|
@ -272,7 +272,7 @@ export default abstract class BasePlatform {
|
||||
return null;
|
||||
}
|
||||
|
||||
public setLanguage(preferredLangs: string[]) {}
|
||||
public setLanguage(preferredLangs: string[]): void {}
|
||||
|
||||
public setSpellCheckEnabled(enabled: boolean): void {}
|
||||
|
||||
@ -280,7 +280,7 @@ export default abstract class BasePlatform {
|
||||
return null;
|
||||
}
|
||||
|
||||
public setSpellCheckLanguages(preferredLangs: string[]) {}
|
||||
public setSpellCheckLanguages(preferredLangs: string[]): void {}
|
||||
|
||||
public getSpellCheckLanguages(): Promise<string[]> | null {
|
||||
return null;
|
||||
|
@ -40,7 +40,7 @@ export class BlurhashEncoder {
|
||||
this.worker.onmessage = this.onMessage;
|
||||
}
|
||||
|
||||
private onMessage = (ev: MessageEvent<IBlurhashWorkerResponse>) => {
|
||||
private onMessage = (ev: MessageEvent<IBlurhashWorkerResponse>): void => {
|
||||
const { seq, blurhash } = ev.data;
|
||||
const deferred = this.pendingDeferredMap.get(seq);
|
||||
if (deferred) {
|
||||
|
@ -68,16 +68,20 @@ interface IMediaConfig {
|
||||
* @param {File} imageFile The file to load in an image element.
|
||||
* @return {Promise} A promise that resolves with the html image element.
|
||||
*/
|
||||
async function loadImageElement(imageFile: File) {
|
||||
async function loadImageElement(imageFile: File): Promise<{
|
||||
width: number;
|
||||
height: number;
|
||||
img: HTMLImageElement;
|
||||
}> {
|
||||
// Load the file into an html element
|
||||
const img = new Image();
|
||||
const objectUrl = URL.createObjectURL(imageFile);
|
||||
const imgPromise = new Promise((resolve, reject) => {
|
||||
img.onload = function () {
|
||||
img.onload = function (): void {
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
resolve(img);
|
||||
};
|
||||
img.onerror = function (e) {
|
||||
img.onerror = function (e): void {
|
||||
reject(e);
|
||||
};
|
||||
});
|
||||
@ -185,13 +189,13 @@ function loadVideoElement(videoFile: File): Promise<HTMLVideoElement> {
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function (ev) {
|
||||
reader.onload = function (ev): void {
|
||||
// Wait until we have enough data to thumbnail the first frame.
|
||||
video.onloadeddata = async function () {
|
||||
video.onloadeddata = async function (): Promise<void> {
|
||||
resolve(video);
|
||||
video.pause();
|
||||
};
|
||||
video.onerror = function (e) {
|
||||
video.onerror = function (e): void {
|
||||
reject(e);
|
||||
};
|
||||
|
||||
@ -206,7 +210,7 @@ function loadVideoElement(videoFile: File): Promise<HTMLVideoElement> {
|
||||
video.load();
|
||||
video.play();
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reader.onerror = function (e): void {
|
||||
reject(e);
|
||||
};
|
||||
reader.readAsDataURL(videoFile);
|
||||
@ -253,10 +257,10 @@ function infoForVideoFile(
|
||||
function readFileAsArrayBuffer(file: File | Blob): Promise<ArrayBuffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
reader.onload = function (e): void {
|
||||
resolve(e.target.result as ArrayBuffer);
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
reader.onerror = function (e): void {
|
||||
reject(e);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
@ -461,7 +465,7 @@ export default class ContentMessages {
|
||||
matrixClient: MatrixClient,
|
||||
replyToEvent: MatrixEvent | undefined,
|
||||
promBefore?: Promise<any>,
|
||||
) {
|
||||
): Promise<void> {
|
||||
const fileName = file.name || _t("Attachment");
|
||||
const content: Omit<IMediaEventContent, "info"> & { info: Partial<IMediaEventInfo> } = {
|
||||
body: fileName,
|
||||
@ -491,7 +495,7 @@ export default class ContentMessages {
|
||||
this.inprogress.push(upload);
|
||||
dis.dispatch<UploadStartedPayload>({ action: Action.UploadStarted, upload });
|
||||
|
||||
function onProgress(progress: UploadProgress) {
|
||||
function onProgress(progress: UploadProgress): void {
|
||||
upload.onProgress(progress);
|
||||
dis.dispatch<UploadProgressPayload>({ action: Action.UploadProgress, upload });
|
||||
}
|
||||
@ -568,7 +572,7 @@ export default class ContentMessages {
|
||||
}
|
||||
}
|
||||
|
||||
private isFileSizeAcceptable(file: File) {
|
||||
private isFileSizeAcceptable(file: File): boolean {
|
||||
if (
|
||||
this.mediaConfig !== null &&
|
||||
this.mediaConfig["m.upload.size"] !== undefined &&
|
||||
@ -599,7 +603,7 @@ export default class ContentMessages {
|
||||
});
|
||||
}
|
||||
|
||||
public static sharedInstance() {
|
||||
public static sharedInstance(): ContentMessages {
|
||||
if (window.mxContentMessages === undefined) {
|
||||
window.mxContentMessages = new ContentMessages();
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ export function wantsDateSeparator(prevEventDate: Date, nextEventDate: Date): bo
|
||||
return prevEventDate.getDay() !== nextEventDate.getDay();
|
||||
}
|
||||
|
||||
export function formatFullDateNoDay(date: Date) {
|
||||
export function formatFullDateNoDay(date: Date): string {
|
||||
return _t("%(date)s at %(time)s", {
|
||||
date: date.toLocaleDateString().replace(/\//g, "-"),
|
||||
time: date.toLocaleTimeString().replace(/:/g, "-"),
|
||||
@ -205,7 +205,7 @@ export function formatFullDateNoDayISO(date: Date): string {
|
||||
return date.toISOString();
|
||||
}
|
||||
|
||||
export function formatFullDateNoDayNoTime(date: Date) {
|
||||
export function formatFullDateNoDayNoTime(date: Date): string {
|
||||
return date.getFullYear() + "/" + pad(date.getMonth() + 1) + "/" + pad(date.getDate());
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||
import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { SyncState } from "matrix-js-sdk/src/sync";
|
||||
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
|
||||
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import dis from "./dispatcher/dispatcher";
|
||||
@ -56,7 +57,7 @@ export default class DeviceListener {
|
||||
// has the user dismissed any of the various nag toasts to setup encryption on this device?
|
||||
private dismissedThisDeviceToast = false;
|
||||
// cache of the key backup info
|
||||
private keyBackupInfo: object = null;
|
||||
private keyBackupInfo: IKeyBackupInfo | null = null;
|
||||
private keyBackupFetchedAt: number = null;
|
||||
private keyBackupStatusChecked = false;
|
||||
// We keep a list of our own device IDs so we can batch ones that were already
|
||||
@ -70,12 +71,12 @@ export default class DeviceListener {
|
||||
private enableBulkUnverifiedSessionsReminder = true;
|
||||
private deviceClientInformationSettingWatcherRef: string | undefined;
|
||||
|
||||
public static sharedInstance() {
|
||||
public static sharedInstance(): DeviceListener {
|
||||
if (!window.mxDeviceListener) window.mxDeviceListener = new DeviceListener();
|
||||
return window.mxDeviceListener;
|
||||
}
|
||||
|
||||
public start() {
|
||||
public start(): void {
|
||||
this.running = true;
|
||||
MatrixClientPeg.get().on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
|
||||
MatrixClientPeg.get().on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
|
||||
@ -98,7 +99,7 @@ export default class DeviceListener {
|
||||
this.updateClientInformation();
|
||||
}
|
||||
|
||||
public stop() {
|
||||
public stop(): void {
|
||||
this.running = false;
|
||||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
|
||||
@ -134,7 +135,7 @@ export default class DeviceListener {
|
||||
*
|
||||
* @param {String[]} deviceIds List of device IDs to dismiss notifications for
|
||||
*/
|
||||
public async dismissUnverifiedSessions(deviceIds: Iterable<string>) {
|
||||
public async dismissUnverifiedSessions(deviceIds: Iterable<string>): Promise<void> {
|
||||
logger.log("Dismissing unverified sessions: " + Array.from(deviceIds).join(","));
|
||||
for (const d of deviceIds) {
|
||||
this.dismissed.add(d);
|
||||
@ -143,19 +144,19 @@ export default class DeviceListener {
|
||||
this.recheck();
|
||||
}
|
||||
|
||||
public dismissEncryptionSetup() {
|
||||
public dismissEncryptionSetup(): void {
|
||||
this.dismissedThisDeviceToast = true;
|
||||
this.recheck();
|
||||
}
|
||||
|
||||
private ensureDeviceIdsAtStartPopulated() {
|
||||
private ensureDeviceIdsAtStartPopulated(): void {
|
||||
if (this.ourDeviceIdsAtStart === null) {
|
||||
const cli = MatrixClientPeg.get();
|
||||
this.ourDeviceIdsAtStart = new Set(cli.getStoredDevicesForUser(cli.getUserId()).map((d) => d.deviceId));
|
||||
}
|
||||
}
|
||||
|
||||
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => {
|
||||
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => {
|
||||
// If we didn't know about *any* devices before (ie. it's fresh login),
|
||||
// then they are all pre-existing devices, so ignore this and set the
|
||||
// devicesAtStart list to the devices that we see after the fetch.
|
||||
@ -168,26 +169,26 @@ export default class DeviceListener {
|
||||
// before we download any new ones.
|
||||
};
|
||||
|
||||
private onDevicesUpdated = (users: string[]) => {
|
||||
private onDevicesUpdated = (users: string[]): void => {
|
||||
if (!users.includes(MatrixClientPeg.get().getUserId())) return;
|
||||
this.recheck();
|
||||
};
|
||||
|
||||
private onDeviceVerificationChanged = (userId: string) => {
|
||||
private onDeviceVerificationChanged = (userId: string): void => {
|
||||
if (userId !== MatrixClientPeg.get().getUserId()) return;
|
||||
this.recheck();
|
||||
};
|
||||
|
||||
private onUserTrustStatusChanged = (userId: string) => {
|
||||
private onUserTrustStatusChanged = (userId: string): void => {
|
||||
if (userId !== MatrixClientPeg.get().getUserId()) return;
|
||||
this.recheck();
|
||||
};
|
||||
|
||||
private onCrossSingingKeysChanged = () => {
|
||||
private onCrossSingingKeysChanged = (): void => {
|
||||
this.recheck();
|
||||
};
|
||||
|
||||
private onAccountData = (ev: MatrixEvent) => {
|
||||
private onAccountData = (ev: MatrixEvent): void => {
|
||||
// User may have:
|
||||
// * migrated SSSS to symmetric
|
||||
// * uploaded keys to secret storage
|
||||
@ -202,13 +203,13 @@ export default class DeviceListener {
|
||||
}
|
||||
};
|
||||
|
||||
private onSync = (state: SyncState, prevState?: SyncState) => {
|
||||
private onSync = (state: SyncState, prevState?: SyncState): void => {
|
||||
if (state === "PREPARED" && prevState === null) {
|
||||
this.recheck();
|
||||
}
|
||||
};
|
||||
|
||||
private onRoomStateEvents = (ev: MatrixEvent) => {
|
||||
private onRoomStateEvents = (ev: MatrixEvent): void => {
|
||||
if (ev.getType() !== EventType.RoomEncryption) return;
|
||||
|
||||
// If a room changes to encrypted, re-check as it may be our first
|
||||
@ -216,7 +217,7 @@ export default class DeviceListener {
|
||||
this.recheck();
|
||||
};
|
||||
|
||||
private onAction = ({ action }: ActionPayload) => {
|
||||
private onAction = ({ action }: ActionPayload): void => {
|
||||
if (action !== Action.OnLoggedIn) return;
|
||||
this.recheck();
|
||||
this.updateClientInformation();
|
||||
@ -224,7 +225,7 @@ export default class DeviceListener {
|
||||
|
||||
// The server doesn't tell us when key backup is set up, so we poll
|
||||
// & cache the result
|
||||
private async getKeyBackupInfo() {
|
||||
private async getKeyBackupInfo(): Promise<IKeyBackupInfo> {
|
||||
const now = new Date().getTime();
|
||||
if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) {
|
||||
this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||
@ -233,7 +234,7 @@ export default class DeviceListener {
|
||||
return this.keyBackupInfo;
|
||||
}
|
||||
|
||||
private shouldShowSetupEncryptionToast() {
|
||||
private shouldShowSetupEncryptionToast(): boolean {
|
||||
// If we're in the middle of a secret storage operation, we're likely
|
||||
// modifying the state involved here, so don't add new toasts to setup.
|
||||
if (isSecretStorageBeingAccessed()) return false;
|
||||
@ -242,7 +243,7 @@ export default class DeviceListener {
|
||||
return cli && cli.getRooms().some((r) => cli.isRoomEncrypted(r.roomId));
|
||||
}
|
||||
|
||||
private async recheck() {
|
||||
private async recheck(): Promise<void> {
|
||||
if (!this.running) return; // we have been stopped
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
||||
@ -359,7 +360,7 @@ export default class DeviceListener {
|
||||
this.displayingToastsForDeviceIds = newUnverifiedDeviceIds;
|
||||
}
|
||||
|
||||
private checkKeyBackupStatus = async () => {
|
||||
private checkKeyBackupStatus = async (): Promise<void> => {
|
||||
if (this.keyBackupStatusChecked) {
|
||||
return;
|
||||
}
|
||||
@ -388,7 +389,7 @@ export default class DeviceListener {
|
||||
}
|
||||
};
|
||||
|
||||
private updateClientInformation = async () => {
|
||||
private updateClientInformation = async (): Promise<void> => {
|
||||
try {
|
||||
if (this.shouldRecordClientInformation) {
|
||||
await recordClientInformation(MatrixClientPeg.get(), SdkConfig.get(), PlatformPeg.get());
|
||||
|
@ -16,5 +16,6 @@ limitations under the License.
|
||||
|
||||
import { TimelineRenderingType } from "./contexts/RoomContext";
|
||||
|
||||
export const editorRoomKey = (roomId: string, context: TimelineRenderingType) => `mx_edit_room_${roomId}_${context}`;
|
||||
export const editorStateKey = (eventId: string) => `mx_edit_state_${eventId}`;
|
||||
export const editorRoomKey = (roomId: string, context: TimelineRenderingType): string =>
|
||||
`mx_edit_room_${roomId}_${context}`;
|
||||
export const editorStateKey = (eventId: string): string => `mx_edit_state_${eventId}`;
|
||||
|
@ -449,9 +449,9 @@ export interface IOptsReturnString extends IOpts {
|
||||
returnString: true;
|
||||
}
|
||||
|
||||
const emojiToHtmlSpan = (emoji: string) =>
|
||||
const emojiToHtmlSpan = (emoji: string): string =>
|
||||
`<span class='mx_Emoji' title='${unicodeToShortcode(emoji)}'>${emoji}</span>`;
|
||||
const emojiToJsxSpan = (emoji: string, key: number) => (
|
||||
const emojiToJsxSpan = (emoji: string, key: number): JSX.Element => (
|
||||
<span key={key} className="mx_Emoji" title={unicodeToShortcode(emoji)}>
|
||||
{emoji}
|
||||
</span>
|
||||
@ -505,7 +505,7 @@ function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | s
|
||||
*/
|
||||
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnString): string;
|
||||
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnNode): ReactNode;
|
||||
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}) {
|
||||
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}): ReactNode | string {
|
||||
const isFormattedBody = content.format === "org.matrix.custom.html" && !!content.formatted_body;
|
||||
let bodyHasEmoji = false;
|
||||
let isHtmlMessage = false;
|
||||
|
@ -28,7 +28,7 @@ limitations under the License.
|
||||
* consume in the timeline, when performing scroll offset calculations
|
||||
* (e.g. scroll locking)
|
||||
*/
|
||||
export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number) {
|
||||
export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number): number {
|
||||
if (!fullWidth || !fullHeight) {
|
||||
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
||||
// log this because it's spammy
|
||||
|
@ -76,7 +76,7 @@ export const Key = {
|
||||
|
||||
export const IS_MAC = navigator.platform.toUpperCase().includes("MAC");
|
||||
|
||||
export function isOnlyCtrlOrCmdKeyEvent(ev) {
|
||||
export function isOnlyCtrlOrCmdKeyEvent(ev: KeyboardEvent): boolean {
|
||||
if (IS_MAC) {
|
||||
return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
|
||||
} else {
|
||||
|
@ -169,7 +169,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||
|
||||
private silencedCalls = new Set<string>(); // callIds
|
||||
|
||||
public static get instance() {
|
||||
public static get instance(): LegacyCallHandler {
|
||||
if (!window.mxLegacyCallHandler) {
|
||||
window.mxLegacyCallHandler = new LegacyCallHandler();
|
||||
}
|
||||
@ -456,7 +456,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||
return callsNotInThatRoom;
|
||||
}
|
||||
|
||||
public getAllActiveCallsForPip(roomId: string) {
|
||||
public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
|
||||
// This checks if there is space for the call view in the aux panel
|
||||
@ -478,7 +478,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||
const audio = document.getElementById(audioId) as HTMLMediaElement;
|
||||
if (audio) {
|
||||
this.addEventListenersForAudioElement(audio);
|
||||
const playAudio = async () => {
|
||||
const playAudio = async (): Promise<void> => {
|
||||
try {
|
||||
if (audio.muted) {
|
||||
logger.error(
|
||||
@ -524,7 +524,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||
// TODO: Attach an invisible element for this instead
|
||||
// which listens?
|
||||
const audio = document.getElementById(audioId) as HTMLMediaElement;
|
||||
const pauseAudio = () => {
|
||||
const pauseAudio = (): void => {
|
||||
logger.debug(`${logPrefix} pausing audio`);
|
||||
// pause doesn't return a promise, so just do it
|
||||
audio.pause();
|
||||
@ -600,7 +600,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||
this.setCallListeners(newCall);
|
||||
this.setCallState(newCall, newCall.state);
|
||||
});
|
||||
call.on(CallEvent.AssertedIdentityChanged, async () => {
|
||||
call.on(CallEvent.AssertedIdentityChanged, async (): Promise<void> => {
|
||||
if (!this.matchesCallForThisRoom(call)) return;
|
||||
|
||||
logger.log(`Call ID ${call.callId} got new asserted identity:`, call.getRemoteAssertedIdentity());
|
||||
@ -808,7 +808,7 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||
|
||||
private showICEFallbackPrompt(): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const code = (sub) => <code>{sub}</code>;
|
||||
const code = (sub: string): JSX.Element => <code>{sub}</code>;
|
||||
Modal.createDialog(
|
||||
QuestionDialog,
|
||||
{
|
||||
|
@ -219,7 +219,7 @@ export function attemptTokenLogin(
|
||||
})
|
||||
.then(function (creds) {
|
||||
logger.log("Logged in with token");
|
||||
return clearStorage().then(async () => {
|
||||
return clearStorage().then(async (): Promise<boolean> => {
|
||||
await persistCredentials(creds);
|
||||
// remember that we just logged in
|
||||
sessionStorage.setItem("mx_fresh_login", String(true));
|
||||
@ -406,7 +406,7 @@ async function pickleKeyToAesKey(pickleKey: string): Promise<Uint8Array> {
|
||||
);
|
||||
}
|
||||
|
||||
async function abortLogin() {
|
||||
async function abortLogin(): Promise<void> {
|
||||
const signOut = await showStorageEvictedDialog();
|
||||
if (signOut) {
|
||||
await clearStorage();
|
||||
|
@ -20,14 +20,14 @@ import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
|
||||
|
||||
export function getConfigLivestreamUrl() {
|
||||
export function getConfigLivestreamUrl(): string | undefined {
|
||||
return SdkConfig.get("audio_stream_url");
|
||||
}
|
||||
|
||||
// Dummy rtmp URL used to signal that we want a special audio-only stream
|
||||
const AUDIOSTREAM_DUMMY_URL = "rtmp://audiostream.dummy/";
|
||||
|
||||
async function createLiveStream(roomId: string) {
|
||||
async function createLiveStream(roomId: string): Promise<void> {
|
||||
const openIdToken = await MatrixClientPeg.get().getOpenIdToken();
|
||||
|
||||
const url = getConfigLivestreamUrl() + "/createStream";
|
||||
@ -47,7 +47,7 @@ async function createLiveStream(roomId: string) {
|
||||
return respBody["stream_id"];
|
||||
}
|
||||
|
||||
export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string) {
|
||||
export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string): Promise<void> {
|
||||
const streamId = await createLiveStream(roomId);
|
||||
|
||||
await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, {
|
||||
|
@ -122,7 +122,7 @@ export default class Login {
|
||||
initial_device_display_name: this.defaultDeviceDisplayName,
|
||||
};
|
||||
|
||||
const tryFallbackHs = (originalError) => {
|
||||
const tryFallbackHs = (originalError: Error): Promise<IMatrixClientCreds> => {
|
||||
return sendLoginRequest(this.fallbackHsUrl, this.isUrl, "m.login.password", loginParams).catch(
|
||||
(fallbackError) => {
|
||||
logger.log("fallback HS login failed", fallbackError);
|
||||
|
@ -56,7 +56,7 @@ function isMultiLine(node: commonmark.Node): boolean {
|
||||
return par.firstChild != par.lastChild;
|
||||
}
|
||||
|
||||
function getTextUntilEndOrLinebreak(node: commonmark.Node) {
|
||||
function getTextUntilEndOrLinebreak(node: commonmark.Node): string {
|
||||
let currentNode = node;
|
||||
let text = "";
|
||||
while (currentNode !== null && currentNode.type !== "softbreak" && currentNode.type !== "linebreak") {
|
||||
@ -137,7 +137,7 @@ export default class Markdown {
|
||||
* See: https://github.com/vector-im/element-web/issues/4674
|
||||
* @param parsed
|
||||
*/
|
||||
private repairLinks(parsed: commonmark.Node) {
|
||||
private repairLinks(parsed: commonmark.Node): commonmark.Node {
|
||||
const walker = parsed.walker();
|
||||
let event: commonmark.NodeWalkingStep = null;
|
||||
let text = "";
|
||||
|
@ -77,7 +77,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
// Neither the static nor priority modal will be in this list.
|
||||
private modals: IModal<any>[] = [];
|
||||
|
||||
private static getOrCreateContainer() {
|
||||
private static getOrCreateContainer(): HTMLElement {
|
||||
let container = document.getElementById(DIALOG_CONTAINER_ID);
|
||||
|
||||
if (!container) {
|
||||
@ -89,7 +89,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
return container;
|
||||
}
|
||||
|
||||
private static getOrCreateStaticContainer() {
|
||||
private static getOrCreateStaticContainer(): HTMLElement {
|
||||
let container = document.getElementById(STATIC_DIALOG_CONTAINER_ID);
|
||||
|
||||
if (!container) {
|
||||
@ -101,31 +101,31 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
return container;
|
||||
}
|
||||
|
||||
public toggleCurrentDialogVisibility() {
|
||||
public toggleCurrentDialogVisibility(): void {
|
||||
const modal = this.getCurrentModal();
|
||||
if (!modal) return;
|
||||
modal.hidden = !modal.hidden;
|
||||
}
|
||||
|
||||
public hasDialogs() {
|
||||
return this.priorityModal || this.staticModal || this.modals.length > 0;
|
||||
public hasDialogs(): boolean {
|
||||
return !!this.priorityModal || !!this.staticModal || this.modals.length > 0;
|
||||
}
|
||||
|
||||
public createDialog<T extends any[]>(
|
||||
Element: React.ComponentType<any>,
|
||||
...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]>
|
||||
) {
|
||||
): IHandle<T> {
|
||||
return this.createDialogAsync<T>(Promise.resolve(Element), ...rest);
|
||||
}
|
||||
|
||||
public appendDialog<T extends any[]>(
|
||||
Element: React.ComponentType,
|
||||
...rest: ParametersWithoutFirst<ModalManager["appendDialogAsync"]>
|
||||
) {
|
||||
): IHandle<T> {
|
||||
return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest);
|
||||
}
|
||||
|
||||
public closeCurrentModal(reason: string) {
|
||||
public closeCurrentModal(reason: string): void {
|
||||
const modal = this.getCurrentModal();
|
||||
if (!modal) {
|
||||
return;
|
||||
@ -139,7 +139,11 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
props?: IProps<T>,
|
||||
className?: string,
|
||||
options?: IOptions<T>,
|
||||
) {
|
||||
): {
|
||||
modal: IModal<T>;
|
||||
closeDialog: IHandle<T>["close"];
|
||||
onFinishedProm: IHandle<T>["finished"];
|
||||
} {
|
||||
const modal: IModal<T> = {
|
||||
onFinished: props ? props.onFinished : null,
|
||||
onBeforeClose: options.onBeforeClose,
|
||||
@ -173,7 +177,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
): [IHandle<T>["close"], IHandle<T>["finished"]] {
|
||||
const deferred = defer<T>();
|
||||
return [
|
||||
async (...args: T) => {
|
||||
async (...args: T): Promise<void> => {
|
||||
if (modal.beforeClosePromise) {
|
||||
await modal.beforeClosePromise;
|
||||
} else if (modal.onBeforeClose) {
|
||||
@ -302,7 +306,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
}
|
||||
}
|
||||
|
||||
private onBackgroundClick = () => {
|
||||
private onBackgroundClick = (): void => {
|
||||
const modal = this.getCurrentModal();
|
||||
if (!modal) {
|
||||
return;
|
||||
@ -320,7 +324,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
return this.priorityModal ? this.priorityModal : this.modals[0] || this.staticModal;
|
||||
}
|
||||
|
||||
private async reRender() {
|
||||
private async reRender(): Promise<void> {
|
||||
// await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around
|
||||
await sleep(0);
|
||||
|
||||
|
@ -32,13 +32,13 @@ import { PlatformSetPayload } from "./dispatcher/payloads/PlatformSetPayload";
|
||||
* object.
|
||||
*/
|
||||
export class PlatformPeg {
|
||||
private platform: BasePlatform = null;
|
||||
private platform: BasePlatform | null = null;
|
||||
|
||||
/**
|
||||
* Returns the current Platform object for the application.
|
||||
* This should be an instance of a class extending BasePlatform.
|
||||
*/
|
||||
public get() {
|
||||
public get(): BasePlatform | null {
|
||||
return this.platform;
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ export class PlatformPeg {
|
||||
* Sets the current platform handler object to use for the application.
|
||||
* @param {BasePlatform} platform an instance of a class extending BasePlatform.
|
||||
*/
|
||||
public set(platform: BasePlatform) {
|
||||
public set(platform: BasePlatform): void {
|
||||
this.platform = platform;
|
||||
defaultDispatcher.dispatch<PlatformSetPayload>({
|
||||
action: Action.PlatformSet,
|
||||
|
@ -175,7 +175,7 @@ export class PosthogAnalytics {
|
||||
this.onLayoutUpdated();
|
||||
}
|
||||
|
||||
private onLayoutUpdated = () => {
|
||||
private onLayoutUpdated = (): void => {
|
||||
let layout: UserProperties["WebLayout"];
|
||||
|
||||
switch (SettingsStore.getValue("layout")) {
|
||||
@ -195,7 +195,7 @@ export class PosthogAnalytics {
|
||||
this.setProperty("WebLayout", layout);
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (payload.action !== Action.SettingUpdated) return;
|
||||
const settingsPayload = payload as SettingUpdatedPayload;
|
||||
if (["layout", "useCompactLayout"].includes(settingsPayload.settingName)) {
|
||||
@ -232,7 +232,7 @@ export class PosthogAnalytics {
|
||||
return properties;
|
||||
};
|
||||
|
||||
private registerSuperProperties(properties: Properties) {
|
||||
private registerSuperProperties(properties: Properties): void {
|
||||
if (this.enabled) {
|
||||
this.posthog.register(properties);
|
||||
}
|
||||
@ -255,7 +255,7 @@ export class PosthogAnalytics {
|
||||
}
|
||||
|
||||
// eslint-disable-nextline no-unused-varsx
|
||||
private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions) {
|
||||
private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions): void {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -107,20 +107,20 @@ export default class PosthogTrackers {
|
||||
}
|
||||
|
||||
export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> {
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
PosthogTrackers.instance.trackOverride(this.props.screenName);
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
public componentDidUpdate(): void {
|
||||
// We do not clear the old override here so that we do not send the non-override screen as a transition
|
||||
PosthogTrackers.instance.trackOverride(this.props.screenName);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
PosthogTrackers.instance.clearOverride(this.props.screenName);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
return null; // no need to render anything, we just need to hook into the React lifecycle
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class Presence {
|
||||
* Start listening the user activity to evaluate his presence state.
|
||||
* Any state change will be sent to the homeserver.
|
||||
*/
|
||||
public async start() {
|
||||
public async start(): Promise<void> {
|
||||
this.unavailableTimer = new Timer(UNAVAILABLE_TIME_MS);
|
||||
// the user_activity_start action starts the timer
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
@ -58,7 +58,7 @@ class Presence {
|
||||
/**
|
||||
* Stop tracking user activity
|
||||
*/
|
||||
public stop() {
|
||||
public stop(): void {
|
||||
if (this.dispatcherRef) {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
this.dispatcherRef = null;
|
||||
@ -73,11 +73,11 @@ class Presence {
|
||||
* Get the current presence state.
|
||||
* @returns {string} the presence state (see PRESENCE enum)
|
||||
*/
|
||||
public getState() {
|
||||
public getState(): State {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (payload.action === "user_activity") {
|
||||
this.setState(State.Online);
|
||||
this.unavailableTimer.restart();
|
||||
@ -89,7 +89,7 @@ class Presence {
|
||||
* If the state has changed, the homeserver will be notified.
|
||||
* @param {string} newState the new presence state (see PRESENCE enum)
|
||||
*/
|
||||
private async setState(newState: State) {
|
||||
private async setState(newState: State): Promise<void> {
|
||||
if (newState === this.state) {
|
||||
return;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export default class ScalarAuthClient {
|
||||
this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl;
|
||||
}
|
||||
|
||||
private writeTokenToStore() {
|
||||
private writeTokenToStore(): void {
|
||||
window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken);
|
||||
if (this.isDefaultManager) {
|
||||
// We remove the old token from storage to migrate upwards. This is safe
|
||||
@ -72,7 +72,7 @@ export default class ScalarAuthClient {
|
||||
return this.readTokenFromStore();
|
||||
}
|
||||
|
||||
public setTermsInteractionCallback(callback) {
|
||||
public setTermsInteractionCallback(callback: TermsInteractionCallback): void {
|
||||
this.termsInteractionCallback = callback;
|
||||
}
|
||||
|
||||
|
@ -711,7 +711,7 @@ function returnStateEvent(event: MessageEvent<any>, roomId: string, eventType: s
|
||||
sendResponse(event, stateEvent.getContent());
|
||||
}
|
||||
|
||||
async function getOpenIdToken(event: MessageEvent<any>) {
|
||||
async function getOpenIdToken(event: MessageEvent<any>): Promise<void> {
|
||||
try {
|
||||
const tokenObject = await MatrixClientPeg.get().getOpenIdToken();
|
||||
sendResponse(event, tokenObject);
|
||||
@ -728,7 +728,7 @@ async function sendEvent(
|
||||
content?: IContent;
|
||||
}>,
|
||||
roomId: string,
|
||||
) {
|
||||
): Promise<void> {
|
||||
const eventType = event.data.type;
|
||||
const stateKey = event.data.state_key;
|
||||
const content = event.data.content;
|
||||
@ -786,7 +786,7 @@ async function readEvents(
|
||||
limit?: number;
|
||||
}>,
|
||||
roomId: string,
|
||||
) {
|
||||
): Promise<void> {
|
||||
const eventType = event.data.type;
|
||||
const stateKey = event.data.state_key;
|
||||
const limit = event.data.limit;
|
||||
|
@ -56,7 +56,7 @@ export default class SdkConfig {
|
||||
private static instance: IConfigOptions;
|
||||
private static fallback: SnakedObject<IConfigOptions>;
|
||||
|
||||
private static setInstance(i: IConfigOptions) {
|
||||
private static setInstance(i: IConfigOptions): void {
|
||||
SdkConfig.instance = i;
|
||||
SdkConfig.fallback = new SnakedObject(i);
|
||||
|
||||
@ -90,18 +90,18 @@ export default class SdkConfig {
|
||||
return val === undefined ? undefined : null;
|
||||
}
|
||||
|
||||
public static put(cfg: Partial<IConfigOptions>) {
|
||||
public static put(cfg: Partial<IConfigOptions>): void {
|
||||
SdkConfig.setInstance({ ...DEFAULTS, ...cfg });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the config to be completely empty.
|
||||
*/
|
||||
public static unset() {
|
||||
public static unset(): void {
|
||||
SdkConfig.setInstance(<IConfigOptions>{}); // safe to cast - defaults will be applied
|
||||
}
|
||||
|
||||
public static add(cfg: Partial<IConfigOptions>) {
|
||||
public static add(cfg: Partial<IConfigOptions>): void {
|
||||
SdkConfig.put({ ...SdkConfig.get(), ...cfg });
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ async function confirmToDismiss(): Promise<boolean> {
|
||||
type KeyParams = { passphrase: string; recoveryKey: string };
|
||||
|
||||
function makeInputToKey(keyInfo: ISecretStorageKeyInfo): (keyParams: KeyParams) => Promise<Uint8Array> {
|
||||
return async ({ passphrase, recoveryKey }) => {
|
||||
return async ({ passphrase, recoveryKey }): Promise<Uint8Array> => {
|
||||
if (passphrase) {
|
||||
return deriveKey(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations);
|
||||
} else {
|
||||
@ -151,7 +151,7 @@ async function getSecretStorageKey({
|
||||
/* props= */
|
||||
{
|
||||
keyInfo,
|
||||
checkPrivateKey: async (input: KeyParams) => {
|
||||
checkPrivateKey: async (input: KeyParams): Promise<boolean> => {
|
||||
const key = await inputToKey(input);
|
||||
return MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo);
|
||||
},
|
||||
@ -160,7 +160,7 @@ async function getSecretStorageKey({
|
||||
/* isPriorityModal= */ false,
|
||||
/* isStaticModal= */ false,
|
||||
/* options= */ {
|
||||
onBeforeClose: async (reason) => {
|
||||
onBeforeClose: async (reason): Promise<boolean> => {
|
||||
if (reason === "backgroundClick") {
|
||||
return confirmToDismiss();
|
||||
}
|
||||
@ -196,7 +196,7 @@ export async function getDehydrationKey(
|
||||
/* props= */
|
||||
{
|
||||
keyInfo,
|
||||
checkPrivateKey: async (input) => {
|
||||
checkPrivateKey: async (input): Promise<boolean> => {
|
||||
const key = await inputToKey(input);
|
||||
try {
|
||||
checkFunc(key);
|
||||
@ -210,7 +210,7 @@ export async function getDehydrationKey(
|
||||
/* isPriorityModal= */ false,
|
||||
/* isStaticModal= */ false,
|
||||
/* options= */ {
|
||||
onBeforeClose: async (reason) => {
|
||||
onBeforeClose: async (reason): Promise<boolean> => {
|
||||
if (reason === "backgroundClick") {
|
||||
return confirmToDismiss();
|
||||
}
|
||||
@ -324,7 +324,7 @@ export async function promptForBackupPassphrase(): Promise<Uint8Array> {
|
||||
* bootstrapped. Optional.
|
||||
* @param {bool} [forceReset] Reset secret storage even if it's already set up
|
||||
*/
|
||||
export async function accessSecretStorage(func = async () => {}, forceReset = false) {
|
||||
export async function accessSecretStorage(func = async (): Promise<void> => {}, forceReset = false): Promise<void> {
|
||||
const cli = MatrixClientPeg.get();
|
||||
secretStorageBeingAccessed = true;
|
||||
try {
|
||||
@ -342,7 +342,7 @@ export async function accessSecretStorage(func = async () => {}, forceReset = fa
|
||||
/* priority = */ false,
|
||||
/* static = */ true,
|
||||
/* options = */ {
|
||||
onBeforeClose: async (reason) => {
|
||||
onBeforeClose: async (reason): Promise<boolean> => {
|
||||
// If Secure Backup is required, you cannot leave the modal.
|
||||
if (reason === "backgroundClick") {
|
||||
return !isSecureBackupRequired();
|
||||
@ -357,7 +357,7 @@ export async function accessSecretStorage(func = async () => {}, forceReset = fa
|
||||
}
|
||||
} else {
|
||||
await cli.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async (makeRequest) => {
|
||||
authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => {
|
||||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||
title: _t("Setting up keys"),
|
||||
matrixClient: cli,
|
||||
|
@ -60,7 +60,7 @@ export default class SendHistoryManager {
|
||||
};
|
||||
}
|
||||
|
||||
public save(editorModel: EditorModel, replyEvent?: MatrixEvent) {
|
||||
public save(editorModel: EditorModel, replyEvent?: MatrixEvent): void {
|
||||
const item = SendHistoryManager.createItem(editorModel, replyEvent);
|
||||
this.history.push(item);
|
||||
this.currentIndex = this.history.length;
|
||||
|
@ -85,7 +85,7 @@ const singleMxcUpload = async (): Promise<string | null> => {
|
||||
|
||||
Modal.createDialog(UploadConfirmDialog, {
|
||||
file,
|
||||
onFinished: async (shouldContinue) => {
|
||||
onFinished: async (shouldContinue): Promise<void> => {
|
||||
if (shouldContinue) {
|
||||
const { content_uri: uri } = await MatrixClientPeg.get().uploadContent(file);
|
||||
resolve(uri);
|
||||
@ -151,11 +151,11 @@ export class Command {
|
||||
this.analyticsName = opts.analyticsName;
|
||||
}
|
||||
|
||||
public getCommand() {
|
||||
public getCommand(): string {
|
||||
return `/${this.command}`;
|
||||
}
|
||||
|
||||
public getCommandWithArgs() {
|
||||
public getCommandWithArgs(): string {
|
||||
return this.getCommand() + " " + this.args;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ export class Command {
|
||||
return this.runFn(roomId, args);
|
||||
}
|
||||
|
||||
public getUsage() {
|
||||
public getUsage(): string {
|
||||
return _t("Usage") + ": " + this.getCommandWithArgs();
|
||||
}
|
||||
|
||||
@ -193,15 +193,15 @@ export class Command {
|
||||
}
|
||||
}
|
||||
|
||||
function reject(error) {
|
||||
function reject(error?: any): RunResult {
|
||||
return { error };
|
||||
}
|
||||
|
||||
function success(promise?: Promise<any>) {
|
||||
function success(promise?: Promise<any>): RunResult {
|
||||
return { promise };
|
||||
}
|
||||
|
||||
function successSync(value: any) {
|
||||
function successSync(value: any): RunResult {
|
||||
return success(Promise.resolve(value));
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ export const Commands = [
|
||||
);
|
||||
|
||||
return success(
|
||||
finished.then(async ([resp]) => {
|
||||
finished.then(async ([resp]): Promise<void> => {
|
||||
if (!resp?.continue) return;
|
||||
await upgradeRoom(room, args, resp.invite);
|
||||
}),
|
||||
@ -338,7 +338,7 @@ export const Commands = [
|
||||
runFn: function (roomId, args) {
|
||||
if (args) {
|
||||
return success(
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
const unixTimestamp = Date.parse(args);
|
||||
if (!unixTimestamp) {
|
||||
throw newTranslatableError(
|
||||
@ -501,7 +501,9 @@ export const Commands = [
|
||||
? ContentHelpers.parseTopicContent(content)
|
||||
: { text: _t("This room has no topic.") };
|
||||
|
||||
const ref = (e) => e && linkifyElement(e);
|
||||
const ref = (e): void => {
|
||||
if (e) linkifyElement(e);
|
||||
};
|
||||
const body = topicToHtml(topic.text, topic.html, ref, true);
|
||||
|
||||
Modal.createDialog(InfoDialog, {
|
||||
@ -1028,7 +1030,7 @@ export const Commands = [
|
||||
const fingerprint = matches[3];
|
||||
|
||||
return success(
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
const device = cli.getStoredDevice(userId, deviceId);
|
||||
if (!device) {
|
||||
throw newTranslatableError("Unknown (user, session) pair: (%(userId)s, %(deviceId)s)", {
|
||||
@ -1205,7 +1207,7 @@ export const Commands = [
|
||||
},
|
||||
runFn: (roomId) => {
|
||||
return success(
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
const room = await VoipUserMapper.sharedInstance().getVirtualRoomForRoom(roomId);
|
||||
if (!room) throw newTranslatableError("No virtual room for this room");
|
||||
dis.dispatch<ViewRoomPayload>({
|
||||
@ -1231,7 +1233,7 @@ export const Commands = [
|
||||
}
|
||||
|
||||
return success(
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
if (isPhoneNumber) {
|
||||
const results = await LegacyCallHandler.instance.pstnLookup(userId);
|
||||
if (!results || results.length === 0 || !results[0].userid) {
|
||||
@ -1265,7 +1267,7 @@ export const Commands = [
|
||||
const [userId, msg] = matches.slice(1);
|
||||
if (userId && userId.startsWith("@") && userId.includes(":")) {
|
||||
return success(
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const roomId = await ensureDMExists(cli, userId);
|
||||
dis.dispatch<ViewRoomPayload>({
|
||||
|
@ -302,7 +302,7 @@ export class SlidingSyncManager {
|
||||
* @param batchSize The number of rooms to return in each request.
|
||||
* @param gapBetweenRequestsMs The number of milliseconds to wait between requests.
|
||||
*/
|
||||
public async startSpidering(batchSize: number, gapBetweenRequestsMs: number) {
|
||||
public async startSpidering(batchSize: number, gapBetweenRequestsMs: number): Promise<void> {
|
||||
await sleep(gapBetweenRequestsMs); // wait a bit as this is called on first render so let's let things load
|
||||
const listIndex = this.getOrAllocateListIndex(SlidingSyncManager.ListSearch);
|
||||
let startIndex = batchSize;
|
||||
|
@ -75,7 +75,7 @@ export type TermsInteractionCallback = (
|
||||
export async function startTermsFlow(
|
||||
services: Service[],
|
||||
interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback,
|
||||
) {
|
||||
): Promise<void> {
|
||||
const termsPromises = services.map((s) => MatrixClientPeg.get().getTerms(s.serviceType, s.baseUrl));
|
||||
|
||||
/*
|
||||
@ -176,7 +176,7 @@ export async function startTermsFlow(
|
||||
urlsForService,
|
||||
);
|
||||
});
|
||||
return Promise.all(agreePromises);
|
||||
await Promise.all(agreePromises);
|
||||
}
|
||||
|
||||
export async function dialogTermsInteractionCallback(
|
||||
|
@ -228,7 +228,7 @@ function textForTombstoneEvent(ev: MatrixEvent): () => string | null {
|
||||
return () => _t("%(senderDisplayName)s upgraded this room.", { senderDisplayName });
|
||||
}
|
||||
|
||||
const onViewJoinRuleSettingsClick = () => {
|
||||
const onViewJoinRuleSettingsClick = (): void => {
|
||||
defaultDispatcher.dispatch({
|
||||
action: "open_room_settings",
|
||||
initial_tab_id: ROOM_SECURITY_TAB,
|
||||
|
@ -50,7 +50,7 @@ export default class UserActivity {
|
||||
this.activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS);
|
||||
}
|
||||
|
||||
public static sharedInstance() {
|
||||
public static sharedInstance(): UserActivity {
|
||||
if (window.mxUserActivity === undefined) {
|
||||
window.mxUserActivity = new UserActivity(window, document);
|
||||
}
|
||||
@ -66,7 +66,7 @@ export default class UserActivity {
|
||||
* later on when the user does become active.
|
||||
* @param {Timer} timer the timer to use
|
||||
*/
|
||||
public timeWhileActiveNow(timer: Timer) {
|
||||
public timeWhileActiveNow(timer: Timer): void {
|
||||
this.timeWhile(timer, this.attachedActiveNowTimers);
|
||||
if (this.userActiveNow()) {
|
||||
timer.start();
|
||||
@ -82,14 +82,14 @@ export default class UserActivity {
|
||||
* later on when the user does become active.
|
||||
* @param {Timer} timer the timer to use
|
||||
*/
|
||||
public timeWhileActiveRecently(timer: Timer) {
|
||||
public timeWhileActiveRecently(timer: Timer): void {
|
||||
this.timeWhile(timer, this.attachedActiveRecentlyTimers);
|
||||
if (this.userActiveRecently()) {
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
private timeWhile(timer: Timer, attachedTimers: Timer[]) {
|
||||
private timeWhile(timer: Timer, attachedTimers: Timer[]): void {
|
||||
// important this happens first
|
||||
const index = attachedTimers.indexOf(timer);
|
||||
if (index === -1) {
|
||||
@ -113,7 +113,7 @@ export default class UserActivity {
|
||||
/**
|
||||
* Start listening to user activity
|
||||
*/
|
||||
public start() {
|
||||
public start(): void {
|
||||
this.document.addEventListener("mousedown", this.onUserActivity);
|
||||
this.document.addEventListener("mousemove", this.onUserActivity);
|
||||
this.document.addEventListener("keydown", this.onUserActivity);
|
||||
@ -133,7 +133,7 @@ export default class UserActivity {
|
||||
/**
|
||||
* Stop tracking user activity
|
||||
*/
|
||||
public stop() {
|
||||
public stop(): void {
|
||||
this.document.removeEventListener("mousedown", this.onUserActivity);
|
||||
this.document.removeEventListener("mousemove", this.onUserActivity);
|
||||
this.document.removeEventListener("keydown", this.onUserActivity);
|
||||
@ -152,7 +152,7 @@ export default class UserActivity {
|
||||
* user's attention at any given moment.
|
||||
* @returns {boolean} true if user is currently 'active'
|
||||
*/
|
||||
public userActiveNow() {
|
||||
public userActiveNow(): boolean {
|
||||
return this.activeNowTimeout.isRunning();
|
||||
}
|
||||
|
||||
@ -164,11 +164,11 @@ export default class UserActivity {
|
||||
* (or they may have gone to make tea and left the window focused).
|
||||
* @returns {boolean} true if user has been active recently
|
||||
*/
|
||||
public userActiveRecently() {
|
||||
public userActiveRecently(): boolean {
|
||||
return this.activeRecentlyTimeout.isRunning();
|
||||
}
|
||||
|
||||
private onPageVisibilityChanged = (e) => {
|
||||
private onPageVisibilityChanged = (e): void => {
|
||||
if (this.document.visibilityState === "hidden") {
|
||||
this.activeNowTimeout.abort();
|
||||
this.activeRecentlyTimeout.abort();
|
||||
@ -177,12 +177,12 @@ export default class UserActivity {
|
||||
}
|
||||
};
|
||||
|
||||
private onWindowBlurred = () => {
|
||||
private onWindowBlurred = (): void => {
|
||||
this.activeNowTimeout.abort();
|
||||
this.activeRecentlyTimeout.abort();
|
||||
};
|
||||
|
||||
private onUserActivity = (event: MouseEvent) => {
|
||||
private onUserActivity = (event: MouseEvent): void => {
|
||||
// ignore anything if the window isn't focused
|
||||
if (!this.document.hasFocus()) return;
|
||||
|
||||
@ -214,7 +214,7 @@ export default class UserActivity {
|
||||
}
|
||||
};
|
||||
|
||||
private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer) {
|
||||
private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer): Promise<void> {
|
||||
attachedTimers.forEach((t) => t.start());
|
||||
try {
|
||||
await timeout.finished();
|
||||
|
@ -87,7 +87,7 @@ interface IAction {
|
||||
};
|
||||
}
|
||||
|
||||
export const reducer = (state: IState, action: IAction) => {
|
||||
export const reducer: Reducer<IState, IAction> = (state: IState, action: IAction) => {
|
||||
switch (action.type) {
|
||||
case Type.Register: {
|
||||
if (!state.activeRef) {
|
||||
|
@ -26,7 +26,7 @@ interface IProps extends Omit<React.HTMLProps<HTMLDivElement>, "onKeyDown"> {}
|
||||
// https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar
|
||||
// All buttons passed in children must use RovingTabIndex to set `onFocus`, `isActive`, `ref`
|
||||
const Toolbar: React.FC<IProps> = ({ children, ...props }) => {
|
||||
const onKeyDown = (ev: React.KeyboardEvent) => {
|
||||
const onKeyDown = (ev: React.KeyboardEvent): void => {
|
||||
const target = ev.target as HTMLElement;
|
||||
// Don't interfere with input default keydown behaviour
|
||||
if (target.tagName === "INPUT") return;
|
||||
|
@ -33,7 +33,7 @@ interface IProps extends React.ComponentProps<typeof StyledCheckbox> {
|
||||
export const StyledMenuItemCheckbox: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => {
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>();
|
||||
|
||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||
const onKeyDown = (e: React.KeyboardEvent): void => {
|
||||
let handled = true;
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
|
||||
@ -55,7 +55,7 @@ export const StyledMenuItemCheckbox: React.FC<IProps> = ({ children, label, onCh
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
const onKeyUp = (e: React.KeyboardEvent) => {
|
||||
const onKeyUp = (e: React.KeyboardEvent): void => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Space:
|
||||
|
@ -33,7 +33,7 @@ interface IProps extends React.ComponentProps<typeof StyledRadioButton> {
|
||||
export const StyledMenuItemRadio: React.FC<IProps> = ({ children, label, onChange, onClose, ...props }) => {
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLInputElement>();
|
||||
|
||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||
const onKeyDown = (e: React.KeyboardEvent): void => {
|
||||
let handled = true;
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
|
||||
@ -55,7 +55,7 @@ export const StyledMenuItemRadio: React.FC<IProps> = ({ children, label, onChang
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
const onKeyUp = (e: React.KeyboardEvent) => {
|
||||
const onKeyUp = (e: React.KeyboardEvent): void => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { AsyncActionPayload } from "../dispatcher/payloads";
|
||||
import { AsyncActionFn, AsyncActionPayload } from "../dispatcher/payloads";
|
||||
|
||||
/**
|
||||
* Create an action thunk that will dispatch actions indicating the current
|
||||
@ -45,7 +45,7 @@ import { AsyncActionPayload } from "../dispatcher/payloads";
|
||||
* `fn`.
|
||||
*/
|
||||
export function asyncAction(id: string, fn: () => Promise<any>, pendingFn: () => any | null): AsyncActionPayload {
|
||||
const helper = (dispatch) => {
|
||||
const helper: AsyncActionFn = (dispatch) => {
|
||||
dispatch({
|
||||
action: id + ".pending",
|
||||
request: typeof pendingFn === "function" ? pendingFn() : undefined,
|
||||
|
@ -22,7 +22,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||
* Redirect to the correct device manager section
|
||||
* Based on the labs setting
|
||||
*/
|
||||
export const viewUserDeviceSettings = (isNewDeviceManagerEnabled: boolean) => {
|
||||
export const viewUserDeviceSettings = (isNewDeviceManagerEnabled: boolean): void => {
|
||||
defaultDispatcher.dispatch({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: isNewDeviceManagerEnabled ? UserTab.SessionManager : UserTab.Security,
|
||||
|
@ -56,7 +56,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||
};
|
||||
}
|
||||
|
||||
public updateCurrentRoom = async (room) => {
|
||||
public updateCurrentRoom = async (room): Promise<void> => {
|
||||
const eventIndex = EventIndexPeg.get();
|
||||
let stats;
|
||||
|
||||
@ -131,17 +131,17 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||
});
|
||||
}
|
||||
|
||||
private onDisable = async () => {
|
||||
private onDisable = async (): Promise<void> => {
|
||||
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
|
||||
Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true);
|
||||
};
|
||||
|
||||
private onCrawlerSleepTimeChange = (e) => {
|
||||
private onCrawlerSleepTimeChange = (e): void => {
|
||||
this.setState({ crawlerSleepTime: e.target.value });
|
||||
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const brand = SdkConfig.get().brand;
|
||||
|
||||
let crawlerState;
|
||||
|
@ -125,7 +125,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
|
||||
let info;
|
||||
try {
|
||||
if (secureSecretStorage) {
|
||||
await accessSecretStorage(async () => {
|
||||
await accessSecretStorage(async (): Promise<void> => {
|
||||
info = await MatrixClientPeg.get().prepareKeyBackupVersion(null /* random key */, {
|
||||
secureSecretStorage: true,
|
||||
});
|
||||
|
@ -350,7 +350,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
createSecretStorageKey: async () => this.recoveryKey,
|
||||
keyBackupInfo: this.state.backupInfo,
|
||||
setupNewKeyBackup: !this.state.backupInfo,
|
||||
getKeyBackupPassphrase: async () => {
|
||||
getKeyBackupPassphrase: async (): Promise<Uint8Array> => {
|
||||
// We may already have the backup key if we earlier went
|
||||
// through the restore backup path, so pass it along
|
||||
// rather than prompting again.
|
||||
@ -383,7 +383,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
private restoreBackup = async (): Promise<void> => {
|
||||
// It's possible we'll need the backup key later on for bootstrapping,
|
||||
// so let's stash it here, rather than prompting for it twice.
|
||||
const keyCallback = (k) => (this.backupKey = k);
|
||||
const keyCallback = (k: Uint8Array): void => {
|
||||
this.backupKey = k;
|
||||
};
|
||||
|
||||
const { finished } = Modal.createDialog(
|
||||
RestoreKeyBackupDialog,
|
||||
@ -420,7 +422,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
this.setState({ phase: Phase.ChooseKeyPassphrase });
|
||||
};
|
||||
|
||||
private onPassPhraseNextClick = async (e: React.FormEvent) => {
|
||||
private onPassPhraseNextClick = async (e: React.FormEvent): Promise<void> => {
|
||||
e.preventDefault();
|
||||
if (!this.passphraseField.current) return; // unmounting
|
||||
|
||||
@ -434,7 +436,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
this.setState({ phase: Phase.PassphraseConfirm });
|
||||
};
|
||||
|
||||
private onPassPhraseConfirmNextClick = async (e: React.FormEvent) => {
|
||||
private onPassPhraseConfirmNextClick = async (e: React.FormEvent): Promise<void> => {
|
||||
e.preventDefault();
|
||||
|
||||
if (this.state.passPhrase !== this.state.passPhraseConfirm) return;
|
||||
|
@ -121,7 +121,7 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
|
||||
return false;
|
||||
};
|
||||
|
||||
private onPassphraseChange = (ev: React.ChangeEvent<HTMLInputElement>, phrase: AnyPassphrase) => {
|
||||
private onPassphraseChange = (ev: React.ChangeEvent<HTMLInputElement>, phrase: AnyPassphrase): void => {
|
||||
this.setState({
|
||||
[phrase]: ev.target.value,
|
||||
} as Pick<IState, AnyPassphrase>);
|
||||
|
@ -91,7 +91,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
|
||||
return false;
|
||||
};
|
||||
|
||||
private startImport(file: File, passphrase: string) {
|
||||
private startImport(file: File, passphrase: string): Promise<void> {
|
||||
this.setState({
|
||||
errStr: null,
|
||||
phase: Phase.Importing,
|
||||
|
@ -30,7 +30,7 @@ export class ManagedPlayback extends Playback {
|
||||
return super.play();
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
this.manager.destroyPlaybackInstance(this);
|
||||
super.destroy();
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
|
||||
return true; // we don't ever care if the event had listeners, so just return "yes"
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
// Dev note: It's critical that we call stop() during cleanup to ensure that downstream callers
|
||||
// are aware of the final clock position before the user triggered an unload.
|
||||
// noinspection JSIgnoredPromiseFromCall - not concerned about being called async here
|
||||
@ -159,7 +159,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
|
||||
}
|
||||
}
|
||||
|
||||
public async prepare() {
|
||||
public async prepare(): Promise<void> {
|
||||
// don't attempt to decode the media again
|
||||
// AudioContext.decodeAudioData detaches the array buffer `this.buf`
|
||||
// meaning it cannot be re-read
|
||||
@ -190,7 +190,7 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
|
||||
this.context.decodeAudioData(
|
||||
this.buf,
|
||||
(b) => resolve(b),
|
||||
async (e) => {
|
||||
async (e): Promise<void> => {
|
||||
try {
|
||||
// This error handler is largely for Safari as well, which doesn't support Opus/Ogg
|
||||
// very well.
|
||||
@ -232,12 +232,12 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
|
||||
this.emit(PlaybackState.Stopped); // signal that we're not decoding anymore
|
||||
}
|
||||
|
||||
private onPlaybackEnd = async () => {
|
||||
private onPlaybackEnd = async (): Promise<void> => {
|
||||
await this.context.suspend();
|
||||
this.emit(PlaybackState.Stopped);
|
||||
};
|
||||
|
||||
public async play() {
|
||||
public async play(): Promise<void> {
|
||||
// We can't restart a buffer source, so we need to create a new one if we hit the end
|
||||
if (this.state === PlaybackState.Stopped) {
|
||||
this.disconnectSource();
|
||||
@ -256,13 +256,13 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
|
||||
this.emit(PlaybackState.Playing);
|
||||
}
|
||||
|
||||
private disconnectSource() {
|
||||
private disconnectSource(): void {
|
||||
if (this.element) return; // leave connected, we can (and must) re-use it
|
||||
this.source?.disconnect();
|
||||
this.source?.removeEventListener("ended", this.onPlaybackEnd);
|
||||
}
|
||||
|
||||
private makeNewSourceBuffer() {
|
||||
private makeNewSourceBuffer(): void {
|
||||
if (this.element && this.source) return; // leave connected, we can (and must) re-use it
|
||||
|
||||
if (this.element) {
|
||||
@ -276,22 +276,22 @@ export class Playback extends EventEmitter implements IDestroyable, PlaybackInte
|
||||
this.source.connect(this.context.destination);
|
||||
}
|
||||
|
||||
public async pause() {
|
||||
public async pause(): Promise<void> {
|
||||
await this.context.suspend();
|
||||
this.emit(PlaybackState.Paused);
|
||||
}
|
||||
|
||||
public async stop() {
|
||||
public async stop(): Promise<void> {
|
||||
await this.onPlaybackEnd();
|
||||
this.clock.flagStop();
|
||||
}
|
||||
|
||||
public async toggle() {
|
||||
public async toggle(): Promise<void> {
|
||||
if (this.isPlaying) await this.pause();
|
||||
else await this.play();
|
||||
}
|
||||
|
||||
public async skipTo(timeSeconds: number) {
|
||||
public async skipTo(timeSeconds: number): Promise<void> {
|
||||
// Dev note: this function talks a lot about clock desyncs. There is a clock running
|
||||
// independently to the audio context and buffer so that accurate human-perceptible
|
||||
// time can be exposed. The PlaybackClock class has more information, but the short
|
||||
|
@ -89,7 +89,7 @@ export class PlaybackClock implements IDestroyable {
|
||||
return this.observable;
|
||||
}
|
||||
|
||||
private checkTime = (force = false) => {
|
||||
private checkTime = (force = false): void => {
|
||||
const now = this.timeSeconds; // calculated dynamically
|
||||
if (this.lastCheck !== now || force) {
|
||||
this.observable.update([now, this.durationSeconds]);
|
||||
@ -102,7 +102,7 @@ export class PlaybackClock implements IDestroyable {
|
||||
* The placeholders will be overridden once known.
|
||||
* @param {MatrixEvent} event The event to use for placeholders.
|
||||
*/
|
||||
public populatePlaceholdersFrom(event: MatrixEvent) {
|
||||
public populatePlaceholdersFrom(event: MatrixEvent): void {
|
||||
const durationMs = Number(event.getContent()["info"]?.["duration"]);
|
||||
if (Number.isFinite(durationMs)) this.placeholderDuration = durationMs / 1000;
|
||||
}
|
||||
@ -112,11 +112,11 @@ export class PlaybackClock implements IDestroyable {
|
||||
* This is to ensure the clock isn't skewed into thinking it is ~0.5s into
|
||||
* a clip when the duration is set.
|
||||
*/
|
||||
public flagLoadTime() {
|
||||
public flagLoadTime(): void {
|
||||
this.clipStart = this.context.currentTime;
|
||||
}
|
||||
|
||||
public flagStart() {
|
||||
public flagStart(): void {
|
||||
if (this.stopped) {
|
||||
this.clipStart = this.context.currentTime;
|
||||
this.stopped = false;
|
||||
@ -128,7 +128,7 @@ export class PlaybackClock implements IDestroyable {
|
||||
}
|
||||
}
|
||||
|
||||
public flagStop() {
|
||||
public flagStop(): void {
|
||||
this.stopped = true;
|
||||
|
||||
// Reset the clock time now so that the update going out will trigger components
|
||||
@ -136,13 +136,13 @@ export class PlaybackClock implements IDestroyable {
|
||||
this.clipStart = this.context.currentTime;
|
||||
}
|
||||
|
||||
public syncTo(contextTime: number, clipTime: number) {
|
||||
public syncTo(contextTime: number, clipTime: number): void {
|
||||
this.clipStart = contextTime - clipTime;
|
||||
this.stopped = false; // count as a mid-stream pause (if we were stopped)
|
||||
this.checkTime(true);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
this.observable.close();
|
||||
if (this.timerId) clearInterval(this.timerId);
|
||||
}
|
||||
|
@ -38,13 +38,13 @@ export class PlaybackManager {
|
||||
* instances are paused.
|
||||
* @param playback Optional. The playback to leave untouched.
|
||||
*/
|
||||
public pauseAllExcept(playback?: Playback) {
|
||||
public pauseAllExcept(playback?: Playback): void {
|
||||
this.instances
|
||||
.filter((p) => p !== playback && p.currentState === PlaybackState.Playing)
|
||||
.forEach((p) => p.pause());
|
||||
}
|
||||
|
||||
public destroyPlaybackInstance(playback: ManagedPlayback) {
|
||||
public destroyPlaybackInstance(playback: ManagedPlayback): void {
|
||||
this.instances = this.instances.filter((p) => p !== playback);
|
||||
}
|
||||
|
||||
|
@ -75,28 +75,28 @@ export class PlaybackQueue {
|
||||
return queue;
|
||||
}
|
||||
|
||||
private persistClocks() {
|
||||
private persistClocks(): void {
|
||||
localStorage.setItem(
|
||||
`mx_voice_message_clocks_${this.room.roomId}`,
|
||||
JSON.stringify(Array.from(this.clockStates.entries())),
|
||||
);
|
||||
}
|
||||
|
||||
private loadClocks() {
|
||||
private loadClocks(): void {
|
||||
const val = localStorage.getItem(`mx_voice_message_clocks_${this.room.roomId}`);
|
||||
if (!!val) {
|
||||
this.clockStates = new Map<string, number>(JSON.parse(val));
|
||||
}
|
||||
}
|
||||
|
||||
public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback) {
|
||||
public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback): void {
|
||||
// We don't ever detach our listeners: we expect the Playback to clean up for us
|
||||
this.playbacks.set(mxEvent.getId(), playback);
|
||||
playback.on(UPDATE_EVENT, (state) => this.onPlaybackStateChange(playback, mxEvent, state));
|
||||
playback.clockInfo.liveData.onUpdate((clock) => this.onPlaybackClock(playback, mxEvent, clock));
|
||||
}
|
||||
|
||||
private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState) {
|
||||
private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState): void {
|
||||
// Remember where the user got to in playback
|
||||
const wasLastPlaying = this.currentPlaybackId === mxEvent.getId();
|
||||
if (newState === PlaybackState.Stopped && this.clockStates.has(mxEvent.getId()) && !wasLastPlaying) {
|
||||
@ -210,7 +210,7 @@ export class PlaybackQueue {
|
||||
}
|
||||
}
|
||||
|
||||
private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]) {
|
||||
private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]): void {
|
||||
if (playback.currentState === PlaybackState.Decoding) return; // ignore pre-ready values
|
||||
|
||||
if (playback.currentState !== PlaybackState.Stopped) {
|
||||
|
@ -43,7 +43,7 @@ class MxVoiceWorklet extends AudioWorkletProcessor {
|
||||
private nextAmplitudeSecond = 0;
|
||||
private amplitudeIndex = 0;
|
||||
|
||||
public process(inputs, outputs, parameters) {
|
||||
public process(inputs, outputs, parameters): boolean {
|
||||
const currentSecond = roundTimeToTargetFreq(currentTime);
|
||||
// We special case the first ping because there's a fairly good chance that we'll miss the zeroth
|
||||
// update. Firefox for instance takes 0.06 seconds (roughly) to call this function for the first
|
||||
|
@ -141,7 +141,7 @@ export class VoiceMessageRecording implements IDestroyable {
|
||||
this.voiceRecording.destroy();
|
||||
}
|
||||
|
||||
private onDataAvailable = (data: ArrayBuffer) => {
|
||||
private onDataAvailable = (data: ArrayBuffer): void => {
|
||||
const buf = new Uint8Array(data);
|
||||
this.buffer = concat(this.buffer, buf);
|
||||
};
|
||||
@ -153,6 +153,6 @@ export class VoiceMessageRecording implements IDestroyable {
|
||||
}
|
||||
}
|
||||
|
||||
export const createVoiceMessageRecording = (matrixClient: MatrixClient) => {
|
||||
export const createVoiceMessageRecording = (matrixClient: MatrixClient): VoiceMessageRecording => {
|
||||
return new VoiceMessageRecording(matrixClient, new VoiceRecording());
|
||||
};
|
||||
|
@ -110,7 +110,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||
return !MediaDeviceHandler.getAudioNoiseSuppression();
|
||||
}
|
||||
|
||||
private async makeRecorder() {
|
||||
private async makeRecorder(): Promise<void> {
|
||||
try {
|
||||
this.recorderStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
@ -212,14 +212,14 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||
return !!Recorder.isRecordingSupported();
|
||||
}
|
||||
|
||||
private onAudioProcess = (ev: AudioProcessingEvent) => {
|
||||
private onAudioProcess = (ev: AudioProcessingEvent): void => {
|
||||
this.processAudioUpdate(ev.playbackTime);
|
||||
|
||||
// We skip the functionality of the worklet regarding waveform calculations: we
|
||||
// should get that information pretty quick during the playback info.
|
||||
};
|
||||
|
||||
private processAudioUpdate = (timeSeconds: number) => {
|
||||
private processAudioUpdate = (timeSeconds: number): void => {
|
||||
if (!this.recording) return;
|
||||
|
||||
this.observable.update({
|
||||
@ -260,7 +260,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||
/**
|
||||
* {@link https://github.com/chris-rudmin/opus-recorder#instance-fields ref for recorderSeconds}
|
||||
*/
|
||||
public get recorderSeconds() {
|
||||
public get recorderSeconds(): number {
|
||||
return this.recorder.encodedSamplePosition / 48000;
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
return Singleflight.for(this, "stop").do(async () => {
|
||||
return Singleflight.for(this, "stop").do(async (): Promise<void> => {
|
||||
if (!this.recording) {
|
||||
throw new Error("No recording to stop");
|
||||
}
|
||||
@ -307,7 +307,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||
});
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
// noinspection JSIgnoredPromiseFromCall - not concerned about stop() being called async here
|
||||
this.stop();
|
||||
this.removeAllListeners();
|
||||
|
@ -22,7 +22,7 @@ import { TimelineRenderingType } from "../contexts/RoomContext";
|
||||
import type { ICompletion, ISelectionRange } from "./Autocompleter";
|
||||
|
||||
export interface ICommand {
|
||||
command: string | null;
|
||||
command: RegExpExecArray | null;
|
||||
range: {
|
||||
start: number;
|
||||
end: number;
|
||||
@ -59,7 +59,7 @@ export default abstract class AutocompleteProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
// stub
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ export default abstract class AutocompleteProvider {
|
||||
* @param {boolean} force True if the user is forcing completion
|
||||
* @return {object} { command, range } where both objects fields are null if no match
|
||||
*/
|
||||
public getCurrentCommand(query: string, selection: ISelectionRange, force = false) {
|
||||
public getCurrentCommand(query: string, selection: ISelectionRange, force = false): ICommand {
|
||||
let commandRegex = this.commandRegex;
|
||||
|
||||
if (force && this.shouldForceComplete()) {
|
||||
@ -83,7 +83,7 @@ export default abstract class AutocompleteProvider {
|
||||
|
||||
commandRegex.lastIndex = 0;
|
||||
|
||||
let match;
|
||||
let match: RegExpExecArray;
|
||||
while ((match = commandRegex.exec(query)) !== null) {
|
||||
const start = match.index;
|
||||
const end = start + match[0].length;
|
||||
|
@ -69,7 +69,7 @@ export default class Autocompleter {
|
||||
});
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
this.providers.forEach((p) => {
|
||||
p.destroy();
|
||||
});
|
||||
@ -88,7 +88,7 @@ export default class Autocompleter {
|
||||
*/
|
||||
// list of results from each provider, each being a list of completions or null if it times out
|
||||
const completionsList: ICompletion[][] = await Promise.all(
|
||||
this.providers.map(async (provider) => {
|
||||
this.providers.map(async (provider): Promise<ICompletion[] | null> => {
|
||||
return timeout(
|
||||
provider.getCompletions(query, selection, force, limit),
|
||||
null,
|
||||
|
@ -100,7 +100,7 @@ export default class CommandProvider extends AutocompleteProvider {
|
||||
});
|
||||
}
|
||||
|
||||
public getName() {
|
||||
public getName(): string {
|
||||
return "*️⃣ " + _t("Commands");
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ const SORTED_EMOJI: ISortedEmoji[] = EMOJI.sort((a, b) => {
|
||||
_orderBy: index,
|
||||
}));
|
||||
|
||||
function score(query, space) {
|
||||
function score(query: string, space: string): number {
|
||||
const index = space.indexOf(query);
|
||||
if (index === -1) {
|
||||
return Infinity;
|
||||
@ -154,7 +154,7 @@ export default class EmojiProvider extends AutocompleteProvider {
|
||||
return [];
|
||||
}
|
||||
|
||||
public getName() {
|
||||
public getName(): string {
|
||||
return "😃 " + _t("Emoji");
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ export default class NotifProvider extends AutocompleteProvider {
|
||||
return [];
|
||||
}
|
||||
|
||||
public getName() {
|
||||
public getName(): string {
|
||||
return "❗️ " + _t("Room Notification");
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ export default class QueryMatcher<T extends {}> {
|
||||
}
|
||||
}
|
||||
|
||||
public setObjects(objects: T[]) {
|
||||
public setObjects(objects: T[]): void {
|
||||
this._items = new Map();
|
||||
|
||||
for (const object of objects) {
|
||||
|
@ -37,7 +37,15 @@ function canonicalScore(displayedAlias: string, room: Room): number {
|
||||
return displayedAlias === room.getCanonicalAlias() ? 0 : 1;
|
||||
}
|
||||
|
||||
function matcherObject(room: Room, displayedAlias: string, matchName = "") {
|
||||
function matcherObject(
|
||||
room: Room,
|
||||
displayedAlias: string,
|
||||
matchName = "",
|
||||
): {
|
||||
room: Room;
|
||||
matchName: string;
|
||||
displayedAlias: string;
|
||||
} {
|
||||
return {
|
||||
room,
|
||||
matchName,
|
||||
@ -46,7 +54,7 @@ function matcherObject(room: Room, displayedAlias: string, matchName = "") {
|
||||
}
|
||||
|
||||
export default class RoomProvider extends AutocompleteProvider {
|
||||
protected matcher: QueryMatcher<Room>;
|
||||
protected matcher: QueryMatcher<ReturnType<typeof matcherObject>>;
|
||||
|
||||
public constructor(room: Room, renderingType?: TimelineRenderingType) {
|
||||
super({ commandRegex: ROOM_REGEX, renderingType });
|
||||
@ -55,7 +63,7 @@ export default class RoomProvider extends AutocompleteProvider {
|
||||
});
|
||||
}
|
||||
|
||||
protected getRooms() {
|
||||
protected getRooms(): Room[] {
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
||||
// filter out spaces here as they get their own autocomplete provider
|
||||
@ -68,7 +76,6 @@ export default class RoomProvider extends AutocompleteProvider {
|
||||
force = false,
|
||||
limit = -1,
|
||||
): Promise<ICompletion[]> {
|
||||
let completions = [];
|
||||
const { command, range } = this.getCurrentCommand(query, selection, force);
|
||||
if (command) {
|
||||
// the only reason we need to do this is because Fuse only matches on properties
|
||||
@ -96,15 +103,15 @@ export default class RoomProvider extends AutocompleteProvider {
|
||||
|
||||
this.matcher.setObjects(matcherObjects);
|
||||
const matchedString = command[0];
|
||||
completions = this.matcher.match(matchedString, limit);
|
||||
let completions = this.matcher.match(matchedString, limit);
|
||||
completions = sortBy(completions, [
|
||||
(c) => canonicalScore(c.displayedAlias, c.room),
|
||||
(c) => c.displayedAlias.length,
|
||||
]);
|
||||
completions = uniqBy(completions, (match) => match.room);
|
||||
completions = completions
|
||||
.map((room) => {
|
||||
return {
|
||||
return completions
|
||||
.map(
|
||||
(room): ICompletion => ({
|
||||
completion: room.displayedAlias,
|
||||
completionId: room.room.roomId,
|
||||
type: "room",
|
||||
@ -116,14 +123,14 @@ export default class RoomProvider extends AutocompleteProvider {
|
||||
</PillCompletion>
|
||||
),
|
||||
range,
|
||||
};
|
||||
})
|
||||
}),
|
||||
)
|
||||
.filter((completion) => !!completion.completion && completion.completion.length > 0);
|
||||
}
|
||||
return completions;
|
||||
return [];
|
||||
}
|
||||
|
||||
public getName() {
|
||||
public getName(): string {
|
||||
return _t("Rooms");
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import React from "react";
|
||||
|
||||
import { _t } from "../languageHandler";
|
||||
@ -21,13 +22,13 @@ import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
import RoomProvider from "./RoomProvider";
|
||||
|
||||
export default class SpaceProvider extends RoomProvider {
|
||||
protected getRooms() {
|
||||
protected getRooms(): Room[] {
|
||||
return MatrixClientPeg.get()
|
||||
.getVisibleRooms()
|
||||
.filter((r) => r.isSpaceRoom());
|
||||
}
|
||||
|
||||
public getName() {
|
||||
public getName(): string {
|
||||
return _t("Spaces");
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||
MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public destroy(): void {
|
||||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
MatrixClientPeg.get().removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||
@ -77,7 +77,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||
toStartOfTimeline: boolean,
|
||||
removed: boolean,
|
||||
data: IRoomTimelineData,
|
||||
) => {
|
||||
): void => {
|
||||
if (!room) return; // notification timeline, we'll get this event again with a room specific timeline
|
||||
if (removed) return;
|
||||
if (room.roomId !== this.room.roomId) return;
|
||||
@ -93,7 +93,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||
this.onUserSpoke(ev.sender);
|
||||
};
|
||||
|
||||
private onRoomStateUpdate = (state: RoomState) => {
|
||||
private onRoomStateUpdate = (state: RoomState): void => {
|
||||
// ignore updates in other rooms
|
||||
if (state.roomId !== this.room.roomId) return;
|
||||
|
||||
@ -150,7 +150,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||
return _t("Users");
|
||||
}
|
||||
|
||||
private makeUsers() {
|
||||
private makeUsers(): void {
|
||||
const events = this.room.getLiveTimeline().getEvents();
|
||||
const lastSpoken = {};
|
||||
|
||||
@ -167,7 +167,7 @@ export default class UserProvider extends AutocompleteProvider {
|
||||
this.matcher.setObjects(this.users);
|
||||
}
|
||||
|
||||
public onUserSpoke(user: RoomMember) {
|
||||
public onUserSpoke(user: RoomMember): void {
|
||||
if (!this.users) return;
|
||||
if (!user) return;
|
||||
if (user.userId === MatrixClientPeg.get().credentials.userId) return;
|
||||
|
@ -22,7 +22,7 @@ type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
|
||||
JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps<T> : DynamicElementProps<"div">;
|
||||
type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<Omit<JSX.IntrinsicElements[T], "ref">>;
|
||||
|
||||
export type IProps<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
|
||||
export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<DynamicHtmlElementProps<T>, "onScroll"> & {
|
||||
element?: T;
|
||||
className?: string;
|
||||
onScroll?: (event: Event) => void;
|
||||
@ -39,7 +39,7 @@ export default class AutoHideScrollbar<T extends keyof JSX.IntrinsicElements> ex
|
||||
|
||||
public readonly containerRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
if (this.containerRef.current && this.props.onScroll) {
|
||||
// Using the passive option to not block the main thread
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners
|
||||
@ -49,13 +49,13 @@ export default class AutoHideScrollbar<T extends keyof JSX.IntrinsicElements> ex
|
||||
this.props.wrappedRef?.(this.containerRef.current);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
if (this.containerRef.current && this.props.onScroll) {
|
||||
this.containerRef.current.removeEventListener("scroll", this.props.onScroll);
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { element, className, onScroll, tabIndex, wrappedRef, children, ...otherProps } = this.props;
|
||||
|
||||
|
@ -52,11 +52,11 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
|
||||
const editorContainerRef = useRef<HTMLDivElement>(null);
|
||||
const editorRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const focusEditor = () => {
|
||||
const focusEditor = (): void => {
|
||||
editorRef?.current?.focus();
|
||||
};
|
||||
|
||||
const onQueryChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const onQueryChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||
const value = e.target.value.trim();
|
||||
setQuery(value);
|
||||
|
||||
@ -74,11 +74,11 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
|
||||
setSuggestions(matches);
|
||||
};
|
||||
|
||||
const onClickInputArea = () => {
|
||||
const onClickInputArea = (): void => {
|
||||
focusEditor();
|
||||
};
|
||||
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
const onKeyDown = (e: KeyboardEvent): void => {
|
||||
const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey;
|
||||
|
||||
// when the field is empty and the user hits backspace remove the right-most target
|
||||
@ -87,7 +87,7 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSelection = (completion: ICompletion) => {
|
||||
const toggleSelection = (completion: ICompletion): void => {
|
||||
const newSelection = [...selection];
|
||||
const index = selection.findIndex((selection) => selection.completionId === completion.completionId);
|
||||
|
||||
@ -101,7 +101,7 @@ export const AutocompleteInput: React.FC<AutocompleteInputProps> = ({
|
||||
focusEditor();
|
||||
};
|
||||
|
||||
const removeSelection = (completion: ICompletion) => {
|
||||
const removeSelection = (completion: ICompletion): void => {
|
||||
const newSelection = [...selection];
|
||||
const index = selection.findIndex((selection) => selection.completionId === completion.completionId);
|
||||
|
||||
|
@ -64,7 +64,7 @@ export enum ChevronFace {
|
||||
None = "none",
|
||||
}
|
||||
|
||||
export interface IProps extends IPosition {
|
||||
export interface MenuProps extends IPosition {
|
||||
menuWidth?: number;
|
||||
menuHeight?: number;
|
||||
|
||||
@ -77,7 +77,9 @@ export interface IProps extends IPosition {
|
||||
menuPaddingRight?: number;
|
||||
|
||||
zIndex?: number;
|
||||
}
|
||||
|
||||
export interface IProps extends MenuProps {
|
||||
// If true, insert an invisible screen-sized element behind the menu that when clicked will close it.
|
||||
hasBackground?: boolean;
|
||||
// whether this context menu should be focus managed. If false it must handle itself
|
||||
@ -128,21 +130,21 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||
this.initialFocus = document.activeElement as HTMLElement;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
Modal.on(ModalManagerEvent.Opened, this.onModalOpen);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
Modal.off(ModalManagerEvent.Opened, this.onModalOpen);
|
||||
// return focus to the thing which had it before us
|
||||
this.initialFocus.focus();
|
||||
}
|
||||
|
||||
private onModalOpen = () => {
|
||||
private onModalOpen = (): void => {
|
||||
this.props.onFinished?.();
|
||||
};
|
||||
|
||||
private collectContextMenuRect = (element: HTMLDivElement) => {
|
||||
private collectContextMenuRect = (element: HTMLDivElement): void => {
|
||||
// We don't need to clean up when unmounting, so ignore
|
||||
if (!element) return;
|
||||
|
||||
@ -159,7 +161,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onContextMenu = (e) => {
|
||||
private onContextMenu = (e: React.MouseEvent): void => {
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
|
||||
@ -184,20 +186,20 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onContextMenuPreventBubbling = (e) => {
|
||||
private onContextMenuPreventBubbling = (e: React.MouseEvent): void => {
|
||||
// stop propagation so that any context menu handlers don't leak out of this context menu
|
||||
// but do not inhibit the default browser menu
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
// Prevent clicks on the background from going through to the component which opened the menu.
|
||||
private onFinished = (ev: React.MouseEvent) => {
|
||||
private onFinished = (ev: React.MouseEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.props.onFinished?.();
|
||||
};
|
||||
|
||||
private onClick = (ev: React.MouseEvent) => {
|
||||
private onClick = (ev: React.MouseEvent): void => {
|
||||
// Don't allow clicks to escape the context menu wrapper
|
||||
ev.stopPropagation();
|
||||
|
||||
@ -208,7 +210,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||
|
||||
// We now only handle closing the ContextMenu in this keyDown handler.
|
||||
// All of the item/option navigation is delegated to RovingTabIndex.
|
||||
private onKeyDown = (ev: React.KeyboardEvent) => {
|
||||
private onKeyDown = (ev: React.KeyboardEvent): void => {
|
||||
ev.stopPropagation(); // prevent keyboard propagating out of the context menu, we're focus-locked
|
||||
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
@ -243,7 +245,7 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
protected renderMenu(hasBackground = this.props.hasBackground) {
|
||||
protected renderMenu(hasBackground = this.props.hasBackground): JSX.Element {
|
||||
const position: Partial<Writeable<DOMRect>> = {};
|
||||
const {
|
||||
top,
|
||||
@ -501,17 +503,13 @@ export const toLeftOrRightOf = (elementRect: DOMRect, chevronOffset = 12): ToRig
|
||||
return toRightOf(elementRect, chevronOffset);
|
||||
};
|
||||
|
||||
export type AboveLeftOf = IPosition & {
|
||||
chevronFace: ChevronFace;
|
||||
};
|
||||
|
||||
// Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect,
|
||||
// and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?)
|
||||
export const aboveLeftOf = (
|
||||
elementRect: Pick<DOMRect, "right" | "top" | "bottom">,
|
||||
chevronFace = ChevronFace.None,
|
||||
vPadding = 0,
|
||||
): AboveLeftOf => {
|
||||
): MenuProps => {
|
||||
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
|
||||
|
||||
const buttonRight = elementRect.right + window.scrollX;
|
||||
@ -535,7 +533,7 @@ export const aboveRightOf = (
|
||||
elementRect: Pick<DOMRect, "left" | "top" | "bottom">,
|
||||
chevronFace = ChevronFace.None,
|
||||
vPadding = 0,
|
||||
): AboveLeftOf => {
|
||||
): MenuProps => {
|
||||
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
|
||||
|
||||
const buttonLeft = elementRect.left + window.scrollX;
|
||||
@ -555,11 +553,11 @@ export const aboveRightOf = (
|
||||
|
||||
// Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect
|
||||
// and always above elementRect
|
||||
export const alwaysAboveLeftOf = (
|
||||
export const alwaysMenuProps = (
|
||||
elementRect: Pick<DOMRect, "right" | "bottom" | "top">,
|
||||
chevronFace = ChevronFace.None,
|
||||
vPadding = 0,
|
||||
) => {
|
||||
): IPosition & { chevronFace: ChevronFace } => {
|
||||
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
|
||||
|
||||
const buttonRight = elementRect.right + window.scrollX;
|
||||
@ -578,7 +576,7 @@ export const alwaysAboveRightOf = (
|
||||
elementRect: Pick<DOMRect, "left" | "top">,
|
||||
chevronFace = ChevronFace.None,
|
||||
vPadding = 0,
|
||||
) => {
|
||||
): IPosition & { chevronFace: ChevronFace } => {
|
||||
const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace };
|
||||
|
||||
const buttonLeft = elementRect.left + window.scrollX;
|
||||
@ -607,12 +605,12 @@ export const useContextMenu = <T extends any = HTMLElement>(inputRef?: RefObject
|
||||
}
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const open = (ev?: SyntheticEvent) => {
|
||||
const open = (ev?: SyntheticEvent): void => {
|
||||
ev?.preventDefault();
|
||||
ev?.stopPropagation();
|
||||
setIsOpen(true);
|
||||
};
|
||||
const close = (ev?: SyntheticEvent) => {
|
||||
const close = (ev?: SyntheticEvent): void => {
|
||||
ev?.preventDefault();
|
||||
ev?.stopPropagation();
|
||||
setIsOpen(false);
|
||||
@ -622,8 +620,11 @@ export const useContextMenu = <T extends any = HTMLElement>(inputRef?: RefObject
|
||||
};
|
||||
|
||||
// XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs.
|
||||
export function createMenu(ElementClass, props) {
|
||||
const onFinished = function (...args) {
|
||||
export function createMenu(
|
||||
ElementClass: typeof React.Component,
|
||||
props: Record<string, any>,
|
||||
): { close: (...args: any[]) => void } {
|
||||
const onFinished = function (...args): void {
|
||||
ReactDOM.unmountComponentAtNode(getOrCreateContainer());
|
||||
props?.onFinished?.apply(null, args);
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
||||
return sanitizeHtml(_t(s));
|
||||
}
|
||||
|
||||
private async fetchEmbed() {
|
||||
private async fetchEmbed(): Promise<void> {
|
||||
let res: Response;
|
||||
|
||||
try {
|
||||
|
@ -37,7 +37,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
||||
useEffect(() => {
|
||||
if (!parent || parent.ondrop) return;
|
||||
|
||||
const onDragEnter = (ev: DragEvent) => {
|
||||
const onDragEnter = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
@ -55,7 +55,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
||||
}));
|
||||
};
|
||||
|
||||
const onDragLeave = (ev: DragEvent) => {
|
||||
const onDragLeave = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
@ -65,7 +65,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
||||
}));
|
||||
};
|
||||
|
||||
const onDragOver = (ev: DragEvent) => {
|
||||
const onDragOver = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
@ -79,7 +79,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const onDrop = (ev: DragEvent) => {
|
||||
const onDrop = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
onFileDrop(ev.dataTransfer);
|
||||
|
@ -223,7 +223,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
return (
|
||||
<BaseCard className="mx_FilePanel mx_RoomView_messageListWrapper" onClose={this.props.onClose}>
|
||||
|
@ -22,7 +22,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
export default class GenericErrorPage extends React.PureComponent<IProps> {
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className="mx_GenericErrorPage">
|
||||
<div className="mx_GenericErrorPage_box">
|
||||
|
@ -33,17 +33,17 @@ import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUpl
|
||||
import PosthogTrackers from "../../PosthogTrackers";
|
||||
import EmbeddedPage from "./EmbeddedPage";
|
||||
|
||||
const onClickSendDm = (ev: ButtonEvent) => {
|
||||
const onClickSendDm = (ev: ButtonEvent): void => {
|
||||
PosthogTrackers.trackInteraction("WebHomeCreateChatButton", ev);
|
||||
dis.dispatch({ action: "view_create_chat" });
|
||||
};
|
||||
|
||||
const onClickExplore = (ev: ButtonEvent) => {
|
||||
const onClickExplore = (ev: ButtonEvent): void => {
|
||||
PosthogTrackers.trackInteraction("WebHomeExploreRoomsButton", ev);
|
||||
dis.fire(Action.ViewRoomDirectory);
|
||||
};
|
||||
|
||||
const onClickNewRoom = (ev: ButtonEvent) => {
|
||||
const onClickNewRoom = (ev: ButtonEvent): void => {
|
||||
PosthogTrackers.trackInteraction("WebHomeCreateRoomButton", ev);
|
||||
dis.dispatch({ action: "view_create_room" });
|
||||
};
|
||||
@ -52,12 +52,17 @@ interface IProps {
|
||||
justRegistered?: boolean;
|
||||
}
|
||||
|
||||
const getOwnProfile = (userId: string) => ({
|
||||
const getOwnProfile = (
|
||||
userId: string,
|
||||
): {
|
||||
displayName: string;
|
||||
avatarUrl: string;
|
||||
} => ({
|
||||
displayName: OwnProfileStore.instance.displayName || userId,
|
||||
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE),
|
||||
});
|
||||
|
||||
const UserWelcomeTop = () => {
|
||||
const UserWelcomeTop: React.FC = () => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const userId = cli.getUserId();
|
||||
const [ownProfile, setOwnProfile] = useState(getOwnProfile(userId));
|
||||
|
@ -28,7 +28,7 @@ interface IProps {
|
||||
interface IState {}
|
||||
|
||||
export default class HostSignupAction extends React.PureComponent<IProps, IState> {
|
||||
private openDialog = async () => {
|
||||
private openDialog = async (): Promise<void> => {
|
||||
this.props.onClick?.();
|
||||
await HostSignupStore.instance.setHostSignupActive(true);
|
||||
};
|
||||
|
@ -130,7 +130,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.authLogic
|
||||
.attemptAuth()
|
||||
.then((result) => {
|
||||
@ -155,7 +155,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
|
||||
if (this.intervalId !== null) {
|
||||
@ -249,7 +249,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
|
||||
this.authLogic.setEmailSid(sid);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const stage = this.state.authStage;
|
||||
if (!stage) {
|
||||
if (this.state.busy) {
|
||||
|
@ -89,7 +89,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
return SettingsStore.getValue("feature_breadcrumbs_v2") ? BreadcrumbsMode.Labs : BreadcrumbsMode.Legacy;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
|
||||
UIStore.instance.on("ListContainer", this.refreshStickyHeaders);
|
||||
// Using the passive option to not block the main thread
|
||||
@ -97,7 +97,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
this.listContainerRef.current?.addEventListener("scroll", this.onScroll, { passive: true });
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
||||
@ -112,25 +112,25 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private updateActiveSpace = (activeSpace: SpaceKey) => {
|
||||
private updateActiveSpace = (activeSpace: SpaceKey): void => {
|
||||
this.setState({ activeSpace });
|
||||
};
|
||||
|
||||
private onDialPad = () => {
|
||||
private onDialPad = (): void => {
|
||||
dis.fire(Action.OpenDialPad);
|
||||
};
|
||||
|
||||
private onExplore = (ev: ButtonEvent) => {
|
||||
private onExplore = (ev: ButtonEvent): void => {
|
||||
dis.fire(Action.ViewRoomDirectory);
|
||||
PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", ev);
|
||||
};
|
||||
|
||||
private refreshStickyHeaders = () => {
|
||||
private refreshStickyHeaders = (): void => {
|
||||
if (!this.listContainerRef.current) return; // ignore: no headers to sticky
|
||||
this.handleStickyHeaders(this.listContainerRef.current);
|
||||
};
|
||||
|
||||
private onBreadcrumbsUpdate = () => {
|
||||
private onBreadcrumbsUpdate = (): void => {
|
||||
const newVal = LeftPanel.breadcrumbsMode;
|
||||
if (newVal !== this.state.showBreadcrumbs) {
|
||||
this.setState({ showBreadcrumbs: newVal });
|
||||
@ -141,7 +141,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private handleStickyHeaders(list: HTMLDivElement) {
|
||||
private handleStickyHeaders(list: HTMLDivElement): void {
|
||||
if (this.isDoingStickyHeaders) return;
|
||||
this.isDoingStickyHeaders = true;
|
||||
window.requestAnimationFrame(() => {
|
||||
@ -150,7 +150,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
private doStickyHeaders(list: HTMLDivElement) {
|
||||
private doStickyHeaders(list: HTMLDivElement): void {
|
||||
const topEdge = list.scrollTop;
|
||||
const bottomEdge = list.offsetHeight + list.scrollTop;
|
||||
const sublists = list.querySelectorAll<HTMLDivElement>(".mx_RoomSublist:not(.mx_RoomSublist_hidden)");
|
||||
@ -282,20 +282,20 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private onScroll = (ev: Event) => {
|
||||
private onScroll = (ev: Event): void => {
|
||||
const list = ev.target as HTMLDivElement;
|
||||
this.handleStickyHeaders(list);
|
||||
};
|
||||
|
||||
private onFocus = (ev: React.FocusEvent) => {
|
||||
private onFocus = (ev: React.FocusEvent): void => {
|
||||
this.focusedElement = ev.target;
|
||||
};
|
||||
|
||||
private onBlur = () => {
|
||||
private onBlur = (): void => {
|
||||
this.focusedElement = null;
|
||||
};
|
||||
|
||||
private onKeyDown = (ev: React.KeyboardEvent, state?: IRovingTabIndexState) => {
|
||||
private onKeyDown = (ev: React.KeyboardEvent, state?: IRovingTabIndexState): void => {
|
||||
if (!this.focusedElement) return;
|
||||
|
||||
const action = getKeyBindingsManager().getRoomListAction(ev);
|
||||
|
@ -142,7 +142,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
|
||||
return [...this.events][0]?.getRoomId();
|
||||
}
|
||||
|
||||
private onSilencedCallsChanged = () => {
|
||||
private onSilencedCallsChanged = (): void => {
|
||||
const newState = LegacyCallHandler.instance.isCallSilenced(this.callId);
|
||||
this.emit(LegacyCallEventGrouperEvent.SilencedChanged, newState);
|
||||
};
|
||||
@ -163,20 +163,20 @@ export default class LegacyCallEventGrouper extends EventEmitter {
|
||||
LegacyCallHandler.instance.placeCall(this.roomId, this.isVoice ? CallType.Voice : CallType.Video);
|
||||
};
|
||||
|
||||
public toggleSilenced = () => {
|
||||
public toggleSilenced = (): void => {
|
||||
const silenced = LegacyCallHandler.instance.isCallSilenced(this.callId);
|
||||
silenced
|
||||
? LegacyCallHandler.instance.unSilenceCall(this.callId)
|
||||
: LegacyCallHandler.instance.silenceCall(this.callId);
|
||||
};
|
||||
|
||||
private setCallListeners() {
|
||||
private setCallListeners(): void {
|
||||
if (!this.call) return;
|
||||
this.call.addListener(CallEvent.State, this.setState);
|
||||
this.call.addListener(CallEvent.LengthChanged, this.onLengthChanged);
|
||||
}
|
||||
|
||||
private setState = () => {
|
||||
private setState = (): void => {
|
||||
if (CONNECTING_STATES.includes(this.call?.state)) {
|
||||
this.state = CallState.Connecting;
|
||||
} else if (SUPPORTED_STATES.includes(this.call?.state)) {
|
||||
@ -190,7 +190,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
|
||||
this.emit(LegacyCallEventGrouperEvent.StateChanged, this.state);
|
||||
};
|
||||
|
||||
private setCall = () => {
|
||||
private setCall = (): void => {
|
||||
if (this.call) return;
|
||||
|
||||
this.call = LegacyCallHandler.instance.getCallById(this.callId);
|
||||
@ -198,7 +198,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
|
||||
this.setState();
|
||||
};
|
||||
|
||||
public add(event: MatrixEvent) {
|
||||
public add(event: MatrixEvent): void {
|
||||
if (this.events.has(event)) return; // nothing to do
|
||||
this.events.add(event);
|
||||
this.setCall();
|
||||
|
@ -159,7 +159,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
this.resizeHandler = React.createRef();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
document.addEventListener("keydown", this.onNativeKeyDown, false);
|
||||
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
|
||||
@ -191,7 +191,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
this.refreshBackgroundImage();
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
document.removeEventListener("keydown", this.onNativeKeyDown, false);
|
||||
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
this._matrixClient.removeListener(ClientEvent.AccountData, this.onAccountData);
|
||||
@ -221,14 +221,14 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
this.setState({ backgroundImage });
|
||||
};
|
||||
|
||||
public canResetTimelineInRoom = (roomId: string) => {
|
||||
public canResetTimelineInRoom = (roomId: string): boolean => {
|
||||
if (!this._roomView.current) {
|
||||
return true;
|
||||
}
|
||||
return this._roomView.current.canResetTimeline();
|
||||
};
|
||||
|
||||
private createResizer() {
|
||||
private createResizer(): Resizer {
|
||||
let panelSize;
|
||||
let panelCollapsed;
|
||||
const collapseConfig: ICollapseConfig = {
|
||||
@ -268,7 +268,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
return resizer;
|
||||
}
|
||||
|
||||
private loadResizerPreferences() {
|
||||
private loadResizerPreferences(): void {
|
||||
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
|
||||
if (isNaN(lhsSize)) {
|
||||
lhsSize = 350;
|
||||
@ -276,13 +276,13 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
this.resizer.forHandleWithId("lp-resizer").resize(lhsSize);
|
||||
}
|
||||
|
||||
private onAccountData = (event: MatrixEvent) => {
|
||||
private onAccountData = (event: MatrixEvent): void => {
|
||||
if (event.getType() === "m.ignored_user_list") {
|
||||
dis.dispatch({ action: "ignore_state_changed" });
|
||||
}
|
||||
};
|
||||
|
||||
private onCompactLayoutChanged = () => {
|
||||
private onCompactLayoutChanged = (): void => {
|
||||
this.setState({
|
||||
useCompactLayout: SettingsStore.getValue("useCompactLayout"),
|
||||
});
|
||||
@ -311,13 +311,13 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onUsageLimitDismissed = () => {
|
||||
private onUsageLimitDismissed = (): void => {
|
||||
this.setState({
|
||||
usageLimitDismissed: true,
|
||||
});
|
||||
};
|
||||
|
||||
private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
|
||||
private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit): void {
|
||||
const error = (syncError?.error as MatrixError)?.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
||||
if (error) {
|
||||
usageLimitEventContent = (syncError?.error as MatrixError).data as IUsageLimit;
|
||||
@ -337,9 +337,9 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private updateServerNoticeEvents = async () => {
|
||||
private updateServerNoticeEvents = async (): Promise<void> => {
|
||||
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
||||
if (!serverNoticeList) return [];
|
||||
if (!serverNoticeList) return;
|
||||
|
||||
const events = [];
|
||||
let pinnedEventTs = 0;
|
||||
@ -379,7 +379,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onPaste = (ev: ClipboardEvent) => {
|
||||
private onPaste = (ev: ClipboardEvent): void => {
|
||||
const element = ev.target as HTMLElement;
|
||||
const inputableElement = getInputableElement(element);
|
||||
if (inputableElement === document.activeElement) return; // nothing to do
|
||||
@ -422,13 +422,13 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
We also listen with a native listener on the document to get keydown events when no element is focused.
|
||||
Bubbling is irrelevant here as the target is the body element.
|
||||
*/
|
||||
private onReactKeyDown = (ev) => {
|
||||
private onReactKeyDown = (ev): void => {
|
||||
// events caught while bubbling up on the root element
|
||||
// of this component, so something must be focused.
|
||||
this.onKeyDown(ev);
|
||||
};
|
||||
|
||||
private onNativeKeyDown = (ev) => {
|
||||
private onNativeKeyDown = (ev): void => {
|
||||
// only pass this if there is no focused element.
|
||||
// if there is, onKeyDown will be called by the
|
||||
// react keydown handler that respects the react bubbling order.
|
||||
@ -437,7 +437,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onKeyDown = (ev) => {
|
||||
private onKeyDown = (ev): void => {
|
||||
let handled = false;
|
||||
|
||||
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
||||
@ -615,13 +615,13 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
* dispatch a page-up/page-down/etc to the appropriate component
|
||||
* @param {Object} ev The key event
|
||||
*/
|
||||
private onScrollKeyPressed = (ev) => {
|
||||
private onScrollKeyPressed = (ev): void => {
|
||||
if (this._roomView.current) {
|
||||
this._roomView.current.handleScrollKey(ev);
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let pageElement;
|
||||
|
||||
switch (this.props.page_type) {
|
||||
|
@ -216,7 +216,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
realQueryParams: {},
|
||||
startingFragmentQueryParams: {},
|
||||
config: {},
|
||||
onTokenLoginCompleted: () => {},
|
||||
onTokenLoginCompleted: (): void => {},
|
||||
};
|
||||
|
||||
private firstSyncComplete = false;
|
||||
@ -317,7 +317,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.props.realQueryParams,
|
||||
this.props.defaultDeviceDisplayName,
|
||||
this.getFragmentAfterLogin(),
|
||||
).then(async (loggedIn) => {
|
||||
).then(async (loggedIn): Promise<boolean | void> => {
|
||||
if (this.props.realQueryParams?.loginToken) {
|
||||
// remove the loginToken from the URL regardless
|
||||
this.props.onTokenLoginCompleted();
|
||||
@ -353,7 +353,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
initSentry(SdkConfig.get("sentry"));
|
||||
}
|
||||
|
||||
private async postLoginSetup() {
|
||||
private async postLoginSetup(): Promise<void> {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const cryptoEnabled = cli.isCryptoEnabled();
|
||||
if (!cryptoEnabled) {
|
||||
@ -367,7 +367,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
// as a proxy to figure out if it's worth prompting the user to verify
|
||||
// from another device.
|
||||
promisesList.push(
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
crossSigningIsSetUp = await cli.userHasCrossSigningKeys();
|
||||
})(),
|
||||
);
|
||||
@ -417,7 +417,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
window.addEventListener("resize", this.onWindowResized);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps, prevState) {
|
||||
public componentDidUpdate(prevProps, prevState): void {
|
||||
if (this.shouldTrackPageChange(prevState, this.state)) {
|
||||
const durationMs = this.stopPageChangeTimer();
|
||||
PosthogTrackers.instance.trackPageChange(this.state.view, this.state.page_type, durationMs);
|
||||
@ -428,7 +428,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
Lifecycle.stopMatrixClient();
|
||||
dis.unregister(this.dispatcherRef);
|
||||
this.themeWatcher.stop();
|
||||
@ -477,7 +477,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private getServerProperties() {
|
||||
private getServerProperties(): { serverConfig: ValidatedServerConfig } {
|
||||
let props = this.state.serverConfig;
|
||||
if (!props) props = this.props.serverConfig; // for unit tests
|
||||
if (!props) props = SdkConfig.get("validated_server_config");
|
||||
@ -513,11 +513,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
// to try logging out.
|
||||
}
|
||||
|
||||
private startPageChangeTimer() {
|
||||
private startPageChangeTimer(): void {
|
||||
PerformanceMonitor.instance.start(PerformanceEntryNames.PAGE_CHANGE);
|
||||
}
|
||||
|
||||
private stopPageChangeTimer() {
|
||||
private stopPageChangeTimer(): number | null {
|
||||
const perfMonitor = PerformanceMonitor.instance;
|
||||
|
||||
perfMonitor.stop(PerformanceEntryNames.PAGE_CHANGE);
|
||||
@ -876,13 +876,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private setPage(pageType: PageType) {
|
||||
private setPage(pageType: PageType): void {
|
||||
this.setState({
|
||||
page_type: pageType,
|
||||
});
|
||||
}
|
||||
|
||||
private async startRegistration(params: { [key: string]: string }) {
|
||||
private async startRegistration(params: { [key: string]: string }): Promise<void> {
|
||||
const newState: Partial<IState> = {
|
||||
view: Views.REGISTER,
|
||||
};
|
||||
@ -916,7 +916,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
|
||||
// switch view to the given room
|
||||
private async viewRoom(roomInfo: ViewRoomPayload) {
|
||||
private async viewRoom(roomInfo: ViewRoomPayload): Promise<void> {
|
||||
this.focusComposer = true;
|
||||
|
||||
if (roomInfo.room_alias) {
|
||||
@ -992,7 +992,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
);
|
||||
}
|
||||
|
||||
private viewSomethingBehindModal() {
|
||||
private viewSomethingBehindModal(): void {
|
||||
if (this.state.view !== Views.LOGGED_IN) {
|
||||
this.viewWelcome();
|
||||
return;
|
||||
@ -1002,7 +1002,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private viewWelcome() {
|
||||
private viewWelcome(): void {
|
||||
if (shouldUseLoginForWelcome(SdkConfig.get())) {
|
||||
return this.viewLogin();
|
||||
}
|
||||
@ -1014,7 +1014,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.themeWatcher.recheck();
|
||||
}
|
||||
|
||||
private viewLogin(otherState?: any) {
|
||||
private viewLogin(otherState?: any): void {
|
||||
this.setStateForNewView({
|
||||
view: Views.LOGIN,
|
||||
...otherState,
|
||||
@ -1024,7 +1024,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.themeWatcher.recheck();
|
||||
}
|
||||
|
||||
private viewHome(justRegistered = false) {
|
||||
private viewHome(justRegistered = false): void {
|
||||
// The home page requires the "logged in" view, so we'll set that.
|
||||
this.setStateForNewView({
|
||||
view: Views.LOGGED_IN,
|
||||
@ -1037,7 +1037,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.themeWatcher.recheck();
|
||||
}
|
||||
|
||||
private viewUser(userId: string, subAction: string) {
|
||||
private viewUser(userId: string, subAction: string): void {
|
||||
// Wait for the first sync so that `getRoom` gives us a room object if it's
|
||||
// in the sync response
|
||||
const waitForSync = this.firstSyncPromise ? this.firstSyncPromise.promise : Promise.resolve();
|
||||
@ -1052,7 +1052,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType) {
|
||||
private async createRoom(defaultPublic = false, defaultName?: string, type?: RoomType): Promise<void> {
|
||||
const modal = Modal.createDialog(CreateRoomDialog, {
|
||||
type,
|
||||
defaultPublic,
|
||||
@ -1065,7 +1065,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private chatCreateOrReuse(userId: string) {
|
||||
private chatCreateOrReuse(userId: string): void {
|
||||
const snakedConfig = new SnakedObject<IConfigOptions>(this.props.config);
|
||||
// Use a deferred action to reshow the dialog once the user has registered
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
@ -1115,11 +1115,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private leaveRoomWarnings(roomId: string) {
|
||||
private leaveRoomWarnings(roomId: string): JSX.Element[] {
|
||||
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
|
||||
const isSpace = roomToLeave?.isSpaceRoom();
|
||||
// Show a warning if there are additional complications.
|
||||
const warnings = [];
|
||||
const warnings: JSX.Element[] = [];
|
||||
|
||||
const memberCount = roomToLeave.currentState.getJoinedMemberCount();
|
||||
if (memberCount === 1) {
|
||||
@ -1153,7 +1153,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
private leaveRoom(roomId: string) {
|
||||
private leaveRoom(roomId: string): void {
|
||||
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
|
||||
const warnings = this.leaveRoomWarnings(roomId);
|
||||
|
||||
@ -1184,7 +1184,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
private forgetRoom(roomId: string) {
|
||||
private forgetRoom(roomId: string): void {
|
||||
const room = MatrixClientPeg.get().getRoom(roomId);
|
||||
MatrixClientPeg.get()
|
||||
.forget(roomId)
|
||||
@ -1208,7 +1208,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
private async copyRoom(roomId: string) {
|
||||
private async copyRoom(roomId: string): Promise<void> {
|
||||
const roomLink = makeRoomPermalink(roomId);
|
||||
const success = await copyPlaintext(roomLink);
|
||||
if (!success) {
|
||||
@ -1223,13 +1223,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
* Starts a chat with the welcome user, if the user doesn't already have one
|
||||
* @returns {string} The room ID of the new room, or null if no room was created
|
||||
*/
|
||||
private async startWelcomeUserChat() {
|
||||
private async startWelcomeUserChat(): Promise<string | null> {
|
||||
// We can end up with multiple tabs post-registration where the user
|
||||
// might then end up with a session and we don't want them all making
|
||||
// a chat with the welcome user: try to de-dupe.
|
||||
// We need to wait for the first sync to complete for this to
|
||||
// work though.
|
||||
let waitFor;
|
||||
let waitFor: Promise<void>;
|
||||
if (!this.firstSyncComplete) {
|
||||
waitFor = this.firstSyncPromise.promise;
|
||||
} else {
|
||||
@ -1254,7 +1254,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
// run without the update to m.direct, making another welcome
|
||||
// user room (it doesn't wait for new data from the server, just
|
||||
// the saved sync to be loaded).
|
||||
const saveWelcomeUser = (ev: MatrixEvent) => {
|
||||
const saveWelcomeUser = (ev: MatrixEvent): void => {
|
||||
if (ev.getType() === EventType.Direct && ev.getContent()[snakedConfig.get("welcome_user_id")]) {
|
||||
MatrixClientPeg.get().store.save(true);
|
||||
MatrixClientPeg.get().removeListener(ClientEvent.AccountData, saveWelcomeUser);
|
||||
@ -1270,7 +1270,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
/**
|
||||
* Called when a new logged in session has started
|
||||
*/
|
||||
private async onLoggedIn() {
|
||||
private async onLoggedIn(): Promise<void> {
|
||||
ThemeController.isLogin = false;
|
||||
this.themeWatcher.recheck();
|
||||
StorageManager.tryPersistStorage();
|
||||
@ -1301,7 +1301,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private async onShowPostLoginScreen(useCase?: UseCase) {
|
||||
private async onShowPostLoginScreen(useCase?: UseCase): Promise<void> {
|
||||
if (useCase) {
|
||||
PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase);
|
||||
SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase);
|
||||
@ -1370,7 +1370,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private initPosthogAnalyticsToast() {
|
||||
private initPosthogAnalyticsToast(): void {
|
||||
// Show the analytics toast if necessary
|
||||
if (SettingsStore.getValue("pseudonymousAnalyticsOptIn") === null) {
|
||||
showAnalyticsToast();
|
||||
@ -1397,7 +1397,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
);
|
||||
}
|
||||
|
||||
private showScreenAfterLogin() {
|
||||
private showScreenAfterLogin(): void {
|
||||
// If screenAfterLogin is set, use that, then null it so that a second login will
|
||||
// result in view_home_page, _user_settings or _room_directory
|
||||
if (this.screenAfterLogin && this.screenAfterLogin.screen) {
|
||||
@ -1415,7 +1415,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private viewLastRoom() {
|
||||
private viewLastRoom(): void {
|
||||
dis.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: localStorage.getItem("mx_last_room_id"),
|
||||
@ -1426,7 +1426,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
/**
|
||||
* Called when the session is logged out
|
||||
*/
|
||||
private onLoggedOut() {
|
||||
private onLoggedOut(): void {
|
||||
this.viewLogin({
|
||||
ready: false,
|
||||
collapseLhs: false,
|
||||
@ -1439,7 +1439,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
/**
|
||||
* Called when the session is softly logged out
|
||||
*/
|
||||
private onSoftLogout() {
|
||||
private onSoftLogout(): void {
|
||||
this.notifyNewScreen("soft_logout");
|
||||
this.setStateForNewView({
|
||||
view: Views.SOFT_LOGOUT,
|
||||
@ -1455,7 +1455,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
* Called just before the matrix client is started
|
||||
* (useful for setting listeners)
|
||||
*/
|
||||
private onWillStartClient() {
|
||||
private onWillStartClient(): void {
|
||||
// reset the 'have completed first sync' flag,
|
||||
// since we're about to start the client and therefore about
|
||||
// to do the first sync
|
||||
@ -1610,7 +1610,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
break;
|
||||
}
|
||||
});
|
||||
cli.on(CryptoEvent.KeyBackupFailed, async (errcode) => {
|
||||
cli.on(CryptoEvent.KeyBackupFailed, async (errcode): Promise<void> => {
|
||||
let haveNewVersion;
|
||||
let newVersionInfo;
|
||||
// if key backup is still enabled, there must be a new backup in place
|
||||
@ -1678,7 +1678,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
* setting up anything that requires the client to be started.
|
||||
* @private
|
||||
*/
|
||||
private onClientStarted() {
|
||||
private onClientStarted(): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
||||
if (cli.isCryptoEnabled()) {
|
||||
@ -1700,7 +1700,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public showScreen(screen: string, params?: { [key: string]: any }) {
|
||||
public showScreen(screen: string, params?: { [key: string]: any }): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const isLoggedOutOrGuest = !cli || cli.isGuest();
|
||||
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
|
||||
@ -1861,14 +1861,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private notifyNewScreen(screen: string, replaceLast = false) {
|
||||
private notifyNewScreen(screen: string, replaceLast = false): void {
|
||||
if (this.props.onNewScreen) {
|
||||
this.props.onNewScreen(screen, replaceLast);
|
||||
}
|
||||
this.setPageSubtitle();
|
||||
}
|
||||
|
||||
private onLogoutClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
|
||||
private onLogoutClick(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>): void {
|
||||
dis.dispatch({
|
||||
action: "logout",
|
||||
});
|
||||
@ -1876,7 +1876,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
private handleResize = () => {
|
||||
private handleResize = (): void => {
|
||||
const LHS_THRESHOLD = 1000;
|
||||
const width = UIStore.instance.windowWidth;
|
||||
|
||||
@ -1892,19 +1892,19 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.state.resizeNotifier.notifyWindowResized();
|
||||
};
|
||||
|
||||
private dispatchTimelineResize() {
|
||||
private dispatchTimelineResize(): void {
|
||||
dis.dispatch({ action: "timeline_resize" });
|
||||
}
|
||||
|
||||
private onRegisterClick = () => {
|
||||
private onRegisterClick = (): void => {
|
||||
this.showScreen("register");
|
||||
};
|
||||
|
||||
private onLoginClick = () => {
|
||||
private onLoginClick = (): void => {
|
||||
this.showScreen("login");
|
||||
};
|
||||
|
||||
private onForgotPasswordClick = () => {
|
||||
private onForgotPasswordClick = (): void => {
|
||||
this.showScreen("forgot_password");
|
||||
};
|
||||
|
||||
@ -1926,7 +1926,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
private setPageSubtitle(subtitle = "") {
|
||||
private setPageSubtitle(subtitle = ""): void {
|
||||
if (this.state.currentRoomId) {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client && client.getRoom(this.state.currentRoomId);
|
||||
@ -1963,11 +1963,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.setPageSubtitle();
|
||||
};
|
||||
|
||||
private onServerConfigChange = (serverConfig: ValidatedServerConfig) => {
|
||||
private onServerConfigChange = (serverConfig: ValidatedServerConfig): void => {
|
||||
this.setState({ serverConfig });
|
||||
};
|
||||
|
||||
private makeRegistrationUrl = (params: QueryDict) => {
|
||||
private makeRegistrationUrl = (params: QueryDict): string => {
|
||||
if (this.props.startingFragmentQueryParams.referrer) {
|
||||
params.referrer = this.props.startingFragmentQueryParams.referrer;
|
||||
}
|
||||
@ -2016,7 +2016,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
return fragmentAfterLogin;
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const fragmentAfterLogin = this.getFragmentAfterLogin();
|
||||
let view = null;
|
||||
|
||||
@ -2132,7 +2132,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.USE_CASE_SELECTION) {
|
||||
view = <UseCaseSelection onFinished={(useCase) => this.onShowPostLoginScreen(useCase)} />;
|
||||
view = <UseCaseSelection onFinished={(useCase): Promise<void> => this.onShowPostLoginScreen(useCase)} />;
|
||||
} else {
|
||||
logger.error(`Unknown view ${this.state.view}`);
|
||||
}
|
||||
|
@ -296,19 +296,19 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.calculateRoomMembersCount();
|
||||
this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
|
||||
this.isMounted = true;
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.isMounted = false;
|
||||
this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
|
||||
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps, prevState) {
|
||||
public componentDidUpdate(prevProps, prevState): void {
|
||||
if (prevProps.layout !== this.props.layout) {
|
||||
this.calculateRoomMembersCount();
|
||||
}
|
||||
@ -752,7 +752,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
const readReceipts = this.readReceiptsByEvent[eventId];
|
||||
|
||||
let isLastSuccessful = false;
|
||||
const isSentState = (s) => !s || s === "sent";
|
||||
const isSentState = (s): boolean => !s || s === "sent";
|
||||
const isSent = isSentState(mxEv.getAssociatedStatus());
|
||||
const hasNextEvent = nextEvent && this.shouldShowEvent(nextEvent);
|
||||
if (!hasNextEvent && isSent) {
|
||||
@ -982,7 +982,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let topSpinner;
|
||||
let bottomSpinner;
|
||||
if (this.props.backPaginating) {
|
||||
|
@ -37,15 +37,15 @@ export default class NonUrgentToastContainer extends React.PureComponent<IProps,
|
||||
NonUrgentToastStore.instance.on(UPDATE_EVENT, this.onUpdateToasts);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
NonUrgentToastStore.instance.off(UPDATE_EVENT, this.onUpdateToasts);
|
||||
}
|
||||
|
||||
private onUpdateToasts = () => {
|
||||
private onUpdateToasts = (): void => {
|
||||
this.setState({ toasts: NonUrgentToastStore.instance.components });
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const toasts = this.state.toasts.map((t, i) => {
|
||||
return (
|
||||
<div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}>
|
||||
|
@ -55,7 +55,7 @@ export default class NotificationPanel extends React.PureComponent<IProps, IStat
|
||||
this.setState({ narrow });
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const emptyState = (
|
||||
<div className="mx_RightPanel_empty mx_NotificationPanel_empty">
|
||||
<h2>{_t("You're all caught up")}</h2>
|
||||
|
@ -79,7 +79,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this._moving = value;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
document.addEventListener("mousemove", this.onMoving);
|
||||
document.addEventListener("mouseup", this.onEndMoving);
|
||||
UIStore.instance.on(UI_EVENTS.Resize, this.onResize);
|
||||
@ -87,7 +87,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this.snap();
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
document.removeEventListener("mousemove", this.onMoving);
|
||||
document.removeEventListener("mouseup", this.onEndMoving);
|
||||
UIStore.instance.off(UI_EVENTS.Resize, this.onResize);
|
||||
@ -97,7 +97,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
if (prevProps.children !== this.props.children) this.snap(true);
|
||||
}
|
||||
|
||||
private animationCallback = () => {
|
||||
private animationCallback = (): void => {
|
||||
if (
|
||||
!this.moving &&
|
||||
Math.abs(this.translationX - this.desiredTranslationX) <= 1 &&
|
||||
@ -119,13 +119,13 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this.props.onMove?.();
|
||||
};
|
||||
|
||||
private setStyle = () => {
|
||||
private setStyle = (): void => {
|
||||
if (!this.callViewWrapper.current) return;
|
||||
// Set the element's style directly, bypassing React for efficiency
|
||||
this.callViewWrapper.current.style.transform = `translateX(${this.translationX}px) translateY(${this.translationY}px)`;
|
||||
};
|
||||
|
||||
private setTranslation(inTranslationX: number, inTranslationY: number) {
|
||||
private setTranslation(inTranslationX: number, inTranslationY: number): void {
|
||||
const width = this.callViewWrapper.current?.clientWidth || PIP_VIEW_WIDTH;
|
||||
const height = this.callViewWrapper.current?.clientHeight || PIP_VIEW_HEIGHT;
|
||||
|
||||
@ -152,7 +152,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this.snap(false);
|
||||
};
|
||||
|
||||
private snap = (animate = false) => {
|
||||
private snap = (animate = false): void => {
|
||||
const translationX = this.desiredTranslationX;
|
||||
const translationY = this.desiredTranslationY;
|
||||
// We subtract the PiP size from the window size in order to calculate
|
||||
@ -187,14 +187,14 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this.scheduledUpdate.mark();
|
||||
};
|
||||
|
||||
private onStartMoving = (event: React.MouseEvent | MouseEvent) => {
|
||||
private onStartMoving = (event: React.MouseEvent | MouseEvent): void => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.mouseHeld = true;
|
||||
};
|
||||
|
||||
private onMoving = (event: MouseEvent) => {
|
||||
private onMoving = (event: MouseEvent): void => {
|
||||
if (!this.mouseHeld) return;
|
||||
|
||||
event.preventDefault();
|
||||
@ -210,7 +210,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this.setTranslation(event.pageX - this.initX, event.pageY - this.initY);
|
||||
};
|
||||
|
||||
private onEndMoving = (event: MouseEvent) => {
|
||||
private onEndMoving = (event: MouseEvent): void => {
|
||||
if (!this.mouseHeld) return;
|
||||
|
||||
event.preventDefault();
|
||||
@ -223,7 +223,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
this.snap(true);
|
||||
};
|
||||
|
||||
private onClickCapture = (event: React.MouseEvent) => {
|
||||
private onClickCapture = (event: React.MouseEvent): void => {
|
||||
// To prevent mouse up events during dragging from being double-counted
|
||||
// as clicks, we cancel clicks before they ever reach the target
|
||||
if (this.moving) {
|
||||
@ -232,7 +232,7 @@ export default class PictureInPictureDragger extends React.Component<IProps> {
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const style = {
|
||||
transform: `translateX(${this.translationX}px) translateY(${this.translationY}px)`,
|
||||
};
|
||||
|
@ -135,7 +135,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls);
|
||||
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.updateCalls);
|
||||
SdkContextClass.instance.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
@ -149,7 +149,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallChangeRoom, this.updateCalls);
|
||||
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.updateCalls);
|
||||
const cli = MatrixClientPeg.get();
|
||||
@ -164,9 +164,9 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
ActiveWidgetStore.instance.off(ActiveWidgetStoreEvent.Undock, this.onWidgetDockChanges);
|
||||
}
|
||||
|
||||
private onMove = () => this.props.movePersistedElement.current?.();
|
||||
private onMove = (): void => this.props.movePersistedElement.current?.();
|
||||
|
||||
private onRoomViewStoreUpdate = () => {
|
||||
private onRoomViewStoreUpdate = (): void => {
|
||||
const newRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||
const oldRoomId = this.state.viewedRoomId;
|
||||
if (newRoomId === oldRoomId) return;
|
||||
@ -213,7 +213,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
this.updateShowWidgetInPip();
|
||||
};
|
||||
|
||||
private onCallRemoteHold = () => {
|
||||
private onCallRemoteHold = (): void => {
|
||||
if (!this.state.viewedRoomId) return;
|
||||
const [primaryCall, secondaryCalls] = getPrimarySecondaryCallsForPip(this.state.viewedRoomId);
|
||||
|
||||
@ -238,7 +238,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
public updateShowWidgetInPip(
|
||||
persistentWidgetId = this.state.persistentWidgetId,
|
||||
persistentRoomId = this.state.persistentRoomId,
|
||||
) {
|
||||
): void {
|
||||
let fromAnotherRoom = false;
|
||||
let notDocked = false;
|
||||
// Sanity check the room - the widget may have been destroyed between render cycles, and
|
||||
@ -293,7 +293,7 @@ class PipContainerInner extends React.Component<IProps, IState> {
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const pipMode = true;
|
||||
let pipContent: Array<CreatePipChildren> = [];
|
||||
|
||||
|
@ -101,7 +101,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||
};
|
||||
}
|
||||
|
||||
private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => {
|
||||
private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember): void => {
|
||||
if (!this.props.room || member.roomId !== this.props.room.roomId) {
|
||||
return;
|
||||
}
|
||||
@ -118,11 +118,11 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
private onRightPanelStoreUpdate = (): void => {
|
||||
this.setState({ ...(RightPanel.getDerivedStateFromProps(this.props) as IState) });
|
||||
};
|
||||
|
||||
private onClose = () => {
|
||||
private onClose = (): void => {
|
||||
// XXX: There are three different ways of 'closing' this panel depending on what state
|
||||
// things are in... this knows far more than it should do about the state of the rest
|
||||
// of the app and is generally a bit silly.
|
||||
|
@ -39,15 +39,15 @@ export default class RoomSearch extends React.PureComponent<IProps> {
|
||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
defaultDispatcher.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
private openSpotlight() {
|
||||
private openSpotlight(): void {
|
||||
Modal.createDialog(SpotlightDialog, {}, "mx_SpotlightDialog_wrapper", false, true);
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (payload.action === "focus_room_filter") {
|
||||
this.openSpotlight();
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import RoomContext from "../../contexts/RoomContext";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
|
||||
const DEBUG = false;
|
||||
let debuglog = function (msg: string) {};
|
||||
let debuglog = function (msg: string): void {};
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (DEBUG) {
|
||||
@ -76,7 +76,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
|
||||
return searchPromise
|
||||
.then(
|
||||
async (results) => {
|
||||
async (results): Promise<boolean> => {
|
||||
debuglog("search complete");
|
||||
if (aborted.current) {
|
||||
logger.error("Discarding stale search results");
|
||||
@ -209,7 +209,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
|
||||
// once dynamic content in the search results load, make the scrollPanel check
|
||||
// the scroll offsets.
|
||||
const onHeightChanged = () => {
|
||||
const onHeightChanged = (): void => {
|
||||
const scrollPanel = ref.current;
|
||||
scrollPanel?.checkScroll();
|
||||
};
|
||||
|
@ -146,7 +146,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
||||
dis.fire(Action.FocusSendMessageComposer);
|
||||
};
|
||||
|
||||
private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => {
|
||||
private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room): void => {
|
||||
if (room.roomId !== this.props.room.roomId) return;
|
||||
const messages = getUnsentMessages(this.props.room);
|
||||
this.setState({
|
||||
|
@ -115,7 +115,7 @@ import VoipUserMapper from "../../VoipUserMapper";
|
||||
import { isCallEvent } from "./LegacyCallEventGrouper";
|
||||
|
||||
const DEBUG = false;
|
||||
let debuglog = function (msg: string) {};
|
||||
let debuglog = function (msg: string): void {};
|
||||
|
||||
const BROWSER_SUPPORTS_SANDBOX = "sandbox" in document.createElement("iframe");
|
||||
|
||||
@ -248,7 +248,7 @@ function LocalRoomView(props: LocalRoomViewProps): ReactElement {
|
||||
encryptionTile = <EncryptionEvent mxEvent={encryptionEvent} />;
|
||||
}
|
||||
|
||||
const onRetryClicked = () => {
|
||||
const onRetryClicked = (): void => {
|
||||
room.state = LocalRoomState.NEW;
|
||||
defaultDispatcher.dispatch({
|
||||
action: "local_room_event",
|
||||
@ -470,21 +470,21 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
];
|
||||
}
|
||||
|
||||
private onIsResizing = (resizing: boolean) => {
|
||||
private onIsResizing = (resizing: boolean): void => {
|
||||
this.setState({ resizing });
|
||||
};
|
||||
|
||||
private onWidgetStoreUpdate = () => {
|
||||
private onWidgetStoreUpdate = (): void => {
|
||||
if (!this.state.room) return;
|
||||
this.checkWidgets(this.state.room);
|
||||
};
|
||||
|
||||
private onWidgetEchoStoreUpdate = () => {
|
||||
private onWidgetEchoStoreUpdate = (): void => {
|
||||
if (!this.state.room) return;
|
||||
this.checkWidgets(this.state.room);
|
||||
};
|
||||
|
||||
private onWidgetLayoutChange = () => {
|
||||
private onWidgetLayoutChange = (): void => {
|
||||
if (!this.state.room) return;
|
||||
dis.dispatch({
|
||||
action: "appsDrawer",
|
||||
@ -505,7 +505,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
};
|
||||
|
||||
private getMainSplitContentType = (room: Room) => {
|
||||
private getMainSplitContentType = (room: Room): MainSplitContentType => {
|
||||
if (
|
||||
(SettingsStore.getValue("feature_group_calls") && this.context.roomViewStore.isViewingCall()) ||
|
||||
isVideoRoom(room)
|
||||
@ -707,7 +707,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onActiveCalls = () => {
|
||||
private onActiveCalls = (): void => {
|
||||
if (this.state.roomId === undefined) return;
|
||||
const activeCall = CallStore.instance.getActiveCall(this.state.roomId);
|
||||
|
||||
@ -727,7 +727,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.setState({ activeCall });
|
||||
};
|
||||
|
||||
private getRoomId = () => {
|
||||
private getRoomId = (): string => {
|
||||
// According to `onRoomViewStoreUpdate`, `state.roomId` can be null
|
||||
// if we have a room alias we haven't resolved yet. To work around this,
|
||||
// first we'll try the room object if it's there, and then fallback to
|
||||
@ -736,7 +736,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
return this.state.room ? this.state.room.roomId : this.state.roomId;
|
||||
};
|
||||
|
||||
private getPermalinkCreatorForRoom(room: Room) {
|
||||
private getPermalinkCreatorForRoom(room: Room): RoomPermalinkCreator {
|
||||
if (this.permalinkCreators[room.roomId]) return this.permalinkCreators[room.roomId];
|
||||
|
||||
this.permalinkCreators[room.roomId] = new RoomPermalinkCreator(room);
|
||||
@ -750,14 +750,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
return this.permalinkCreators[room.roomId];
|
||||
}
|
||||
|
||||
private stopAllPermalinkCreators() {
|
||||
private stopAllPermalinkCreators(): void {
|
||||
if (!this.permalinkCreators) return;
|
||||
for (const roomId of Object.keys(this.permalinkCreators)) {
|
||||
this.permalinkCreators[roomId].stop();
|
||||
}
|
||||
}
|
||||
|
||||
private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean) {
|
||||
private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean): void {
|
||||
// if this is an unknown room then we're in one of three states:
|
||||
// - This is a room we can peek into (search engine) (we can /peek)
|
||||
// - This is a room we can publicly join or were invited to. (we can /join)
|
||||
@ -822,7 +822,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
private shouldShowApps(room: Room) {
|
||||
private shouldShowApps(room: Room): boolean {
|
||||
if (!BROWSER_SUPPORTS_SANDBOX || !room) return false;
|
||||
|
||||
// Check if user has previously chosen to hide the app drawer for this
|
||||
@ -838,7 +838,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
return isManuallyShown && widgets.length > 0;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.onRoomViewStoreUpdate(true);
|
||||
|
||||
const call = this.getCallForRoom();
|
||||
@ -851,7 +851,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
window.addEventListener("beforeunload", this.onPageUnload);
|
||||
}
|
||||
|
||||
public shouldComponentUpdate(nextProps, nextState) {
|
||||
public shouldComponentUpdate(nextProps, nextState): boolean {
|
||||
const hasPropsDiff = objectHasDiff(this.props, nextProps);
|
||||
|
||||
const { upgradeRecommendation, ...state } = this.state;
|
||||
@ -864,7 +864,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
return hasPropsDiff || hasStateDiff;
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
public componentDidUpdate(): void {
|
||||
// Note: We check the ref here with a flag because componentDidMount, despite
|
||||
// documentation, does not define our messagePanel ref. It looks like our spinner
|
||||
// in render() prevents the ref from being set on first mount, so we try and
|
||||
@ -877,7 +877,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
// set a boolean to say we've been unmounted, which any pending
|
||||
// promises can use to throw away their results.
|
||||
//
|
||||
@ -947,13 +947,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
private onRightPanelStoreUpdate = (): void => {
|
||||
this.setState({
|
||||
showRightPanel: this.context.rightPanelStore.isOpenForRoom(this.state.roomId),
|
||||
});
|
||||
};
|
||||
|
||||
private onPageUnload = (event) => {
|
||||
private onPageUnload = (event): string => {
|
||||
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
|
||||
return (event.returnValue = _t("You seem to be uploading files, are you sure you want to quit?"));
|
||||
} else if (this.getCallForRoom() && this.state.callState !== "ended") {
|
||||
@ -961,7 +961,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onReactKeyDown = (ev) => {
|
||||
private onReactKeyDown = (ev): void => {
|
||||
let handled = false;
|
||||
|
||||
const action = getKeyBindingsManager().getRoomAction(ev);
|
||||
@ -1120,12 +1120,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onLocalRoomEvent(roomId: string) {
|
||||
private onLocalRoomEvent(roomId: string): void {
|
||||
if (roomId !== this.state.room.roomId) return;
|
||||
createRoomFromLocalRoom(this.context.client, this.state.room as LocalRoom);
|
||||
}
|
||||
|
||||
private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data) => {
|
||||
private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data): void => {
|
||||
if (this.unmounted) return;
|
||||
|
||||
// ignore events for other rooms or the notification timeline set
|
||||
@ -1167,7 +1167,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onEventDecrypted = (ev: MatrixEvent) => {
|
||||
private onEventDecrypted = (ev: MatrixEvent): void => {
|
||||
if (!this.state.room || !this.state.matrixClientIsReady) return; // not ready at all
|
||||
if (ev.getRoomId() !== this.state.room.roomId) return; // not for us
|
||||
this.updateVisibleDecryptionFailures();
|
||||
@ -1175,7 +1175,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.handleEffects(ev);
|
||||
};
|
||||
|
||||
private handleEffects = (ev: MatrixEvent) => {
|
||||
private handleEffects = (ev: MatrixEvent): void => {
|
||||
const notifState = this.context.roomNotificationStateStore.getRoomState(this.state.room);
|
||||
if (!notifState.isUnread) return;
|
||||
|
||||
@ -1189,19 +1189,19 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onRoomName = (room: Room) => {
|
||||
private onRoomName = (room: Room): void => {
|
||||
if (this.state.room && room.roomId == this.state.room.roomId) {
|
||||
this.forceUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
private onKeyBackupStatus = () => {
|
||||
private onKeyBackupStatus = (): void => {
|
||||
// Key backup status changes affect whether the in-room recovery
|
||||
// reminder is displayed.
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
public canResetTimeline = () => {
|
||||
public canResetTimeline = (): boolean => {
|
||||
if (!this.messagePanel) {
|
||||
return true;
|
||||
}
|
||||
@ -1216,7 +1216,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
|
||||
// called when state.room is first initialised (either at initial load,
|
||||
// after a successful peek, or after we join the room).
|
||||
private onRoomLoaded = (room: Room) => {
|
||||
private onRoomLoaded = (room: Room): void => {
|
||||
if (this.unmounted) return;
|
||||
// Attach a widget store listener only when we get a room
|
||||
this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
|
||||
@ -1251,17 +1251,17 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private getRoomTombstone(room = this.state.room) {
|
||||
private getRoomTombstone(room = this.state.room): MatrixEvent | undefined {
|
||||
return room?.currentState.getStateEvents(EventType.RoomTombstone, "");
|
||||
}
|
||||
|
||||
private async calculateRecommendedVersion(room: Room) {
|
||||
private async calculateRecommendedVersion(room: Room): Promise<void> {
|
||||
const upgradeRecommendation = await room.getRecommendedVersion();
|
||||
if (this.unmounted) return;
|
||||
this.setState({ upgradeRecommendation });
|
||||
}
|
||||
|
||||
private async loadMembersIfJoined(room: Room) {
|
||||
private async loadMembersIfJoined(room: Room): Promise<void> {
|
||||
// lazy load members if enabled
|
||||
if (this.context.client.hasLazyLoadMembersEnabled()) {
|
||||
if (room && room.getMyMembership() === "join") {
|
||||
@ -1280,14 +1280,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
private calculatePeekRules(room: Room) {
|
||||
private calculatePeekRules(room: Room): void {
|
||||
const historyVisibility = room.currentState.getStateEvents(EventType.RoomHistoryVisibility, "");
|
||||
this.setState({
|
||||
canPeek: historyVisibility?.getContent().history_visibility === HistoryVisibility.WorldReadable,
|
||||
});
|
||||
}
|
||||
|
||||
private updatePreviewUrlVisibility({ roomId }: Room) {
|
||||
private updatePreviewUrlVisibility({ roomId }: Room): void {
|
||||
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
|
||||
const key = this.context.client.isRoomEncrypted(roomId) ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled";
|
||||
this.setState({
|
||||
@ -1295,7 +1295,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
}
|
||||
|
||||
private onRoom = (room: Room) => {
|
||||
private onRoom = (room: Room): void => {
|
||||
if (!room || room.roomId !== this.state.roomId) {
|
||||
return;
|
||||
}
|
||||
@ -1318,7 +1318,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
);
|
||||
};
|
||||
|
||||
private onDeviceVerificationChanged = (userId: string) => {
|
||||
private onDeviceVerificationChanged = (userId: string): void => {
|
||||
const room = this.state.room;
|
||||
if (!room?.currentState.getMember(userId)) {
|
||||
return;
|
||||
@ -1326,7 +1326,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.updateE2EStatus(room);
|
||||
};
|
||||
|
||||
private onUserVerificationChanged = (userId: string) => {
|
||||
private onUserVerificationChanged = (userId: string): void => {
|
||||
const room = this.state.room;
|
||||
if (!room || !room.currentState.getMember(userId)) {
|
||||
return;
|
||||
@ -1334,14 +1334,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.updateE2EStatus(room);
|
||||
};
|
||||
|
||||
private onCrossSigningKeysChanged = () => {
|
||||
private onCrossSigningKeysChanged = (): void => {
|
||||
const room = this.state.room;
|
||||
if (room) {
|
||||
this.updateE2EStatus(room);
|
||||
}
|
||||
};
|
||||
|
||||
private async updateE2EStatus(room: Room) {
|
||||
private async updateE2EStatus(room: Room): Promise<void> {
|
||||
if (!this.context.client.isRoomEncrypted(room.roomId)) return;
|
||||
|
||||
// If crypto is not currently enabled, we aren't tracking devices at all,
|
||||
@ -1357,13 +1357,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.setState({ e2eStatus });
|
||||
}
|
||||
|
||||
private onUrlPreviewsEnabledChange = () => {
|
||||
private onUrlPreviewsEnabledChange = (): void => {
|
||||
if (this.state.room) {
|
||||
this.updatePreviewUrlVisibility(this.state.room);
|
||||
}
|
||||
};
|
||||
|
||||
private onRoomStateEvents = (ev: MatrixEvent, state: RoomState) => {
|
||||
private onRoomStateEvents = (ev: MatrixEvent, state: RoomState): void => {
|
||||
// ignore if we don't have a room yet
|
||||
if (!this.state.room || this.state.room.roomId !== state.roomId) return;
|
||||
|
||||
@ -1377,7 +1377,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onRoomStateUpdate = (state: RoomState) => {
|
||||
private onRoomStateUpdate = (state: RoomState): void => {
|
||||
// ignore members in other rooms
|
||||
if (state.roomId !== this.state.room?.roomId) {
|
||||
return;
|
||||
@ -1386,7 +1386,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.updateRoomMembers();
|
||||
};
|
||||
|
||||
private onMyMembership = (room: Room, membership: string, oldMembership: string) => {
|
||||
private onMyMembership = (room: Room, membership: string, oldMembership: string): void => {
|
||||
if (room.roomId === this.state.roomId) {
|
||||
this.forceUpdate();
|
||||
this.loadMembersIfJoined(room);
|
||||
@ -1394,7 +1394,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private updatePermissions(room: Room) {
|
||||
private updatePermissions(room: Room): void {
|
||||
if (room) {
|
||||
const me = this.context.client.getUserId();
|
||||
const canReact =
|
||||
@ -1420,7 +1420,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
{ leading: true, trailing: true },
|
||||
);
|
||||
|
||||
private checkDesktopNotifications() {
|
||||
private checkDesktopNotifications(): void {
|
||||
const memberCount = this.state.room.getJoinedMemberCount() + this.state.room.getInvitedMemberCount();
|
||||
// if they are not alone prompt the user about notifications so they don't miss replies
|
||||
if (memberCount > 1 && Notifier.shouldShowPrompt()) {
|
||||
@ -1428,7 +1428,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
private updateDMState() {
|
||||
private updateDMState(): void {
|
||||
const room = this.state.room;
|
||||
if (room.getMyMembership() != "join") {
|
||||
return;
|
||||
@ -1439,7 +1439,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
private onInviteClick = () => {
|
||||
private onInviteClick = (): void => {
|
||||
// open the room inviter
|
||||
dis.dispatch({
|
||||
action: "view_invite",
|
||||
@ -1447,7 +1447,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onJoinButtonClicked = () => {
|
||||
private onJoinButtonClicked = (): void => {
|
||||
// If the user is a ROU, allow them to transition to a PWLU
|
||||
if (this.context.client?.isGuest()) {
|
||||
// Join this room once the user has registered and logged in
|
||||
@ -1489,7 +1489,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
{ leading: false, trailing: true },
|
||||
);
|
||||
|
||||
private onMessageListScroll = () => {
|
||||
private onMessageListScroll = (): void => {
|
||||
if (this.messagePanel.isAtEndOfLiveTimeline()) {
|
||||
this.setState({
|
||||
numUnreadMessages: 0,
|
||||
@ -1504,7 +1504,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.updateVisibleDecryptionFailures();
|
||||
};
|
||||
|
||||
private resetJumpToEvent = (eventId?: string) => {
|
||||
private resetJumpToEvent = (eventId?: string): void => {
|
||||
if (
|
||||
this.state.initialEventId &&
|
||||
this.state.initialEventScrollIntoView &&
|
||||
@ -1523,7 +1523,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private injectSticker(url: string, info: object, text: string, threadId: string | null) {
|
||||
private injectSticker(url: string, info: object, text: string, threadId: string | null): void {
|
||||
if (this.context.client.isGuest()) {
|
||||
dis.dispatch({ action: "require_registration" });
|
||||
return;
|
||||
@ -1539,7 +1539,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
}
|
||||
|
||||
private onSearch = (term: string, scope: SearchScope) => {
|
||||
private onSearch = (term: string, scope: SearchScope): void => {
|
||||
const roomId = scope === SearchScope.Room ? this.state.room.roomId : undefined;
|
||||
debuglog("sending search request");
|
||||
const abortController = new AbortController();
|
||||
@ -1569,21 +1569,21 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onAppsClick = () => {
|
||||
private onAppsClick = (): void => {
|
||||
dis.dispatch({
|
||||
action: "appsDrawer",
|
||||
show: !this.state.showApps,
|
||||
});
|
||||
};
|
||||
|
||||
private onForgetClick = () => {
|
||||
private onForgetClick = (): void => {
|
||||
dis.dispatch({
|
||||
action: "forget_room",
|
||||
room_id: this.state.room.roomId,
|
||||
});
|
||||
};
|
||||
|
||||
private onRejectButtonClicked = () => {
|
||||
private onRejectButtonClicked = (): void => {
|
||||
this.setState({
|
||||
rejecting: true,
|
||||
});
|
||||
@ -1611,7 +1611,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
);
|
||||
};
|
||||
|
||||
private onRejectAndIgnoreClick = async () => {
|
||||
private onRejectAndIgnoreClick = async (): Promise<void> => {
|
||||
this.setState({
|
||||
rejecting: true,
|
||||
});
|
||||
@ -1644,7 +1644,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onRejectThreepidInviteButtonClicked = () => {
|
||||
private onRejectThreepidInviteButtonClicked = (): void => {
|
||||
// We can reject 3pid invites in the same way that we accept them,
|
||||
// using /leave rather than /join. In the short term though, we
|
||||
// just ignore them.
|
||||
@ -1652,7 +1652,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
dis.fire(Action.ViewRoomDirectory);
|
||||
};
|
||||
|
||||
private onSearchClick = () => {
|
||||
private onSearchClick = (): void => {
|
||||
this.setState({
|
||||
timelineRenderingType:
|
||||
this.state.timelineRenderingType === TimelineRenderingType.Search
|
||||
@ -1674,7 +1674,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
};
|
||||
|
||||
// jump down to the bottom of this room, where new events are arriving
|
||||
private jumpToLiveTimeline = () => {
|
||||
private jumpToLiveTimeline = (): void => {
|
||||
if (this.state.initialEventId && this.state.isInitialEventHighlighted) {
|
||||
// If we were viewing a highlighted event, firing view_room without
|
||||
// an event will take care of both clearing the URL fragment and
|
||||
@ -1692,18 +1692,18 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
};
|
||||
|
||||
// jump up to wherever our read marker is
|
||||
private jumpToReadMarker = () => {
|
||||
private jumpToReadMarker = (): void => {
|
||||
this.messagePanel.jumpToReadMarker();
|
||||
};
|
||||
|
||||
// update the read marker to match the read-receipt
|
||||
private forgetReadMarker = (ev) => {
|
||||
private forgetReadMarker = (ev): void => {
|
||||
ev.stopPropagation();
|
||||
this.messagePanel.forgetReadMarker();
|
||||
};
|
||||
|
||||
// decide whether or not the top 'unread messages' bar should be shown
|
||||
private updateTopUnreadMessagesBar = () => {
|
||||
private updateTopUnreadMessagesBar = (): void => {
|
||||
if (!this.messagePanel) {
|
||||
return;
|
||||
}
|
||||
@ -1754,12 +1754,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
};
|
||||
}
|
||||
|
||||
private onStatusBarVisible = () => {
|
||||
private onStatusBarVisible = (): void => {
|
||||
if (this.unmounted || this.state.statusBarVisible) return;
|
||||
this.setState({ statusBarVisible: true });
|
||||
};
|
||||
|
||||
private onStatusBarHidden = () => {
|
||||
private onStatusBarHidden = (): void => {
|
||||
// This is currently not desired as it is annoying if it keeps expanding and collapsing
|
||||
if (this.unmounted || !this.state.statusBarVisible) return;
|
||||
this.setState({ statusBarVisible: false });
|
||||
@ -1770,7 +1770,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
*
|
||||
* We pass it down to the scroll panel.
|
||||
*/
|
||||
public handleScrollKey = (ev) => {
|
||||
public handleScrollKey = (ev): void => {
|
||||
let panel: ScrollPanel | TimelinePanel;
|
||||
if (this.searchResultsPanel.current) {
|
||||
panel = this.searchResultsPanel.current;
|
||||
@ -1793,24 +1793,24 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
|
||||
// this has to be a proper method rather than an unnamed function,
|
||||
// otherwise react calls it with null on each update.
|
||||
private gatherTimelinePanelRef = (r) => {
|
||||
private gatherTimelinePanelRef = (r): void => {
|
||||
this.messagePanel = r;
|
||||
};
|
||||
|
||||
private getOldRoom() {
|
||||
private getOldRoom(): Room | null {
|
||||
const createEvent = this.state.room.currentState.getStateEvents(EventType.RoomCreate, "");
|
||||
if (!createEvent || !createEvent.getContent()["predecessor"]) return null;
|
||||
|
||||
return this.context.client.getRoom(createEvent.getContent()["predecessor"]["room_id"]);
|
||||
}
|
||||
|
||||
public getHiddenHighlightCount() {
|
||||
public getHiddenHighlightCount(): number {
|
||||
const oldRoom = this.getOldRoom();
|
||||
if (!oldRoom) return 0;
|
||||
return oldRoom.getUnreadNotificationCount(NotificationCountType.Highlight);
|
||||
}
|
||||
|
||||
public onHiddenHighlightsClick = () => {
|
||||
public onHiddenHighlightsClick = (): void => {
|
||||
const oldRoom = this.getOldRoom();
|
||||
if (!oldRoom) return;
|
||||
dis.dispatch<ViewRoomPayload>({
|
||||
@ -1826,7 +1826,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
});
|
||||
}
|
||||
|
||||
private onFileDrop = (dataTransfer: DataTransfer) =>
|
||||
private onFileDrop = (dataTransfer: DataTransfer): Promise<void> =>
|
||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||
Array.from(dataTransfer.files),
|
||||
this.state.room?.roomId ?? this.state.roomId,
|
||||
@ -1869,7 +1869,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
if (this.state.room instanceof LocalRoom) {
|
||||
if (this.state.room.state === LocalRoomState.CREATING) {
|
||||
return this.renderLocalRoomCreateLoader();
|
||||
|
@ -35,7 +35,7 @@ const UNFILL_REQUEST_DEBOUNCE_MS = 200;
|
||||
// much while the content loads.
|
||||
const PAGE_SIZE = 400;
|
||||
|
||||
const debuglog = (...args: any[]) => {
|
||||
const debuglog = (...args: any[]): void => {
|
||||
if (SettingsStore.getValue("debug_scroll_panel")) {
|
||||
logger.log.call(console, "ScrollPanel debuglog:", ...args);
|
||||
}
|
||||
@ -227,14 +227,14 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||
this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize);
|
||||
}
|
||||
|
||||
private onScroll = (ev: Event | React.UIEvent): void => {
|
||||
private onScroll = (ev: Event): void => {
|
||||
// skip scroll events caused by resizing
|
||||
if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return;
|
||||
debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop);
|
||||
this.scrollTimeout.restart();
|
||||
this.saveScrollState();
|
||||
this.updatePreventShrinking();
|
||||
this.props.onScroll?.(ev as Event);
|
||||
this.props.onScroll?.(ev);
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
this.checkFillState();
|
||||
};
|
||||
@ -587,7 +587,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||
* Scroll up/down in response to a scroll key
|
||||
* @param {object} ev the keyboard event
|
||||
*/
|
||||
public handleScrollKey = (ev: KeyboardEvent) => {
|
||||
public handleScrollKey = (ev: KeyboardEvent): void => {
|
||||
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
||||
switch (roomAction) {
|
||||
case KeyBindingAction.ScrollUp:
|
||||
@ -853,7 +853,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||
return this.divScroll;
|
||||
}
|
||||
|
||||
private collectScroll = (divScroll: HTMLDivElement) => {
|
||||
private collectScroll = (divScroll: HTMLDivElement): void => {
|
||||
this.divScroll = divScroll;
|
||||
};
|
||||
|
||||
|
@ -114,12 +114,12 @@ const Tile: React.FC<ITileProps> = ({
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex();
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
const onPreviewClick = (ev: ButtonEvent) => {
|
||||
const onPreviewClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
onViewRoomClick();
|
||||
};
|
||||
const onJoinClick = async (ev: ButtonEvent) => {
|
||||
const onJoinClick = async (ev: ButtonEvent): Promise<void> => {
|
||||
setBusy(true);
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
@ -271,7 +271,7 @@ const Tile: React.FC<ITileProps> = ({
|
||||
);
|
||||
|
||||
if (showChildren) {
|
||||
const onChildrenKeyDown = (e) => {
|
||||
const onChildrenKeyDown = (e): void => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.ArrowLeft:
|
||||
@ -439,7 +439,7 @@ const toLocalRoom = (cli: MatrixClient, room: IHierarchyRoom): IHierarchyRoom =>
|
||||
return room;
|
||||
};
|
||||
|
||||
export const HierarchyLevel = ({
|
||||
export const HierarchyLevel: React.FC<IHierarchyLevelProps> = ({
|
||||
root,
|
||||
roomSet,
|
||||
hierarchy,
|
||||
@ -448,7 +448,7 @@ export const HierarchyLevel = ({
|
||||
onViewRoomClick,
|
||||
onJoinRoomClick,
|
||||
onToggleClick,
|
||||
}: IHierarchyLevelProps) => {
|
||||
}) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const space = cli.getRoom(root.room_id);
|
||||
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
|
||||
@ -553,7 +553,7 @@ export const useRoomHierarchy = (
|
||||
});
|
||||
|
||||
const loadMore = useCallback(
|
||||
async (pageSize?: number) => {
|
||||
async (pageSize?: number): Promise<void> => {
|
||||
if (hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return;
|
||||
await hierarchy.load(pageSize).catch(setError);
|
||||
setRooms(hierarchy.rooms);
|
||||
@ -578,8 +578,8 @@ export const useRoomHierarchy = (
|
||||
};
|
||||
};
|
||||
|
||||
const useIntersectionObserver = (callback: () => void) => {
|
||||
const handleObserver = (entries: IntersectionObserverEntry[]) => {
|
||||
const useIntersectionObserver = (callback: () => void): ((element: HTMLDivElement) => void) => {
|
||||
const handleObserver = (entries: IntersectionObserverEntry[]): void => {
|
||||
const target = entries[0];
|
||||
if (target.isIntersecting) {
|
||||
callback();
|
||||
@ -610,7 +610,7 @@ interface IManageButtonsProps {
|
||||
setError: Dispatch<SetStateAction<string>>;
|
||||
}
|
||||
|
||||
const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageButtonsProps) => {
|
||||
const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, setSelected, setError }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
|
||||
const [removing, setRemoving] = useState(false);
|
||||
@ -645,7 +645,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
|
||||
<>
|
||||
<Button
|
||||
{...props}
|
||||
onClick={async () => {
|
||||
onClick={async (): Promise<void> => {
|
||||
setRemoving(true);
|
||||
try {
|
||||
const userId = cli.getUserId();
|
||||
@ -680,7 +680,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
|
||||
</Button>
|
||||
<Button
|
||||
{...props}
|
||||
onClick={async () => {
|
||||
onClick={async (): Promise<void> => {
|
||||
setSaving(true);
|
||||
try {
|
||||
for (const [parentId, childId] of selectedRelations) {
|
||||
@ -713,7 +713,7 @@ const ManageButtons = ({ hierarchy, selected, setSelected, setError }: IManageBu
|
||||
);
|
||||
};
|
||||
|
||||
const SpaceHierarchy = ({ space, initialText = "", showRoom, additionalButtons }: IProps) => {
|
||||
const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, additionalButtons }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const [query, setQuery] = useState(initialText);
|
||||
|
||||
|
@ -103,7 +103,7 @@ enum Phase {
|
||||
PrivateExistingRooms,
|
||||
}
|
||||
|
||||
const SpaceLandingAddButton = ({ space }) => {
|
||||
const SpaceLandingAddButton: React.FC<{ space: Room }> = ({ space }) => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
|
||||
const canCreateRoom = shouldShowComponent(UIComponent.CreateRooms);
|
||||
const canCreateSpace = shouldShowComponent(UIComponent.CreateSpaces);
|
||||
@ -128,7 +128,7 @@ const SpaceLandingAddButton = ({ space }) => {
|
||||
<IconizedContextMenuOption
|
||||
label={_t("New room")}
|
||||
iconClassName="mx_RoomList_iconNewRoom"
|
||||
onClick={async (e) => {
|
||||
onClick={async (e): Promise<void> => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
closeMenu();
|
||||
@ -143,7 +143,7 @@ const SpaceLandingAddButton = ({ space }) => {
|
||||
<IconizedContextMenuOption
|
||||
label={_t("New video room")}
|
||||
iconClassName="mx_RoomList_iconNewVideoRoom"
|
||||
onClick={async (e) => {
|
||||
onClick={async (e): Promise<void> => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
closeMenu();
|
||||
@ -210,7 +210,7 @@ const SpaceLandingAddButton = ({ space }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const SpaceLanding = ({ space }: { space: Room }) => {
|
||||
const SpaceLanding: React.FC<{ space: Room }> = ({ space }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const myMembership = useMyRoomMembership(space);
|
||||
const userId = cli.getUserId();
|
||||
@ -259,7 +259,7 @@ const SpaceLanding = ({ space }: { space: Room }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const onMembersClick = () => {
|
||||
const onMembersClick = (): void => {
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.SpaceMemberList });
|
||||
};
|
||||
|
||||
@ -297,7 +297,12 @@ const SpaceLanding = ({ space }: { space: Room }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
|
||||
const SpaceSetupFirstRooms: React.FC<{
|
||||
space: Room;
|
||||
title: string;
|
||||
description: JSX.Element;
|
||||
onFinished(firstRoomId?: string): void;
|
||||
}> = ({ space, title, description, onFinished }) => {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const numFields = 3;
|
||||
@ -321,7 +326,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
|
||||
);
|
||||
});
|
||||
|
||||
const onNextClick = async (ev: ButtonEvent) => {
|
||||
const onNextClick = async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
if (busy) return;
|
||||
setError("");
|
||||
@ -354,7 +359,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
|
||||
setBusy(false);
|
||||
};
|
||||
|
||||
let onClick = (ev: ButtonEvent) => {
|
||||
let onClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
onFinished();
|
||||
};
|
||||
@ -389,7 +394,10 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const SpaceAddExistingRooms = ({ space, onFinished }) => {
|
||||
const SpaceAddExistingRooms: React.FC<{
|
||||
space: Room;
|
||||
onFinished(): void;
|
||||
}> = ({ space, onFinished }) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>{_t("What do you want to organise?")}</h1>
|
||||
@ -420,7 +428,12 @@ interface ISpaceSetupPublicShareProps extends Pick<IProps & IState, "justCreated
|
||||
onFinished(): void;
|
||||
}
|
||||
|
||||
const SpaceSetupPublicShare = ({ justCreatedOpts, space, onFinished, firstRoomId }: ISpaceSetupPublicShareProps) => {
|
||||
const SpaceSetupPublicShare: React.FC<ISpaceSetupPublicShareProps> = ({
|
||||
justCreatedOpts,
|
||||
space,
|
||||
onFinished,
|
||||
firstRoomId,
|
||||
}) => {
|
||||
return (
|
||||
<div className="mx_SpaceRoomView_publicShare">
|
||||
<h1>
|
||||
@ -443,7 +456,11 @@ const SpaceSetupPublicShare = ({ justCreatedOpts, space, onFinished, firstRoomId
|
||||
);
|
||||
};
|
||||
|
||||
const SpaceSetupPrivateScope = ({ space, justCreatedOpts, onFinished }) => {
|
||||
const SpaceSetupPrivateScope: React.FC<{
|
||||
space: Room;
|
||||
justCreatedOpts: IOpts;
|
||||
onFinished(createRooms: boolean): void;
|
||||
}> = ({ space, justCreatedOpts, onFinished }) => {
|
||||
return (
|
||||
<div className="mx_SpaceRoomView_privateScope">
|
||||
<h1>{_t("Who are you working with?")}</h1>
|
||||
@ -485,7 +502,10 @@ const validateEmailRules = withValidation({
|
||||
],
|
||||
});
|
||||
|
||||
const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
|
||||
const SpaceSetupPrivateInvite: React.FC<{
|
||||
space: Room;
|
||||
onFinished(): void;
|
||||
}> = ({ space, onFinished }) => {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const numFields = 3;
|
||||
@ -501,7 +521,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
|
||||
label={_t("Email address")}
|
||||
placeholder={_t("Email")}
|
||||
value={emailAddresses[i]}
|
||||
onChange={(ev) => setEmailAddress(i, ev.target.value)}
|
||||
onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
|
||||
ref={fieldRefs[i]}
|
||||
onValidate={validateEmailRules}
|
||||
autoFocus={i === 0}
|
||||
@ -510,7 +530,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
|
||||
);
|
||||
});
|
||||
|
||||
const onNextClick = async (ev) => {
|
||||
const onNextClick = async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
if (busy) return;
|
||||
setError("");
|
||||
@ -548,7 +568,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
|
||||
setBusy(false);
|
||||
};
|
||||
|
||||
let onClick = (ev) => {
|
||||
let onClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
onFinished();
|
||||
};
|
||||
@ -642,29 +662,29 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.context.on(RoomEvent.MyMembership, this.onMyMembership);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
defaultDispatcher.unregister(this.dispatcherRef);
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
this.context.off(RoomEvent.MyMembership, this.onMyMembership);
|
||||
}
|
||||
|
||||
private onMyMembership = (room: Room, myMembership: string) => {
|
||||
private onMyMembership = (room: Room, myMembership: string): void => {
|
||||
if (room.roomId === this.props.space.roomId) {
|
||||
this.setState({ myMembership });
|
||||
}
|
||||
};
|
||||
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
private onRightPanelStoreUpdate = (): void => {
|
||||
this.setState({
|
||||
showRightPanel: RightPanelStore.instance.isOpenForRoom(this.props.space.roomId),
|
||||
});
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (payload.action === Action.ViewRoom && payload.room_id === this.props.space.roomId) {
|
||||
this.setState({ phase: Phase.Landing });
|
||||
return;
|
||||
@ -698,7 +718,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private goToFirstRoom = async () => {
|
||||
private goToFirstRoom = async (): Promise<void> => {
|
||||
if (this.state.firstRoomId) {
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
@ -711,7 +731,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||
this.setState({ phase: Phase.Landing });
|
||||
};
|
||||
|
||||
private renderBody() {
|
||||
private renderBody(): JSX.Element {
|
||||
switch (this.state.phase) {
|
||||
case Phase.Landing:
|
||||
if (this.state.myMembership === "join") {
|
||||
@ -794,7 +814,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const rightPanel =
|
||||
this.state.showRightPanel && this.state.phase === Phase.Landing ? (
|
||||
<RightPanel room={this.props.space} resizeNotifier={this.props.resizeNotifier} />
|
||||
|
@ -19,7 +19,7 @@ interface Props extends DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLEleme
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export default function SplashPage({ children, className, ...other }: Props) {
|
||||
export default function SplashPage({ children, className, ...other }: Props): JSX.Element {
|
||||
const classes = classNames(className, "mx_SplashPage");
|
||||
return (
|
||||
<main {...other} className={classes}>
|
||||
|
@ -86,7 +86,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||
* @param {Tab} tab the tab to show
|
||||
* @private
|
||||
*/
|
||||
private setActiveTab(tab: Tab) {
|
||||
private setActiveTab(tab: Tab): void {
|
||||
// make sure this tab is still in available tabs
|
||||
if (!!this.getTabById(tab.id)) {
|
||||
if (this.props.onChange) this.props.onChange(tab.id);
|
||||
@ -96,7 +96,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private renderTabLabel(tab: Tab) {
|
||||
private renderTabLabel(tab: Tab): JSX.Element {
|
||||
let classes = "mx_TabbedView_tabLabel ";
|
||||
|
||||
if (this.state.activeTabId === tab.id) classes += "mx_TabbedView_tabLabel_active";
|
||||
@ -106,7 +106,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
|
||||
tabIcon = <span className={`mx_TabbedView_maskedIcon ${tab.icon}`} />;
|
||||
}
|
||||
|
||||
const onClickHandler = () => this.setActiveTab(tab);
|
||||
const onClickHandler = (): void => this.setActiveTab(tab);
|
||||
|
||||
const label = _t(tab.label);
|
||||
return (
|
||||
|
@ -61,15 +61,12 @@ type ThreadPanelHeaderOption = {
|
||||
key: ThreadFilterType;
|
||||
};
|
||||
|
||||
export const ThreadPanelHeaderFilterOptionItem = ({
|
||||
label,
|
||||
description,
|
||||
onClick,
|
||||
isSelected,
|
||||
}: ThreadPanelHeaderOption & {
|
||||
onClick: () => void;
|
||||
isSelected: boolean;
|
||||
}) => {
|
||||
export const ThreadPanelHeaderFilterOptionItem: React.FC<
|
||||
ThreadPanelHeaderOption & {
|
||||
onClick: () => void;
|
||||
isSelected: boolean;
|
||||
}
|
||||
> = ({ label, description, onClick, isSelected }) => {
|
||||
return (
|
||||
<MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}>
|
||||
<span>{label}</span>
|
||||
@ -78,15 +75,11 @@ export const ThreadPanelHeaderFilterOptionItem = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const ThreadPanelHeader = ({
|
||||
filterOption,
|
||||
setFilterOption,
|
||||
empty,
|
||||
}: {
|
||||
export const ThreadPanelHeader: React.FC<{
|
||||
filterOption: ThreadFilterType;
|
||||
setFilterOption: (filterOption: ThreadFilterType) => void;
|
||||
empty: boolean;
|
||||
}) => {
|
||||
}> = ({ filterOption, setFilterOption, empty }) => {
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>();
|
||||
const options: readonly ThreadPanelHeaderOption[] = [
|
||||
{
|
||||
|
@ -137,7 +137,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps) {
|
||||
public componentDidUpdate(prevProps): void {
|
||||
if (prevProps.mxEvent !== this.props.mxEvent) {
|
||||
this.setupThread(this.props.mxEvent);
|
||||
}
|
||||
@ -192,7 +192,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private setupThread = (mxEv: MatrixEvent) => {
|
||||
private setupThread = (mxEv: MatrixEvent): void => {
|
||||
let thread = this.props.room.getThread(mxEv.getId());
|
||||
if (!thread) {
|
||||
thread = this.props.room.createThread(mxEv.getId(), mxEv, [mxEv], true);
|
||||
@ -200,7 +200,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
this.updateThread(thread);
|
||||
};
|
||||
|
||||
private onNewThread = (thread: Thread) => {
|
||||
private onNewThread = (thread: Thread): void => {
|
||||
if (thread.id === this.props.mxEvent.getId()) {
|
||||
this.setupThread(this.props.mxEvent);
|
||||
}
|
||||
@ -218,7 +218,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
private updateThread = (thread?: Thread) => {
|
||||
private updateThread = (thread?: Thread): void => {
|
||||
if (this.state.thread === thread) return;
|
||||
|
||||
this.setupThreadListeners(thread, this.state.thread);
|
||||
@ -276,7 +276,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
this.setState({ narrow });
|
||||
};
|
||||
|
||||
private onKeyDown = (ev: KeyboardEvent) => {
|
||||
private onKeyDown = (ev: KeyboardEvent): void => {
|
||||
let handled = false;
|
||||
|
||||
const action = getKeyBindingsManager().getRoomAction(ev);
|
||||
@ -300,7 +300,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onFileDrop = (dataTransfer: DataTransfer) => {
|
||||
private onFileDrop = (dataTransfer: DataTransfer): void => {
|
||||
const roomId = this.props.mxEvent.getRoomId();
|
||||
if (roomId) {
|
||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||
|
@ -31,6 +31,7 @@ import { Thread, ThreadEvent } from "matrix-js-sdk/src/models/thread";
|
||||
import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts";
|
||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||
import { ReadReceipt } from "matrix-js-sdk/src/models/read-receipt";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
@ -67,7 +68,7 @@ const READ_MARKER_DEBOUNCE_MS = 100;
|
||||
// How far off-screen a decryption failure can be for it to still count as "visible"
|
||||
const VISIBLE_DECRYPTION_FAILURE_MARGIN = 100;
|
||||
|
||||
const debuglog = (...args: any[]) => {
|
||||
const debuglog = (...args: any[]): void => {
|
||||
if (SettingsStore.getValue("debug_timeline_panel")) {
|
||||
logger.log.call(console, "TimelinePanel debuglog:", ...args);
|
||||
}
|
||||
@ -315,7 +316,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
this.props.timelineSet.room?.on(ThreadEvent.Update, this.onThreadUpdate);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
if (this.props.manageReadReceipts) {
|
||||
this.updateReadReceiptOnUserActivity();
|
||||
}
|
||||
@ -325,7 +326,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
this.initTimeline(this.props);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps) {
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>): void {
|
||||
if (prevProps.timelineSet !== this.props.timelineSet) {
|
||||
// throw new Error("changing timelineSet on a TimelinePanel is not supported");
|
||||
|
||||
@ -360,7 +361,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
// set a boolean to say we've been unmounted, which any pending
|
||||
// promises can use to throw away their results.
|
||||
//
|
||||
@ -616,7 +617,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onMessageListScroll = (e) => {
|
||||
private onMessageListScroll = (e: Event): void => {
|
||||
this.props.onScroll?.(e);
|
||||
if (this.props.manageReadMarkers) {
|
||||
this.doManageReadMarkers();
|
||||
@ -777,7 +778,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
public canResetTimeline = () => this.messagePanel?.current?.isAtBottom();
|
||||
public canResetTimeline = (): boolean => this.messagePanel?.current?.isAtBottom();
|
||||
|
||||
private onRoomRedaction = (ev: MatrixEvent, room: Room): void => {
|
||||
if (this.unmounted) return;
|
||||
@ -1060,7 +1061,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
this.state.readMarkerEventId ?? "",
|
||||
sendRRs ? lastReadEvent ?? undefined : undefined, // Public read receipt (could be null)
|
||||
lastReadEvent ?? undefined, // Private read receipt (could be null)
|
||||
).catch(async (e) => {
|
||||
).catch(async (e): Promise<void> => {
|
||||
// /read_markers API is not implemented on this HS, fallback to just RR
|
||||
if (e.errcode === "M_UNRECOGNIZED" && lastReadEvent) {
|
||||
if (
|
||||
@ -1070,10 +1071,11 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
)
|
||||
return;
|
||||
try {
|
||||
return await cli.sendReadReceipt(
|
||||
await cli.sendReadReceipt(
|
||||
lastReadEvent,
|
||||
sendRRs ? ReceiptType.Read : ReceiptType.ReadPrivate,
|
||||
);
|
||||
return;
|
||||
} catch (error) {
|
||||
logger.error(e);
|
||||
this.lastRRSentEventId = undefined;
|
||||
@ -1314,7 +1316,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
*
|
||||
* We pass it down to the scroll panel.
|
||||
*/
|
||||
public handleScrollKey = (ev) => {
|
||||
public handleScrollKey = (ev: React.KeyboardEvent): void => {
|
||||
if (!this.messagePanel.current) return;
|
||||
|
||||
// jump to the live timeline on ctrl-end, rather than the end of the
|
||||
@ -1342,7 +1344,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
private scrollIntoView(eventId?: string, pixelOffset?: number, offsetBase?: number): void {
|
||||
const doScroll = () => {
|
||||
const doScroll = (): void => {
|
||||
if (!this.messagePanel.current) return;
|
||||
if (eventId) {
|
||||
debuglog(
|
||||
@ -1401,7 +1403,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
? new TimelineWindow(cli, this.props.overlayTimelineSet, { windowLimit: this.props.timelineCap })
|
||||
: undefined;
|
||||
|
||||
const onLoaded = () => {
|
||||
const onLoaded = (): void => {
|
||||
if (this.unmounted) return;
|
||||
|
||||
// clear the timeline min-height when (re)loading the timeline
|
||||
@ -1441,7 +1443,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
);
|
||||
};
|
||||
|
||||
const onError = (error: MatrixError) => {
|
||||
const onError = (error: MatrixError): void => {
|
||||
if (this.unmounted) return;
|
||||
|
||||
this.setState({ timelineLoading: false });
|
||||
@ -1504,7 +1506,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
return;
|
||||
}
|
||||
|
||||
const prom = this.timelineWindow.load(eventId, INITIAL_SIZE).then(async () => {
|
||||
const prom = this.timelineWindow.load(eventId, INITIAL_SIZE).then(async (): Promise<void> => {
|
||||
if (this.overlayTimelineWindow) {
|
||||
// @TODO(kerrya) use timestampToEvent to load the overlay timeline
|
||||
// with more correct position when main TL eventId is truthy
|
||||
@ -1746,7 +1748,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
const wrapperRect = messagePanelNode.getBoundingClientRect();
|
||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||
|
||||
const isNodeInView = (node: HTMLElement) => {
|
||||
const isNodeInView = (node: HTMLElement): boolean => {
|
||||
if (node) {
|
||||
const boundingRect = node.getBoundingClientRect();
|
||||
if (
|
||||
@ -1877,13 +1879,14 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
eventId: string,
|
||||
relationType: RelationType | string,
|
||||
eventType: EventType | string,
|
||||
) => this.props.timelineSet.relations?.getChildEventsForEvent(eventId, relationType, eventType);
|
||||
): Relations | undefined =>
|
||||
this.props.timelineSet.relations?.getChildEventsForEvent(eventId, relationType, eventType);
|
||||
|
||||
private buildLegacyCallEventGroupers(events?: MatrixEvent[]): void {
|
||||
this.callEventGroupers = buildLegacyCallEventGroupers(this.callEventGroupers, events);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
// just show a spinner while the timeline loads.
|
||||
//
|
||||
// put it in a div of the right class (mx_RoomView_messagePanel) so
|
||||
|
@ -39,18 +39,18 @@ export default class ToastContainer extends React.Component<{}, IState> {
|
||||
ToastStore.sharedInstance().on("update", this.onToastStoreUpdate);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
ToastStore.sharedInstance().removeListener("update", this.onToastStoreUpdate);
|
||||
}
|
||||
|
||||
private onToastStoreUpdate = () => {
|
||||
private onToastStoreUpdate = (): void => {
|
||||
this.setState({
|
||||
toasts: ToastStore.sharedInstance().getToasts(),
|
||||
countSeen: ToastStore.sharedInstance().getCountSeen(),
|
||||
});
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const totalCount = this.state.toasts.length;
|
||||
const isStacked = totalCount > 1;
|
||||
let toast;
|
||||
|
@ -65,12 +65,12 @@ export default class UploadBar extends React.PureComponent<IProps, IState> {
|
||||
this.state = this.calculateState();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
this.mounted = true;
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.mounted = false;
|
||||
dis.unregister(this.dispatcherRef!);
|
||||
}
|
||||
@ -91,19 +91,19 @@ export default class UploadBar extends React.PureComponent<IProps, IState> {
|
||||
};
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (!this.mounted) return;
|
||||
if (isUploadPayload(payload)) {
|
||||
this.setState(this.calculateState());
|
||||
}
|
||||
};
|
||||
|
||||
private onCancelClick = (ev: ButtonEvent) => {
|
||||
private onCancelClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ContentMessages.sharedInstance().cancelUpload(this.state.currentUpload!);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
if (!this.state.currentFile) {
|
||||
return null;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||
import { ActionPayload } from "../../dispatcher/payloads";
|
||||
import { Action } from "../../dispatcher/actions";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { ChevronFace, ContextMenuButton } from "./ContextMenu";
|
||||
import { ChevronFace, ContextMenuButton, MenuProps } from "./ContextMenu";
|
||||
import { UserTab } from "../views/dialogs/UserTab";
|
||||
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
||||
import FeedbackDialog from "../views/dialogs/FeedbackDialog";
|
||||
@ -67,7 +67,7 @@ interface IState {
|
||||
showLiveAvatarAddon: boolean;
|
||||
}
|
||||
|
||||
const toRightOf = (rect: PartialDOMRect) => {
|
||||
const toRightOf = (rect: PartialDOMRect): MenuProps => {
|
||||
return {
|
||||
left: rect.width + rect.left + 8,
|
||||
top: rect.top,
|
||||
@ -75,7 +75,7 @@ const toRightOf = (rect: PartialDOMRect) => {
|
||||
};
|
||||
};
|
||||
|
||||
const below = (rect: PartialDOMRect) => {
|
||||
const below = (rect: PartialDOMRect): MenuProps => {
|
||||
return {
|
||||
left: rect.left,
|
||||
top: rect.top + rect.height,
|
||||
@ -118,7 +118,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
});
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.context.voiceBroadcastRecordingsStore.on(
|
||||
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
||||
this.onCurrentVoiceBroadcastRecordingChanged,
|
||||
@ -127,7 +127,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
if (this.themeWatcherRef) SettingsStore.unwatchSetting(this.themeWatcherRef);
|
||||
if (this.dndWatcherRef) SettingsStore.unwatchSetting(this.dndWatcherRef);
|
||||
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
|
||||
@ -163,26 +163,26 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
private onProfileUpdate = async () => {
|
||||
private onProfileUpdate = async (): Promise<void> => {
|
||||
// the store triggered an update, so force a layout update. We don't
|
||||
// have any state to store here for that to magically happen.
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
private onSelectedSpaceUpdate = async () => {
|
||||
private onSelectedSpaceUpdate = async (): Promise<void> => {
|
||||
this.setState({
|
||||
selectedSpace: SpaceStore.instance.activeSpaceRoom,
|
||||
});
|
||||
};
|
||||
|
||||
private onThemeChanged = () => {
|
||||
private onThemeChanged = (): void => {
|
||||
this.setState({
|
||||
isDarkTheme: this.isUserOnDarkTheme(),
|
||||
isHighContrast: this.isUserOnHighContrastTheme(),
|
||||
});
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
switch (payload.action) {
|
||||
case Action.ToggleUserMenu:
|
||||
if (this.state.contextMenuPosition) {
|
||||
@ -194,13 +194,13 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
}
|
||||
};
|
||||
|
||||
private onOpenMenuClick = (ev: React.MouseEvent) => {
|
||||
private onOpenMenuClick = (ev: React.MouseEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.setState({ contextMenuPosition: ev.currentTarget.getBoundingClientRect() });
|
||||
};
|
||||
|
||||
private onContextMenu = (ev: React.MouseEvent) => {
|
||||
private onContextMenu = (ev: React.MouseEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.setState({
|
||||
@ -213,11 +213,11 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
});
|
||||
};
|
||||
|
||||
private onCloseMenu = () => {
|
||||
private onCloseMenu = (): void => {
|
||||
this.setState({ contextMenuPosition: null });
|
||||
};
|
||||
|
||||
private onSwitchThemeClick = (ev: React.MouseEvent) => {
|
||||
private onSwitchThemeClick = (ev: React.MouseEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
@ -236,7 +236,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
SettingsStore.setValue("theme", null, SettingLevel.DEVICE, newTheme); // set at same level as Appearance tab
|
||||
};
|
||||
|
||||
private onSettingsOpen = (ev: ButtonEvent, tabId: string) => {
|
||||
private onSettingsOpen = (ev: ButtonEvent, tabId: string): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
@ -245,7 +245,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||
};
|
||||
|
||||
private onProvideFeedback = (ev: ButtonEvent) => {
|
||||
private onProvideFeedback = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
@ -253,7 +253,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||
};
|
||||
|
||||
private onSignOutClick = async (ev: ButtonEvent) => {
|
||||
private onSignOutClick = async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
@ -268,17 +268,17 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||
};
|
||||
|
||||
private onSignInClick = () => {
|
||||
private onSignInClick = (): void => {
|
||||
defaultDispatcher.dispatch({ action: "start_login" });
|
||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||
};
|
||||
|
||||
private onRegisterClick = () => {
|
||||
private onRegisterClick = (): void => {
|
||||
defaultDispatcher.dispatch({ action: "start_registration" });
|
||||
this.setState({ contextMenuPosition: null }); // also close the menu
|
||||
};
|
||||
|
||||
private onHomeClick = (ev: ButtonEvent) => {
|
||||
private onHomeClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
@ -429,7 +429,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||
);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const avatarSize = 32; // should match border-radius of the avatar
|
||||
|
||||
const userId = MatrixClientPeg.get().getUserId();
|
||||
|
@ -57,7 +57,7 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
|
||||
store.stop();
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const { phase, lostKeys } = this.state;
|
||||
let icon;
|
||||
let title;
|
||||
|
@ -27,7 +27,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
export default class E2eSetup extends React.Component<IProps> {
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<AuthPage>
|
||||
<CompleteSecurityBody>
|
||||
|
@ -110,11 +110,11 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.checkServerCapabilities(this.props.serverConfig);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<Props>) {
|
||||
public componentDidUpdate(prevProps: Readonly<Props>): void {
|
||||
if (
|
||||
prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
|
||||
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
|
||||
@ -159,7 +159,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
private async onPhaseEmailInputSubmit() {
|
||||
private async onPhaseEmailInputSubmit(): Promise<void> {
|
||||
this.phase = Phase.SendingEmail;
|
||||
|
||||
if (await this.sendVerificationMail()) {
|
||||
@ -213,7 +213,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
private async onPhaseEmailSentSubmit() {
|
||||
private async onPhaseEmailSentSubmit(): Promise<void> {
|
||||
this.setState({
|
||||
phase: Phase.PasswordInput,
|
||||
});
|
||||
@ -288,7 +288,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
false,
|
||||
false,
|
||||
{
|
||||
onBeforeClose: async (reason?: string) => {
|
||||
onBeforeClose: async (reason?: string): Promise<boolean> => {
|
||||
if (reason === "backgroundClick") {
|
||||
// Modal dismissed by clicking the background.
|
||||
// Go one phase back.
|
||||
@ -342,7 +342,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
private onInputChanged = (stateKey: string, ev: React.FormEvent<HTMLInputElement>) => {
|
||||
private onInputChanged = (stateKey: string, ev: React.FormEvent<HTMLInputElement>): void => {
|
||||
let value = ev.currentTarget.value;
|
||||
if (stateKey === "email") value = value.trim();
|
||||
this.setState({
|
||||
@ -460,7 +460,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
public renderDone() {
|
||||
public renderDone(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<CheckboxIcon className="mx_Icon mx_Icon_32 mx_Icon_accent" />
|
||||
@ -484,7 +484,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let resetPasswordJsx: JSX.Element;
|
||||
|
||||
switch (this.state.phase) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user