Merge pull request #5663 from matrix-org/t3chguy/spaces1
Use and create new room helpers
This commit is contained in:
commit
a581c36f58
7 changed files with 106 additions and 64 deletions
|
@ -390,7 +390,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placement method for <ContextMenu /> to position context menu to right of elementRect with chevronOffset
|
// Placement method for <ContextMenu /> to position context menu to right of elementRect with chevronOffset
|
||||||
export const toRightOf = (elementRect: DOMRect, chevronOffset = 12) => {
|
export const toRightOf = (elementRect: Pick<DOMRect, "right" | "top" | "height">, chevronOffset = 12) => {
|
||||||
const left = elementRect.right + window.pageXOffset + 3;
|
const left = elementRect.right + window.pageXOffset + 3;
|
||||||
let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
|
let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
|
||||||
top -= chevronOffset + 8; // where 8 is half the height of the chevron
|
top -= chevronOffset + 8; // where 8 is half the height of the chevron
|
||||||
|
|
|
@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React, {ComponentProps} from 'react';
|
||||||
import Room from 'matrix-js-sdk/src/models/room';
|
import Room from 'matrix-js-sdk/src/models/room';
|
||||||
import {getHttpUriForMxc} from 'matrix-js-sdk/src/content-repo';
|
import {getHttpUriForMxc} from 'matrix-js-sdk/src/content-repo';
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import Modal from '../../../Modal';
|
||||||
import * as Avatar from '../../../Avatar';
|
import * as Avatar from '../../../Avatar';
|
||||||
import {ResizeMethod} from "../../../Avatar";
|
import {ResizeMethod} from "../../../Avatar";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps extends Omit<ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url" | "onClick">{
|
||||||
// Room may be left unset here, but if it is,
|
// Room may be left unset here, but if it is,
|
||||||
// oobData.avatarUrl should be set (else there
|
// oobData.avatarUrl should be set (else there
|
||||||
// would be nowhere to get the avatar from)
|
// would be nowhere to get the avatar from)
|
||||||
|
|
40
src/components/views/elements/RoomName.tsx
Normal file
40
src/components/views/elements/RoomName.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
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 {useEffect, useState} from "react";
|
||||||
|
import {Room} from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
|
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
room: Room;
|
||||||
|
children?(name: string): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RoomName = ({ room, children }: IProps): JSX.Element => {
|
||||||
|
const [name, setName] = useState(room?.name);
|
||||||
|
useEventEmitter(room, "Room.name", () => {
|
||||||
|
setName(room?.name);
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
setName(room?.name);
|
||||||
|
}, [room]);
|
||||||
|
|
||||||
|
if (children) return children(name);
|
||||||
|
return name || "";
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RoomName;
|
45
src/components/views/elements/RoomTopic.tsx
Normal file
45
src/components/views/elements/RoomTopic.tsx
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
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 React, {useEffect, useState} from "react";
|
||||||
|
import {EventType} from "matrix-js-sdk/src/@types/event";
|
||||||
|
import {Room} from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
|
import {useEventEmitter} from "../../../hooks/useEventEmitter";
|
||||||
|
import {linkifyElement} from "../../../HtmlUtils";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
room?: Room;
|
||||||
|
children?(topic: string, ref: (element: HTMLElement) => void): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTopic = room => room?.currentState?.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic;
|
||||||
|
|
||||||
|
const RoomTopic = ({ room, children }: IProps): JSX.Element => {
|
||||||
|
const [topic, setTopic] = useState(getTopic(room));
|
||||||
|
useEventEmitter(room.currentState, "RoomState.events", () => {
|
||||||
|
setTopic(getTopic(room));
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
setTopic(getTopic(room));
|
||||||
|
}, [room]);
|
||||||
|
|
||||||
|
const ref = e => e && linkifyElement(e);
|
||||||
|
if (children) return children(topic, ref);
|
||||||
|
return <span ref={ref}>{ topic }</span>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RoomTopic;
|
|
@ -450,17 +450,7 @@ export default class MemberList extends React.Component {
|
||||||
let inviteButton;
|
let inviteButton;
|
||||||
|
|
||||||
if (room && room.getMyMembership() === 'join') {
|
if (room && room.getMyMembership() === 'join') {
|
||||||
// assume we can invite until proven false
|
const canInvite = room.canInvite(cli.getUserId());
|
||||||
let canInvite = true;
|
|
||||||
|
|
||||||
const plEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
|
||||||
const me = room.getMember(cli.getUserId());
|
|
||||||
if (plEvent && me) {
|
|
||||||
const content = plEvent.getContent();
|
|
||||||
if (content && content.invite > me.powerLevel) {
|
|
||||||
canInvite = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let inviteButtonText = _t("Invite to this room");
|
let inviteButtonText = _t("Invite to this room");
|
||||||
const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
|
const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
|
||||||
|
|
|
@ -100,15 +100,8 @@ const NewRoomIntro = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let canInvite = inRoom;
|
|
||||||
const powerLevels = room.currentState.getStateEvents(EventType.RoomPowerLevels, "")?.getContent();
|
|
||||||
const me = room.getMember(cli.getUserId());
|
|
||||||
if (powerLevels && me && powerLevels.invite > me.powerLevel) {
|
|
||||||
canInvite = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let buttons;
|
let buttons;
|
||||||
if (canInvite) {
|
if (room.canInvite(cli.getUserId())) {
|
||||||
const onInviteClick = () => {
|
const onInviteClick = () => {
|
||||||
dis.dispatch({ action: "view_invite", roomId });
|
dis.dispatch({ action: "view_invite", roomId });
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,14 +15,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {createRef} from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
||||||
import RateLimitedFunc from '../../../ratelimitedfunc';
|
import RateLimitedFunc from '../../../ratelimitedfunc';
|
||||||
|
|
||||||
import { linkifyElement } from '../../../HtmlUtils';
|
|
||||||
import {CancelButton} from './SimpleRoomHeader';
|
import {CancelButton} from './SimpleRoomHeader';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import RoomHeaderButtons from '../right_panel/RoomHeaderButtons';
|
import RoomHeaderButtons from '../right_panel/RoomHeaderButtons';
|
||||||
|
@ -30,6 +29,8 @@ import E2EIcon from './E2EIcon';
|
||||||
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
||||||
import {DefaultTagID} from "../../../stores/room-list/models";
|
import {DefaultTagID} from "../../../stores/room-list/models";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
|
import RoomTopic from "../elements/RoomTopic";
|
||||||
|
import RoomName from "../elements/RoomName";
|
||||||
|
|
||||||
export default class RoomHeader extends React.Component {
|
export default class RoomHeader extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -52,35 +53,13 @@ export default class RoomHeader extends React.Component {
|
||||||
onCancelClick: null,
|
onCancelClick: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._topic = createRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
cli.on("RoomState.events", this._onRoomStateEvents);
|
cli.on("RoomState.events", this._onRoomStateEvents);
|
||||||
cli.on("Room.accountData", this._onRoomAccountData);
|
cli.on("Room.accountData", this._onRoomAccountData);
|
||||||
|
|
||||||
// When a room name occurs, RoomState.events is fired *before*
|
|
||||||
// room.name is updated. So we have to listen to Room.name as well as
|
|
||||||
// RoomState.events.
|
|
||||||
if (this.props.room) {
|
|
||||||
this.props.room.on("Room.name", this._onRoomNameChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
if (this._topic.current) {
|
|
||||||
linkifyElement(this._topic.current);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.props.room) {
|
|
||||||
this.props.room.removeListener("Room.name", this._onRoomNameChange);
|
|
||||||
}
|
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
if (cli) {
|
if (cli) {
|
||||||
cli.removeListener("RoomState.events", this._onRoomStateEvents);
|
cli.removeListener("RoomState.events", this._onRoomStateEvents);
|
||||||
|
@ -109,10 +88,6 @@ export default class RoomHeader extends React.Component {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
_onRoomNameChange = (room) => {
|
|
||||||
this.forceUpdate();
|
|
||||||
};
|
|
||||||
|
|
||||||
_hasUnreadPins() {
|
_hasUnreadPins() {
|
||||||
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
|
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
|
||||||
if (!currentPinEvent) return false;
|
if (!currentPinEvent) return false;
|
||||||
|
@ -170,29 +145,28 @@ export default class RoomHeader extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let roomName = _t("Join Room");
|
let oobName = _t("Join Room");
|
||||||
if (this.props.oobData && this.props.oobData.name) {
|
if (this.props.oobData && this.props.oobData.name) {
|
||||||
roomName = this.props.oobData.name;
|
oobName = this.props.oobData.name;
|
||||||
} else if (this.props.room) {
|
|
||||||
roomName = this.props.room.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const textClasses = classNames('mx_RoomHeader_nametext', { mx_RoomHeader_settingsHint: settingsHint });
|
const textClasses = classNames('mx_RoomHeader_nametext', { mx_RoomHeader_settingsHint: settingsHint });
|
||||||
const name =
|
const name =
|
||||||
<div className="mx_RoomHeader_name" onClick={this.props.onSettingsClick}>
|
<div className="mx_RoomHeader_name" onClick={this.props.onSettingsClick}>
|
||||||
<div dir="auto" className={textClasses} title={roomName}>{ roomName }</div>
|
<RoomName room={this.props.room}>
|
||||||
|
{(name) => {
|
||||||
|
const roomName = name || oobName;
|
||||||
|
return <div dir="auto" className={textClasses} title={roomName}>{ roomName }</div>;
|
||||||
|
}}
|
||||||
|
</RoomName>
|
||||||
{ searchStatus }
|
{ searchStatus }
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
let topic;
|
const topicElement = <RoomTopic room={this.props.room}>
|
||||||
if (this.props.room) {
|
{(topic, ref) => <div className="mx_RoomHeader_topic" ref={ref} title={topic} dir="auto">
|
||||||
const ev = this.props.room.currentState.getStateEvents('m.room.topic', '');
|
{ topic }
|
||||||
if (ev) {
|
</div>}
|
||||||
topic = ev.getContent().topic;
|
</RoomTopic>;
|
||||||
}
|
|
||||||
}
|
|
||||||
const topicElement =
|
|
||||||
<div className="mx_RoomHeader_topic" ref={this._topic} title={topic} dir="auto">{ topic }</div>;
|
|
||||||
|
|
||||||
let roomAvatar;
|
let roomAvatar;
|
||||||
if (this.props.room) {
|
if (this.props.room) {
|
||||||
|
|
Loading…
Reference in a new issue