Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 0fe133c

Browse files
authored
Merge branch 'matrix-org:develop' into issue-19180
2 parents ab835c0 + fe79a95 commit 0fe133c

25 files changed

+534
-128
lines changed

res/css/views/auth/_AuthBody.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@ limitations under the License.
5858
background-color: $authpage-body-bg-color;
5959
}
6060

61-
.mx_Field label {
62-
color: $authpage-primary-color;
63-
}
64-
6561
.mx_Field_labelAlwaysTopLeft label,
6662
.mx_Field select + label /* Always show a select's label on top to not collide with the value */,
6763
.mx_Field input:focus + label,

res/css/views/dialogs/_AddExistingToSpaceDialog.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ limitations under the License.
7575
@mixin ProgressBarBorderRadius 8px;
7676
}
7777

78-
.mx_AddExistingToSpace_progressText {
78+
.mx_AddExistingToSpaceDialog_progressText {
7979
margin-top: 8px;
8080
font-size: $font-15px;
8181
line-height: $font-24px;

res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ limitations under the License.
7474
font-size: $font-12px;
7575
line-height: $font-15px;
7676
color: $secondary-content;
77+
margin-top: -13px; // match height of buttons to prevent height changing
7778

7879
.mx_ProgressBar {
7980
height: 8px;

res/css/views/elements/_Field.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ limitations under the License.
100100
color 0.25s ease-out 0.1s,
101101
transform 0.25s ease-out 0.1s,
102102
background-color 0.25s ease-out 0.1s;
103-
color: $primary-content;
104103
background-color: transparent;
105104
font-size: $font-14px;
106105
transform: translateY(0);

res/css/views/rooms/_RoomSublist.scss

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ limitations under the License.
2222
display: none;
2323
}
2424

25+
&:not(.mx_RoomSublist_minimized) {
26+
.mx_RoomSublist_headerContainer {
27+
height: auto;
28+
}
29+
}
30+
2531
.mx_RoomSublist_headerContainer {
2632
// Create a flexbox to make alignment easy
2733
display: flex;
@@ -41,9 +47,7 @@ limitations under the License.
4147
// The combined height must be set in the LeftPanel component for sticky headers
4248
// to work correctly.
4349
padding-bottom: 8px;
44-
// Allow the container to collapse on itself if its children
45-
// are not in the normal document flow
46-
max-height: 24px;
50+
height: 24px;
4751
color: $roomlist-header-color;
4852

4953
.mx_RoomSublist_stickable {
@@ -172,14 +176,6 @@ limitations under the License.
172176
}
173177
}
174178

175-
// In the general case, we reserve space for each sublist header to prevent
176-
// scroll jumps when they become sticky. However, that leaves a gap when
177-
// scrolled to the top above the first sublist (whose header can only ever
178-
// stick to top), so we make sure to exclude the first visible sublist.
179-
&:not(.mx_RoomSublist_hidden) ~ .mx_RoomSublist .mx_RoomSublist_headerContainer {
180-
height: 24px;
181-
}
182-
183179
.mx_RoomSublist_resizeBox {
184180
position: relative;
185181

src/Avatar.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,11 @@ export function avatarUrlForRoom(room: Room, width: number, height: number, resi
142142
// space rooms cannot be DMs so skip the rest
143143
if (SpaceStore.spacesEnabled && room.isSpaceRoom()) return null;
144144

145-
let otherMember = null;
146-
const otherUserId = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
147-
if (otherUserId) {
148-
otherMember = room.getMember(otherUserId);
149-
} else {
150-
// if the room is not marked as a 1:1, but only has max 2 members
151-
// then still try to show any avatar (pref. other member)
152-
otherMember = room.getAvatarFallbackMember();
153-
}
145+
// If the room is not a DM don't fallback to a member avatar
146+
if (!DMRoomMap.shared().getUserIdForRoomId(room.roomId)) return null;
147+
148+
// If there are only two members in the DM use the avatar of the other member
149+
const otherMember = room.getAvatarFallbackMember();
154150
if (otherMember?.getMxcAvatarUrl()) {
155151
return mediaFromMxc(otherMember.getMxcAvatarUrl()).getThumbnailOfSourceHttp(width, height, resizeMethod);
156152
}

src/RoomInvite.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,15 @@ export interface IInviteResult {
4242
*
4343
* @param {string} roomId The ID of the room to invite to
4444
* @param {string[]} addresses Array of strings of addresses to invite. May be matrix IDs or 3pids.
45+
* @param {function} progressCallback optional callback, fired after each invite.
4546
* @returns {Promise} Promise
4647
*/
47-
export function inviteMultipleToRoom(roomId: string, addresses: string[]): Promise<IInviteResult> {
48-
const inviter = new MultiInviter(roomId);
48+
export function inviteMultipleToRoom(
49+
roomId: string,
50+
addresses: string[],
51+
progressCallback?: () => void,
52+
): Promise<IInviteResult> {
53+
const inviter = new MultiInviter(roomId, progressCallback);
4954
return inviter.invite(addresses).then(states => Promise.resolve({ states, inviter }));
5055
}
5156

@@ -104,8 +109,8 @@ export function isValid3pidInvite(event: MatrixEvent): boolean {
104109
return true;
105110
}
106111

107-
export function inviteUsersToRoom(roomId: string, userIds: string[]): Promise<void> {
108-
return inviteMultipleToRoom(roomId, userIds).then((result) => {
112+
export function inviteUsersToRoom(roomId: string, userIds: string[], progressCallback?: () => void): Promise<void> {
113+
return inviteMultipleToRoom(roomId, userIds, progressCallback).then((result) => {
109114
const room = MatrixClientPeg.get().getRoom(roomId);
110115
showAnyInviteErrors(result.states, room, result.inviter);
111116
}).catch((err) => {

src/ScalarMessaging.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,9 @@ function setBotOptions(event: MessageEvent<any>, roomId: string, userId: string)
452452
});
453453
}
454454

455-
function setBotPower(event: MessageEvent<any>, roomId: string, userId: string, level: number): void {
455+
async function setBotPower(
456+
event: MessageEvent<any>, roomId: string, userId: string, level: number, ignoreIfGreater?: boolean,
457+
): Promise<void> {
456458
if (!(Number.isInteger(level) && level >= 0)) {
457459
sendError(event, _t('Power level must be positive integer.'));
458460
return;
@@ -465,22 +467,34 @@ function setBotPower(event: MessageEvent<any>, roomId: string, userId: string, l
465467
return;
466468
}
467469

468-
client.getStateEvent(roomId, "m.room.power_levels", "").then((powerLevels) => {
469-
const powerEvent = new MatrixEvent(
470+
try {
471+
const powerLevels = await client.getStateEvent(roomId, "m.room.power_levels", "");
472+
473+
// If the PL is equal to or greater than the requested PL, ignore.
474+
if (ignoreIfGreater === true) {
475+
// As per https://matrix.org/docs/spec/client_server/r0.6.0#m-room-power-levels
476+
const currentPl = (
477+
powerLevels.content.users && powerLevels.content.users[userId]
478+
) || powerLevels.content.users_default || 0;
479+
480+
if (currentPl >= level) {
481+
return sendResponse(event, {
482+
success: true,
483+
});
484+
}
485+
}
486+
await client.setPowerLevel(roomId, userId, level, new MatrixEvent(
470487
{
471488
type: "m.room.power_levels",
472489
content: powerLevels,
473490
},
474-
);
475-
476-
client.setPowerLevel(roomId, userId, level, powerEvent).then(() => {
477-
sendResponse(event, {
478-
success: true,
479-
});
480-
}, (err) => {
481-
sendError(event, err.message ? err.message : _t('Failed to send request.'), err);
491+
));
492+
return sendResponse(event, {
493+
success: true,
482494
});
483-
});
495+
} catch (err) {
496+
sendError(event, err.message ? err.message : _t('Failed to send request.'), err);
497+
}
484498
}
485499

486500
function getMembershipState(event: MessageEvent<any>, roomId: string, userId: string): void {
@@ -678,7 +692,7 @@ const onMessage = function(event: MessageEvent<any>): void {
678692
setBotOptions(event, roomId, userId);
679693
break;
680694
case Action.SetBotPower:
681-
setBotPower(event, roomId, userId, event.data.level);
695+
setBotPower(event, roomId, userId, event.data.level, event.data.ignoreIfGreater);
682696
break;
683697
default:
684698
console.warn("Unhandled postMessage event with action '" + event.data.action +"'");

src/components/structures/ContextMenu.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ limitations under the License.
1919
import React, { CSSProperties, RefObject, SyntheticEvent, useRef, useState } from "react";
2020
import ReactDOM from "react-dom";
2121
import classNames from "classnames";
22+
import FocusLock from "react-focus-lock";
2223

2324
import { Key } from "../../Keyboard";
2425
import { Writeable } from "../../@types/common";
@@ -43,8 +44,6 @@ function getOrCreateContainer(): HTMLDivElement {
4344
return container;
4445
}
4546

46-
const ARIA_MENU_ITEM_ROLES = new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]);
47-
4847
export interface IPosition {
4948
top?: number;
5049
bottom?: number;
@@ -84,6 +83,10 @@ export interface IProps extends IPosition {
8483
// it will be mounted to a container at the root of the DOM.
8584
mountAsChild?: boolean;
8685

86+
// If specified, contents will be wrapped in a FocusLock, this is only needed if the context menu is being rendered
87+
// within an existing FocusLock e.g inside a modal.
88+
focusLock?: boolean;
89+
8790
// Function to be called on menu close
8891
onFinished();
8992
// on resize callback
@@ -99,7 +102,7 @@ interface IState {
99102
// this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines.
100103
@replaceableComponent("structures.ContextMenu")
101104
export class ContextMenu extends React.PureComponent<IProps, IState> {
102-
private initialFocus: HTMLElement;
105+
private readonly initialFocus: HTMLElement;
103106

104107
static defaultProps = {
105108
hasBackground: true,
@@ -108,6 +111,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
108111

109112
constructor(props, context) {
110113
super(props, context);
114+
111115
this.state = {
112116
contextMenuElem: null,
113117
};
@@ -121,14 +125,13 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
121125
this.initialFocus.focus();
122126
}
123127

124-
private collectContextMenuRect = (element) => {
128+
private collectContextMenuRect = (element: HTMLDivElement) => {
125129
// We don't need to clean up when unmounting, so ignore
126130
if (!element) return;
127131

128-
let first = element.querySelector('[role^="menuitem"]');
129-
if (!first) {
130-
first = element.querySelector('[tab-index]');
131-
}
132+
const first = element.querySelector<HTMLElement>('[role^="menuitem"]')
133+
|| element.querySelector<HTMLElement>('[tab-index]');
134+
132135
if (first) {
133136
first.focus();
134137
}
@@ -205,7 +208,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
205208
descending = true;
206209
}
207210
}
208-
} while (element && !ARIA_MENU_ITEM_ROLES.has(element.getAttribute("role")));
211+
} while (element && !element.getAttribute("role")?.startsWith("menuitem"));
209212

210213
if (element) {
211214
(element as HTMLElement).focus();
@@ -383,6 +386,17 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
383386
);
384387
}
385388

389+
let body = <>
390+
{ chevron }
391+
{ props.children }
392+
</>;
393+
394+
if (props.focusLock) {
395+
body = <FocusLock>
396+
{ body }
397+
</FocusLock>;
398+
}
399+
386400
return (
387401
<div
388402
className={classNames("mx_ContextualMenu_wrapper", this.props.wrapperClassName)}
@@ -397,8 +411,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
397411
ref={this.collectContextMenuRect}
398412
role={this.props.managed ? "menu" : undefined}
399413
>
400-
{ chevron }
401-
{ props.children }
414+
{ body }
402415
</div>
403416
{ background }
404417
</div>

0 commit comments

Comments
 (0)