Convert RoomAliasField to Typescript

This commit is contained in:
Michael Telatynski 2021-06-07 08:54:41 +01:00
parent 12e013508d
commit b2b95257a8
3 changed files with 48 additions and 36 deletions

View file

@ -29,6 +29,11 @@ function getId() {
return `${BASE_ID}_${count++}`; return `${BASE_ID}_${count++}`;
} }
export interface IValidateOpts {
focused?: boolean;
allowEmpty?: boolean;
}
interface IProps { interface IProps {
// The field's ID, which binds the input and label together. Immutable. // The field's ID, which binds the input and label together. Immutable.
id?: string; id?: string;
@ -180,7 +185,7 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
} }
}; };
public async validate({ focused, allowEmpty = true }: {focused?: boolean, allowEmpty?: boolean}) { public async validate({ focused, allowEmpty = true }: IValidateOpts) {
if (!this.props.onValidate) { if (!this.props.onValidate) {
return; return;
} }

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2019 New Vector Ltd Copyright 2019, 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -13,67 +13,74 @@ 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, { createRef } from "react";
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import withValidation from './Validation'; import withValidation from './Validation';
import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { MatrixClientPeg } from '../../../MatrixClientPeg';
import {replaceableComponent} from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import Field, { IValidateOpts } from "./Field";
interface IProps {
domain: string;
value: string;
label?: string;
placeholder?: string;
onChange?(value: string): void;
}
interface IState {
isValid: boolean;
}
// Controlled form component wrapping Field for inputting a room alias scoped to a given domain // Controlled form component wrapping Field for inputting a room alias scoped to a given domain
@replaceableComponent("views.elements.RoomAliasField") @replaceableComponent("views.elements.RoomAliasField")
export default class RoomAliasField extends React.PureComponent { export default class RoomAliasField extends React.PureComponent<IProps, IState> {
static propTypes = { private fieldRef = createRef<Field>();
domain: PropTypes.string.isRequired,
onChange: PropTypes.func, public state = {
value: PropTypes.string.isRequired, isValid: true,
}; };
constructor(props) { private asFullAlias(localpart: string): string {
super(props);
this.state = {isValid: true};
}
_asFullAlias(localpart) {
return `#${localpart}:${this.props.domain}`; return `#${localpart}:${this.props.domain}`;
} }
render() { render() {
const Field = sdk.getComponent('views.elements.Field');
const poundSign = (<span>#</span>); const poundSign = (<span>#</span>);
const aliasPostfix = ":" + this.props.domain; const aliasPostfix = ":" + this.props.domain;
const domain = (<span title={aliasPostfix}>{aliasPostfix}</span>); const domain = (<span title={aliasPostfix}>{aliasPostfix}</span>);
const maxlength = 255 - this.props.domain.length - 2; // 2 for # and : const maxlength = 255 - this.props.domain.length - 2; // 2 for # and :
return ( return (
<Field <Field
label={_t("Room address")} label={this.props.label || _t("Room address")}
className="mx_RoomAliasField" className="mx_RoomAliasField"
prefixComponent={poundSign} prefixComponent={poundSign}
postfixComponent={domain} postfixComponent={domain}
ref={ref => this._fieldRef = ref} ref={this.fieldRef}
onValidate={this._onValidate} onValidate={this.onValidate}
placeholder={_t("e.g. my-room")} placeholder={this.props.placeholder || _t("e.g. my-room")}
onChange={this._onChange} onChange={this.onChange}
value={this.props.value.substring(1, this.props.value.length - this.props.domain.length - 1)} value={this.props.value.substring(1, this.props.value.length - this.props.domain.length - 1)}
maxLength={maxlength} maxLength={maxlength}
/> />
); );
} }
_onChange = (ev) => { private onChange = (ev) => {
if (this.props.onChange) { if (this.props.onChange) {
this.props.onChange(this._asFullAlias(ev.target.value)); this.props.onChange(this.asFullAlias(ev.target.value));
} }
}; };
_onValidate = async (fieldState) => { private onValidate = async (fieldState) => {
const result = await this._validationRules(fieldState); const result = await this.validationRules(fieldState);
this.setState({isValid: result.valid}); this.setState({isValid: result.valid});
return result; return result;
}; };
_validationRules = withValidation({ private validationRules = withValidation({
rules: [ rules: [
{ {
key: "safeLocalpart", key: "safeLocalpart",
@ -81,7 +88,7 @@ export default class RoomAliasField extends React.PureComponent {
if (!value) { if (!value) {
return true; return true;
} }
const fullAlias = this._asFullAlias(value); const fullAlias = this.asFullAlias(value);
// XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668 // XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
return !value.includes("#") && !value.includes(":") && !value.includes(",") && return !value.includes("#") && !value.includes(":") && !value.includes(",") &&
encodeURI(fullAlias) === fullAlias; encodeURI(fullAlias) === fullAlias;
@ -90,7 +97,7 @@ export default class RoomAliasField extends React.PureComponent {
}, { }, {
key: "required", key: "required",
test: async ({ value, allowEmpty }) => allowEmpty || !!value, test: async ({ value, allowEmpty }) => allowEmpty || !!value,
invalid: () => _t("Please provide a room address"), invalid: () => _t("Please provide an address"),
}, { }, {
key: "taken", key: "taken",
final: true, final: true,
@ -100,7 +107,7 @@ export default class RoomAliasField extends React.PureComponent {
} }
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
try { try {
await client.getRoomIdForAlias(this._asFullAlias(value)); await client.getRoomIdForAlias(this.asFullAlias(value));
// we got a room id, so the alias is taken // we got a room id, so the alias is taken
return false; return false;
} catch (err) { } catch (err) {
@ -120,11 +127,11 @@ export default class RoomAliasField extends React.PureComponent {
return this.state.isValid; return this.state.isValid;
} }
validate(options) { validate(options: IValidateOpts) {
return this._fieldRef.validate(options); return this.fieldRef.current?.validate(options);
} }
focus() { focus() {
this._fieldRef.focus(); this.fieldRef.current?.focus();
} }
} }

View file

@ -2014,7 +2014,7 @@
"Room address": "Room address", "Room address": "Room address",
"e.g. my-room": "e.g. my-room", "e.g. my-room": "e.g. my-room",
"Some characters not allowed": "Some characters not allowed", "Some characters not allowed": "Some characters not allowed",
"Please provide a room address": "Please provide a room address", "Please provide an address": "Please provide an address",
"This address is available to use": "This address is available to use", "This address is available to use": "This address is available to use",
"This address is already in use": "This address is already in use", "This address is already in use": "This address is already in use",
"Server Options": "Server Options", "Server Options": "Server Options",