mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 03:25:12 +01:00
Merge pull request #870 from vector-im/implement-room-join-ui
Implement room join UI
This commit is contained in:
commit
664038b946
@ -51,7 +51,7 @@ function allowsChild(parent: Segment<SegmentType> | undefined, child: Segment<Se
|
|||||||
// allowed root segments
|
// allowed root segments
|
||||||
return type === "login" || type === "session" || type === "sso" || type === "logout";
|
return type === "login" || type === "session" || type === "sso" || type === "logout";
|
||||||
case "session":
|
case "session":
|
||||||
return type === "room" || type === "rooms" || type === "settings" || type === "create-room";
|
return type === "room" || type === "rooms" || type === "settings" || type === "create-room" || type === "join-room";
|
||||||
case "rooms":
|
case "rooms":
|
||||||
// downside of the approach: both of these will control which tile is selected
|
// downside of the approach: both of these will control which tile is selected
|
||||||
return type === "room" || type === "empty-grid-tile";
|
return type === "room" || type === "empty-grid-tile";
|
||||||
|
63
src/domain/session/JoinRoomViewModel.ts
Normal file
63
src/domain/session/JoinRoomViewModel.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 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 {ViewModel, Options as BaseOptions} from "../ViewModel";
|
||||||
|
import {SegmentType} from "../navigation/index";
|
||||||
|
import type {Session} from "../../matrix/Session.js";
|
||||||
|
import {joinRoom} from "../../matrix/room/joinRoom";
|
||||||
|
|
||||||
|
type Options = BaseOptions & {
|
||||||
|
session: Session;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class JoinRoomViewModel extends ViewModel<SegmentType, Options> {
|
||||||
|
private _session: Session;
|
||||||
|
private _joinInProgress: boolean = false;
|
||||||
|
private _error: Error | undefined;
|
||||||
|
|
||||||
|
constructor(options: Readonly<Options>) {
|
||||||
|
super(options);
|
||||||
|
this._session = options.session;
|
||||||
|
}
|
||||||
|
|
||||||
|
async join(roomId: string): Promise<void> {
|
||||||
|
this._error = undefined;
|
||||||
|
this._joinInProgress = true;
|
||||||
|
this.emitChange("joinInProgress");
|
||||||
|
try {
|
||||||
|
const id = await joinRoom(roomId, this._session);
|
||||||
|
this.navigation.push("room", id);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this._error = e;
|
||||||
|
this._joinInProgress = false;
|
||||||
|
this.emitChange("error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get joinInProgress(): boolean {
|
||||||
|
return this._joinInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
get status(): string | undefined {
|
||||||
|
if (this._error) {
|
||||||
|
return this._error.message;
|
||||||
|
}
|
||||||
|
else if(this._joinInProgress){
|
||||||
|
return "Joining room";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ import {SessionStatusViewModel} from "./SessionStatusViewModel.js";
|
|||||||
import {RoomGridViewModel} from "./RoomGridViewModel.js";
|
import {RoomGridViewModel} from "./RoomGridViewModel.js";
|
||||||
import {SettingsViewModel} from "./settings/SettingsViewModel.js";
|
import {SettingsViewModel} from "./settings/SettingsViewModel.js";
|
||||||
import {CreateRoomViewModel} from "./CreateRoomViewModel.js";
|
import {CreateRoomViewModel} from "./CreateRoomViewModel.js";
|
||||||
|
import {JoinRoomViewModel} from "./JoinRoomViewModel";
|
||||||
import {ViewModel} from "../ViewModel";
|
import {ViewModel} from "../ViewModel";
|
||||||
import {RoomViewModelObservable} from "./RoomViewModelObservable.js";
|
import {RoomViewModelObservable} from "./RoomViewModelObservable.js";
|
||||||
import {RightPanelViewModel} from "./rightpanel/RightPanelViewModel.js";
|
import {RightPanelViewModel} from "./rightpanel/RightPanelViewModel.js";
|
||||||
@ -45,6 +46,7 @@ export class SessionViewModel extends ViewModel {
|
|||||||
this._roomViewModelObservable = null;
|
this._roomViewModelObservable = null;
|
||||||
this._gridViewModel = null;
|
this._gridViewModel = null;
|
||||||
this._createRoomViewModel = null;
|
this._createRoomViewModel = null;
|
||||||
|
this._joinRoomViewModel = null;
|
||||||
this._setupNavigation();
|
this._setupNavigation();
|
||||||
this._setupForcedLogoutOnAccessTokenInvalidation();
|
this._setupForcedLogoutOnAccessTokenInvalidation();
|
||||||
}
|
}
|
||||||
@ -83,6 +85,12 @@ export class SessionViewModel extends ViewModel {
|
|||||||
}));
|
}));
|
||||||
this._updateCreateRoom(createRoom.get());
|
this._updateCreateRoom(createRoom.get());
|
||||||
|
|
||||||
|
const joinRoom = this.navigation.observe("join-room");
|
||||||
|
this.track(joinRoom.subscribe((joinRoomOpen) => {
|
||||||
|
this._updateJoinRoom(joinRoomOpen);
|
||||||
|
}));
|
||||||
|
this._updateJoinRoom(joinRoom.get());
|
||||||
|
|
||||||
const lightbox = this.navigation.observe("lightbox");
|
const lightbox = this.navigation.observe("lightbox");
|
||||||
this.track(lightbox.subscribe(eventId => {
|
this.track(lightbox.subscribe(eventId => {
|
||||||
this._updateLightbox(eventId);
|
this._updateLightbox(eventId);
|
||||||
@ -121,7 +129,13 @@ export class SessionViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get activeMiddleViewModel() {
|
get activeMiddleViewModel() {
|
||||||
return this._roomViewModelObservable?.get() || this._gridViewModel || this._settingsViewModel || this._createRoomViewModel;
|
return (
|
||||||
|
this._roomViewModelObservable?.get() ||
|
||||||
|
this._gridViewModel ||
|
||||||
|
this._settingsViewModel ||
|
||||||
|
this._createRoomViewModel ||
|
||||||
|
this._joinRoomViewModel
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get roomGridViewModel() {
|
get roomGridViewModel() {
|
||||||
@ -152,6 +166,10 @@ export class SessionViewModel extends ViewModel {
|
|||||||
return this._createRoomViewModel;
|
return this._createRoomViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get joinRoomViewModel() {
|
||||||
|
return this._joinRoomViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
_updateGrid(roomIds) {
|
_updateGrid(roomIds) {
|
||||||
const changed = !(this._gridViewModel && roomIds);
|
const changed = !(this._gridViewModel && roomIds);
|
||||||
const currentRoomId = this.navigation.path.get("room");
|
const currentRoomId = this.navigation.path.get("room");
|
||||||
@ -286,6 +304,16 @@ export class SessionViewModel extends ViewModel {
|
|||||||
this.emitChange("activeMiddleViewModel");
|
this.emitChange("activeMiddleViewModel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateJoinRoom(joinRoomOpen) {
|
||||||
|
if (this._joinRoomViewModel) {
|
||||||
|
this._joinRoomViewModel = this.disposeTracked(this._joinRoomViewModel);
|
||||||
|
}
|
||||||
|
if (joinRoomOpen) {
|
||||||
|
this._joinRoomViewModel = this.track(new JoinRoomViewModel(this.childOptions({session: this._client.session})));
|
||||||
|
}
|
||||||
|
this.emitChange("activeMiddleViewModel");
|
||||||
|
}
|
||||||
|
|
||||||
_updateLightbox(eventId) {
|
_updateLightbox(eventId) {
|
||||||
if (this._lightboxViewModel) {
|
if (this._lightboxViewModel) {
|
||||||
this._lightboxViewModel = this.disposeTracked(this._lightboxViewModel);
|
this._lightboxViewModel = this.disposeTracked(this._lightboxViewModel);
|
||||||
|
@ -34,7 +34,6 @@ export class LeftPanelViewModel extends ViewModel {
|
|||||||
this._setupNavigation();
|
this._setupNavigation();
|
||||||
this._closeUrl = this.urlCreator.urlForSegment("session");
|
this._closeUrl = this.urlCreator.urlForSegment("session");
|
||||||
this._settingsUrl = this.urlCreator.urlForSegment("settings");
|
this._settingsUrl = this.urlCreator.urlForSegment("settings");
|
||||||
this._createRoomUrl = this.urlCreator.urlForSegment("create-room");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_mapTileViewModels(roomsBeingCreated, invites, rooms) {
|
_mapTileViewModels(roomsBeingCreated, invites, rooms) {
|
||||||
@ -74,7 +73,13 @@ export class LeftPanelViewModel extends ViewModel {
|
|||||||
return this._settingsUrl;
|
return this._settingsUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get createRoomUrl() { return this._createRoomUrl; }
|
showCreateRoomView() {
|
||||||
|
this.navigation.push("create-room");
|
||||||
|
}
|
||||||
|
|
||||||
|
showJoinRoomView() {
|
||||||
|
this.navigation.push("join-room");
|
||||||
|
}
|
||||||
|
|
||||||
_setupNavigation() {
|
_setupNavigation() {
|
||||||
const roomObservable = this.navigation.observe("room");
|
const roomObservable = this.navigation.observe("room");
|
||||||
|
@ -23,7 +23,7 @@ import {imageToInfo} from "../common.js";
|
|||||||
// TODO: remove fallback so default isn't included in bundle for SDK users that have their custom tileClassForEntry
|
// TODO: remove fallback so default isn't included in bundle for SDK users that have their custom tileClassForEntry
|
||||||
// this is a breaking SDK change though to make this option mandatory
|
// this is a breaking SDK change though to make this option mandatory
|
||||||
import {tileClassForEntry as defaultTileClassForEntry} from "./timeline/tiles/index";
|
import {tileClassForEntry as defaultTileClassForEntry} from "./timeline/tiles/index";
|
||||||
import {RoomStatus} from "../../../matrix/room/common";
|
import {joinRoom} from "../../../matrix/room/joinRoom";
|
||||||
|
|
||||||
export class RoomViewModel extends ViewModel {
|
export class RoomViewModel extends ViewModel {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
@ -200,22 +200,11 @@ export class RoomViewModel extends ViewModel {
|
|||||||
|
|
||||||
async _processCommandJoin(roomName) {
|
async _processCommandJoin(roomName) {
|
||||||
try {
|
try {
|
||||||
const roomId = await this._options.client.session.joinRoom(roomName);
|
const session = this._options.client.session;
|
||||||
const roomStatusObserver = await this._options.client.session.observeRoomStatus(roomId);
|
const roomId = await joinRoom(roomName, session);
|
||||||
await roomStatusObserver.waitFor(status => status === RoomStatus.Joined);
|
|
||||||
this.navigation.push("room", roomId);
|
this.navigation.push("room", roomId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
let exc;
|
this._sendError = err;
|
||||||
if ((err.statusCode ?? err.status) === 400) {
|
|
||||||
exc = new Error(`/join : '${roomName}' was not legal room ID or room alias`);
|
|
||||||
} else if ((err.statusCode ?? err.status) === 404 || (err.statusCode ?? err.status) === 502 || err.message == "Internal Server Error") {
|
|
||||||
exc = new Error(`/join : room '${roomName}' not found`);
|
|
||||||
} else if ((err.statusCode ?? err.status) === 403) {
|
|
||||||
exc = new Error(`/join : you're not invited to join '${roomName}'`);
|
|
||||||
} else {
|
|
||||||
exc = err;
|
|
||||||
}
|
|
||||||
this._sendError = exc;
|
|
||||||
this._timelineError = null;
|
this._timelineError = null;
|
||||||
this.emitChange("error");
|
this.emitChange("error");
|
||||||
}
|
}
|
||||||
|
42
src/matrix/room/joinRoom.ts
Normal file
42
src/matrix/room/joinRoom.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 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 type {Session} from "../Session.js";
|
||||||
|
import {RoomStatus} from "./common";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join a room and wait for it to arrive in the next sync
|
||||||
|
* @param roomId The id of the room to join
|
||||||
|
* @param session A session instance
|
||||||
|
*/
|
||||||
|
export async function joinRoom(roomId: string, session: Session): Promise<string> {
|
||||||
|
try {
|
||||||
|
const internalRoomId = await session.joinRoom(roomId);
|
||||||
|
const roomStatusObservable = await session.observeRoomStatus(internalRoomId);
|
||||||
|
await roomStatusObservable.waitFor((status: RoomStatus) => status === RoomStatus.Joined);
|
||||||
|
return internalRoomId;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if ((e.statusCode ?? e.status) === 400) {
|
||||||
|
throw new Error(`'${roomId}' is not a legal room ID or alias`);
|
||||||
|
} else if ((e.statusCode ?? e.status) === 404 || (e.statusCode ?? e.status) === 502 || e.message == "Internal Server eor") {
|
||||||
|
throw new Error(`Room '${roomId}' could not be found`);
|
||||||
|
} else if ((e.statusCode ?? e.status) === 403) {
|
||||||
|
throw new Error(`You are not invited to join '${roomId}'`);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1180,7 +1180,7 @@ button.RoomDetailsView_row::after {
|
|||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.CreateRoomView, .RoomBeingCreated_error {
|
.CreateRoomView, .JoinRoomView, .RoomBeingCreated_error {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1211,3 +1211,14 @@ button.RoomDetailsView_row::after {
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: 36px;
|
background-size: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.JoinRoomView_status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.JoinRoomView_status .spinner {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
63
src/platform/web/ui/session/JoinRoomView.ts
Normal file
63
src/platform/web/ui/session/JoinRoomView.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 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 {TemplateView} from "../general/TemplateView";
|
||||||
|
import type {JoinRoomViewModel} from "../../../../domain/session/JoinRoomViewModel";
|
||||||
|
import {spinner} from "../common.js";
|
||||||
|
|
||||||
|
export class JoinRoomView extends TemplateView<JoinRoomViewModel> {
|
||||||
|
render(t, vm) {
|
||||||
|
const input = t.input({
|
||||||
|
type: "text",
|
||||||
|
name: "id",
|
||||||
|
id: "id",
|
||||||
|
placeholder: vm.i18n`Enter a room id or alias`,
|
||||||
|
disabled: vm => vm.joinInProgress,
|
||||||
|
});
|
||||||
|
return t.main({className: "middle"},
|
||||||
|
t.div({className: "JoinRoomView centered-column"}, [
|
||||||
|
t.h2("Join room"),
|
||||||
|
t.form({className: "JoinRoomView_detailsForm form", onSubmit: evt => this.onSubmit(evt, input.value)}, [
|
||||||
|
t.div({className: "vertical-layout"}, [
|
||||||
|
t.div({className: "stretch form-row text"}, [
|
||||||
|
t.label({for: "id"}, vm.i18n`Room id`),
|
||||||
|
input,
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
t.div({className: "button-row"}, [
|
||||||
|
t.button({
|
||||||
|
className: "button-action primary",
|
||||||
|
type: "submit",
|
||||||
|
disabled: vm => vm.joinInProgress
|
||||||
|
}, vm.i18n`Join`),
|
||||||
|
]),
|
||||||
|
t.map(vm => vm.status, (status, t) => {
|
||||||
|
return t.div({ className: "JoinRoomView_status" }, [
|
||||||
|
spinner(t, { hidden: vm => !vm.joinInProgress }),
|
||||||
|
t.span(status),
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(evt, id) {
|
||||||
|
evt.preventDefault();
|
||||||
|
this.value.join(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ import {SettingsView} from "./settings/SettingsView.js";
|
|||||||
import {CreateRoomView} from "./CreateRoomView.js";
|
import {CreateRoomView} from "./CreateRoomView.js";
|
||||||
import {RightPanelView} from "./rightpanel/RightPanelView.js";
|
import {RightPanelView} from "./rightpanel/RightPanelView.js";
|
||||||
import {viewClassForTile} from "./room/common";
|
import {viewClassForTile} from "./room/common";
|
||||||
|
import {JoinRoomView} from "./JoinRoomView";
|
||||||
|
|
||||||
export class SessionView extends TemplateView {
|
export class SessionView extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
@ -48,6 +49,8 @@ export class SessionView extends TemplateView {
|
|||||||
return new SettingsView(vm.settingsViewModel);
|
return new SettingsView(vm.settingsViewModel);
|
||||||
} else if (vm.createRoomViewModel) {
|
} else if (vm.createRoomViewModel) {
|
||||||
return new CreateRoomView(vm.createRoomViewModel);
|
return new CreateRoomView(vm.createRoomViewModel);
|
||||||
|
} else if (vm.joinRoomViewModel) {
|
||||||
|
return new JoinRoomView(vm.joinRoomViewModel);
|
||||||
} else if (vm.currentRoomViewModel) {
|
} else if (vm.currentRoomViewModel) {
|
||||||
if (vm.currentRoomViewModel.kind === "invite") {
|
if (vm.currentRoomViewModel.kind === "invite") {
|
||||||
return new InviteView(vm.currentRoomViewModel);
|
return new InviteView(vm.currentRoomViewModel);
|
||||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
import {ListView} from "../../general/ListView";
|
import {ListView} from "../../general/ListView";
|
||||||
import {TemplateView} from "../../general/TemplateView";
|
import {TemplateView} from "../../general/TemplateView";
|
||||||
import {RoomTileView} from "./RoomTileView.js";
|
import {RoomTileView} from "./RoomTileView.js";
|
||||||
|
import {Menu} from "../../general/Menu.js";
|
||||||
|
import {Popup} from "../../general/Popup.js";
|
||||||
|
|
||||||
class FilterField extends TemplateView {
|
class FilterField extends TemplateView {
|
||||||
render(t, options) {
|
render(t, options) {
|
||||||
@ -51,6 +53,11 @@ class FilterField extends TemplateView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class LeftPanelView extends TemplateView {
|
export class LeftPanelView extends TemplateView {
|
||||||
|
constructor(vm) {
|
||||||
|
super(vm);
|
||||||
|
this._createMenuPopup = null;
|
||||||
|
}
|
||||||
|
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
const gridButtonLabel = vm => {
|
const gridButtonLabel = vm => {
|
||||||
return vm.gridEnabled ?
|
return vm.gridEnabled ?
|
||||||
@ -90,7 +97,11 @@ export class LeftPanelView extends TemplateView {
|
|||||||
"aria-label": gridButtonLabel
|
"aria-label": gridButtonLabel
|
||||||
}),
|
}),
|
||||||
t.a({className: "button-utility settings", href: vm.settingsUrl, "aria-label": vm.i18n`Settings`, title: vm.i18n`Settings`}),
|
t.a({className: "button-utility settings", href: vm.settingsUrl, "aria-label": vm.i18n`Settings`, title: vm.i18n`Settings`}),
|
||||||
t.a({className: "button-utility create", href: vm.createRoomUrl, "aria-label": vm.i18n`Create room`, title: vm.i18n`Create room`}),
|
t.button({
|
||||||
|
className: "button-utility create",
|
||||||
|
"aria-label": vm.i18n`Create room`,
|
||||||
|
onClick: evt => this._toggleCreateMenu(evt)
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return t.div({className: "LeftPanel"}, [
|
return t.div({className: "LeftPanel"}, [
|
||||||
@ -98,4 +109,18 @@ export class LeftPanelView extends TemplateView {
|
|||||||
roomList
|
roomList
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_toggleCreateMenu(evt) {
|
||||||
|
if (this._createMenuPopup && this._createMenuPopup.isOpen) {
|
||||||
|
this._createMenuPopup.close();
|
||||||
|
} else {
|
||||||
|
const vm = this.value;
|
||||||
|
const options = [];
|
||||||
|
options.push(Menu.option(vm.i18n`Create Room`, () => vm.showCreateRoomView()));
|
||||||
|
options.push(Menu.option(vm.i18n`Join Room`, () => vm.showJoinRoomView()));
|
||||||
|
this._createMenuPopup = new Popup(new Menu(options));
|
||||||
|
this._createMenuPopup.trackInTemplateView(this);
|
||||||
|
this._createMenuPopup.showRelativeTo(evt.target, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user