Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/ts/c3
This commit is contained in:
commit
4084a11847
67 changed files with 1784 additions and 253 deletions
54
src/utils/FixedRollingArray.ts
Normal file
54
src/utils/FixedRollingArray.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { arrayFastClone, arraySeed } from "./arrays";
|
||||
|
||||
/**
|
||||
* An array which is of fixed length and accepts rolling values. Values will
|
||||
* be inserted on the left, falling off the right.
|
||||
*/
|
||||
export class FixedRollingArray<T> {
|
||||
private samples: T[] = [];
|
||||
|
||||
/**
|
||||
* Creates a new fixed rolling array.
|
||||
* @param width The width of the array.
|
||||
* @param padValue The value to seed the array with.
|
||||
*/
|
||||
constructor(private width: number, padValue: T) {
|
||||
this.samples = arraySeed(padValue, this.width);
|
||||
}
|
||||
|
||||
/**
|
||||
* The array, as a fixed length.
|
||||
*/
|
||||
public get value(): T[] {
|
||||
return this.samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a value to the array.
|
||||
* @param value The value to push.
|
||||
*/
|
||||
public pushValue(value: T) {
|
||||
let swap = arrayFastClone(this.samples);
|
||||
swap.splice(0, 0, value);
|
||||
if (swap.length > this.width) {
|
||||
swap = swap.slice(0, this.width);
|
||||
}
|
||||
this.samples = swap;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -21,7 +21,7 @@ limitations under the License.
|
|||
* MIT license
|
||||
*/
|
||||
|
||||
function safariVersionCheck(ua) {
|
||||
function safariVersionCheck(ua: string): boolean {
|
||||
console.log("Browser is Safari - checking version for COLR support");
|
||||
try {
|
||||
const safariVersionMatch = ua.match(/Mac OS X ([\d|_]+).*Version\/([\d|.]+).*Safari/);
|
||||
|
@ -44,7 +44,7 @@ function safariVersionCheck(ua) {
|
|||
return false;
|
||||
}
|
||||
|
||||
async function isColrFontSupported() {
|
||||
async function isColrFontSupported(): Promise<boolean> {
|
||||
console.log("Checking for COLR support");
|
||||
|
||||
const { userAgent } = navigator;
|
||||
|
@ -101,7 +101,7 @@ async function isColrFontSupported() {
|
|||
}
|
||||
|
||||
let colrFontCheckStarted = false;
|
||||
export async function fixupColorFonts() {
|
||||
export async function fixupColorFonts(): Promise<void> {
|
||||
if (colrFontCheckStarted) {
|
||||
return;
|
||||
}
|
||||
|
@ -112,14 +112,14 @@ export async function fixupColorFonts() {
|
|||
document.fonts.add(new FontFace("Twemoji", path, {}));
|
||||
// For at least Chrome on Windows 10, we have to explictly add extra
|
||||
// weights for the emoji to appear in bold messages, etc.
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: 600 }));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: 700 }));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: "600" }));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: "700" }));
|
||||
} else {
|
||||
// fall back to SBIX, generated via https://github.com/matrix-org/twemoji-colr/tree/matthew/sbix
|
||||
const path = `url('${require("../../res/fonts/Twemoji_Mozilla/TwemojiMozilla-sbix.woff2")}')`;
|
||||
document.fonts.add(new FontFace("Twemoji", path, {}));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: 600 }));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: 700 }));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: "600" }));
|
||||
document.fonts.add(new FontFace("Twemoji", path, { weight: "700" }));
|
||||
}
|
||||
// ...and if SBIX is not supported, the browser will fall back to one of the native fonts specified.
|
||||
}
|
|
@ -39,6 +39,9 @@ const UNKNOWN_PROFILE_ERRORS = ['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'M_PROFILE_UN
|
|||
|
||||
export type CompletionStates = Record<string, InviteState>;
|
||||
|
||||
const USER_ALREADY_JOINED = "IO.ELEMENT.ALREADY_JOINED";
|
||||
const USER_ALREADY_INVITED = "IO.ELEMENT.ALREADY_INVITED";
|
||||
|
||||
/**
|
||||
* Invites multiple addresses to a room or group, handling rate limiting from the server
|
||||
*/
|
||||
|
@ -130,9 +133,14 @@ export default class MultiInviter {
|
|||
if (!room) throw new Error("Room not found");
|
||||
|
||||
const member = room.getMember(addr);
|
||||
if (member && ['join', 'invite'].includes(member.membership)) {
|
||||
throw new new MatrixError({
|
||||
errcode: "RIOT.ALREADY_IN_ROOM",
|
||||
if (member?.membership === "join") {
|
||||
throw new MatrixError({
|
||||
errcode: USER_ALREADY_JOINED,
|
||||
error: "Member already joined",
|
||||
});
|
||||
} else if (member?.membership === "invite") {
|
||||
throw new MatrixError({
|
||||
errcode: USER_ALREADY_INVITED,
|
||||
error: "Member already invited",
|
||||
});
|
||||
}
|
||||
|
@ -180,30 +188,47 @@ export default class MultiInviter {
|
|||
|
||||
let errorText;
|
||||
let fatal = false;
|
||||
if (err.errcode === 'M_FORBIDDEN') {
|
||||
fatal = true;
|
||||
errorText = _t('You do not have permission to invite people to this room.');
|
||||
} else if (err.errcode === "RIOT.ALREADY_IN_ROOM") {
|
||||
errorText = _t("User %(userId)s is already in the room", { userId: address });
|
||||
} else if (err.errcode === 'M_LIMIT_EXCEEDED') {
|
||||
// we're being throttled so wait a bit & try again
|
||||
setTimeout(() => {
|
||||
this.doInvite(address, ignoreProfile).then(resolve, reject);
|
||||
}, 5000);
|
||||
return;
|
||||
} else if (['M_NOT_FOUND', 'M_USER_NOT_FOUND'].includes(err.errcode)) {
|
||||
errorText = _t("User %(user_id)s does not exist", { user_id: address });
|
||||
} else if (err.errcode === 'M_PROFILE_UNDISCLOSED') {
|
||||
errorText = _t("User %(user_id)s may or may not exist", { user_id: address });
|
||||
} else if (err.errcode === 'M_PROFILE_NOT_FOUND' && !ignoreProfile) {
|
||||
// Invite without the profile check
|
||||
console.warn(`User ${address} does not have a profile - inviting anyways automatically`);
|
||||
this.doInvite(address, true).then(resolve, reject);
|
||||
} else if (err.errcode === "M_BAD_STATE") {
|
||||
errorText = _t("The user must be unbanned before they can be invited.");
|
||||
} else if (err.errcode === "M_UNSUPPORTED_ROOM_VERSION") {
|
||||
errorText = _t("The user's homeserver does not support the version of the room.");
|
||||
} else {
|
||||
switch (err.errcode) {
|
||||
case "M_FORBIDDEN":
|
||||
errorText = _t('You do not have permission to invite people to this room.');
|
||||
fatal = true;
|
||||
break;
|
||||
case USER_ALREADY_INVITED:
|
||||
errorText = _t("User %(userId)s is already invited to the room", { userId: address });
|
||||
break;
|
||||
case USER_ALREADY_JOINED:
|
||||
errorText = _t("User %(userId)s is already in the room", { userId: address });
|
||||
break;
|
||||
case "M_LIMIT_EXCEEDED":
|
||||
// we're being throttled so wait a bit & try again
|
||||
setTimeout(() => {
|
||||
this.doInvite(address, ignoreProfile).then(resolve, reject);
|
||||
}, 5000);
|
||||
return;
|
||||
case "M_NOT_FOUND":
|
||||
case "M_USER_NOT_FOUND":
|
||||
errorText = _t("User %(user_id)s does not exist", { user_id: address });
|
||||
break;
|
||||
case "M_PROFILE_UNDISCLOSED":
|
||||
errorText = _t("User %(user_id)s may or may not exist", { user_id: address });
|
||||
break;
|
||||
case "M_PROFILE_NOT_FOUND":
|
||||
if (!ignoreProfile) {
|
||||
// Invite without the profile check
|
||||
console.warn(`User ${address} does not have a profile - inviting anyways automatically`);
|
||||
this.doInvite(address, true).then(resolve, reject);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "M_BAD_STATE":
|
||||
errorText = _t("The user must be unbanned before they can be invited.");
|
||||
break;
|
||||
case "M_UNSUPPORTED_ROOM_VERSION":
|
||||
errorText = _t("The user's homeserver does not support the version of the room.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!errorText) {
|
||||
errorText = _t('Unknown server error');
|
||||
}
|
||||
|
||||
|
|
|
@ -112,11 +112,9 @@ export function arrayRescale(input: number[], newMin: number, newMax: number): n
|
|||
* @returns {T[]} The array.
|
||||
*/
|
||||
export function arraySeed<T>(val: T, length: number): T[] {
|
||||
const a: T[] = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
a.push(val);
|
||||
}
|
||||
return a;
|
||||
// Size the array up front for performance, and use `fill` to let the browser
|
||||
// optimize the operation better than we can with a `for` loop, if it wants.
|
||||
return new Array<T>(length).fill(val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue