diff --git a/src/domain/session/CreateRoomViewModel.js b/src/domain/session/CreateRoomViewModel.js index b398b615..6e207e31 100644 --- a/src/domain/session/CreateRoomViewModel.js +++ b/src/domain/session/CreateRoomViewModel.js @@ -23,45 +23,60 @@ export class CreateRoomViewModel extends ViewModel { super(options); const {session} = options; this._session = session; - this._name = ""; - this._topic = ""; + this._name = undefined; + this._topic = undefined; + this._roomAlias = undefined; this._isPublic = false; this._isEncrypted = true; + this._isAdvancedShown = false; + this._isFederationDisabled = false; this._avatarScaledBlob = undefined; this._avatarFileName = undefined; this._avatarInfo = undefined; } + get isPublic() { return this._isPublic; } + get isEncrypted() { return this._isEncrypted; } + get canCreate() { return !!this._name; } + avatarUrl() { return this._avatarScaledBlob.url; } + get avatarTitle() { return this._name; } + get avatarLetter() { return ""; } + get avatarColorNumber() { return 0; } + get hasAvatar() { return !!this._avatarScaledBlob; } + get isFederationDisabled() { return this._isFederationDisabled; } + get isAdvancedShown() { return this._isAdvancedShown; } + setName(name) { this._name = name; - this.emitChange("name"); + this.emitChange("canCreate"); } - get name() { return this._name; } + setRoomAlias(roomAlias) { + this._roomAlias = roomAlias; + } setTopic(topic) { this._topic = topic; - this.emitChange("topic"); } - get topic() { return this._topic; } - setPublic(isPublic) { this._isPublic = isPublic; this.emitChange("isPublic"); } - get isPublic() { return this._isPublic; } - setEncrypted(isEncrypted) { this._isEncrypted = isEncrypted; this.emitChange("isEncrypted"); } - get isEncrypted() { return this._isEncrypted; } + setFederationDisabled(disable) { + this._isFederationDisabled = disable; + this.emitChange("isFederationDisabled"); + } - get canCreate() { - return !!this.name; + toggleAdvancedShown() { + this._isAdvancedShown = !this._isAdvancedShown; + this.emitChange("isAdvancedShown"); } create() { @@ -75,24 +90,16 @@ export class CreateRoomViewModel extends ViewModel { } const roomBeingCreated = this._session.createRoom({ type: this.isPublic ? RoomType.Public : RoomType.Private, - name: this.name ?? undefined, + name: this._name ?? undefined, topic: this.topic ?? undefined, isEncrypted: !this.isPublic && this._isEncrypted, - alias: this.isPublic ? this.roomAlias : undefined, + isFederationDisabled: this._isFederationDisabled, + alias: this.isPublic ? ensureAliasIsLocalPart(this._roomAlias) : undefined, avatar, - invites: ["@bwindels:matrix.org"] }); this.navigation.push("room", roomBeingCreated.id); } - - avatarUrl() { return this._avatarScaledBlob.url; } - get avatarTitle() { return this.name; } - get avatarLetter() { return ""; } - get avatarColorNumber() { return 0; } - get hasAvatar() { return !!this._avatarScaledBlob; } - get error() { return ""; } - async selectAvatar() { if (!this.platform.hasReadPixelPermission()) { alert("Please allow canvas image data access, so we can scale your images down."); @@ -124,3 +131,14 @@ export class CreateRoomViewModel extends ViewModel { this.emitChange("hasAvatar"); } } + +function ensureAliasIsLocalPart(roomAliasLocalPart) { + if (roomAliasLocalPart.startsWith("#")) { + roomAliasLocalPart = roomAliasLocalPart.substr(1); + } + const colonIdx = roomAliasLocalPart.indexOf(":"); + if (colonIdx !== -1) { + roomAliasLocalPart = roomAliasLocalPart.substr(0, colonIdx); + } + return roomAliasLocalPart; +} diff --git a/src/matrix/room/create.ts b/src/matrix/room/create.ts index 6a1fc947..c50aba6b 100644 --- a/src/matrix/room/create.ts +++ b/src/matrix/room/create.ts @@ -32,6 +32,7 @@ type CreateRoomPayload = { topic?: string; invite?: string[]; room_alias_name?: string; + creation_content?: {"m.federate": boolean}; initial_state: {type: string; state_key: string; content: Record}[] } @@ -51,6 +52,7 @@ type Avatar = { type Options = { type: RoomType; isEncrypted?: boolean; + isFederationDisabled?: boolean; name?: string; topic?: string; invites?: string[]; @@ -146,6 +148,11 @@ export class RoomBeingCreated extends EventEmitter<{change: never}> { if (this.options.alias) { createOptions.room_alias_name = this.options.alias; } + if (this.options.isFederationDisabled === true) { + createOptions.creation_content = { + "m.federate": false + }; + } if (this.isEncrypted) { createOptions.initial_state.push(createRoomEncryptionEvent()); } diff --git a/src/platform/web/ui/css/themes/element/theme.css b/src/platform/web/ui/css/themes/element/theme.css index 87d82485..a3fb12ee 100644 --- a/src/platform/web/ui/css/themes/element/theme.css +++ b/src/platform/web/ui/css/themes/element/theme.css @@ -111,6 +111,12 @@ limitations under the License. display: block; } +.form-row .form-row-description { + font-size: 1rem; + color: #777; + margin: 8px 0 0 0; +} + .button-action { cursor: pointer; } diff --git a/src/platform/web/ui/session/CreateRoomView.js b/src/platform/web/ui/session/CreateRoomView.js index c447710f..9d6c6bbc 100644 --- a/src/platform/web/ui/session/CreateRoomView.js +++ b/src/platform/web/ui/session/CreateRoomView.js @@ -44,7 +44,7 @@ export class CreateRoomView extends TemplateView { onInput: evt => vm.setName(evt.target.value), type: "text", name: "name", id: "name", placeholder: vm.i18n`Enter a room name` - }, vm => vm.name), + }), ]), ]), t.div({className: "form-row text"}, [ @@ -74,8 +74,18 @@ export class CreateRoomView extends TemplateView { t.input({ onInput: evt => vm.setRoomAlias(evt.target.value), type: "text", name: "roomAlias", id: "roomAlias", - placeholder: vm.i18n`Room alias - `}), + placeholder: vm.i18n`Room alias (, or # or #:hs.tld`}), + ]), + t.div({className: "form-group"}, [ + t.div(t.button({className: "link", type: "button", onClick: () => vm.toggleAdvancedShown()}, + vm => vm.isAdvancedShown ? vm.i18n`Hide advanced settings` : vm.i18n`Show advanced settings`)), + t.div({className: {"form-row check": true, hidden: vm => !vm.isAdvancedShown}}, [ + t.input({type: "checkbox", name: "isFederationDisabled", id: "isFederationDisabled", checked: vm.isFederationDisabled}), + t.label({for: "isFederationDisabled"}, [ + vm.i18n`Disable federation`, + t.p({className: "form-row-description"}, vm.i18n`Can't be changed later. This will prevent people on other homeservers from joining the room. This is typically used when only people from your own organisation (if applicable) should be allowed in the room, and is otherwise not needed.`) + ]), + ]), ]), t.div({className: "button-row"}, [ t.button({ @@ -97,6 +107,9 @@ export class CreateRoomView extends TemplateView { case "isPublic": this.value.setPublic(evt.currentTarget.isPublic.value === "true"); break; + case "isFederationDisabled": + this.value.setFederationDisabled(evt.target.checked); + break; } }