Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Weblate 2019-01-31 16:37:18 +00:00
commit 1990a4d39f
12 changed files with 143 additions and 150 deletions

View file

@ -36,7 +36,7 @@ limitations under the License.
color: $primary-fg-color; color: $primary-fg-color;
} }
.mx_Auth_editServerDetails { .mx_AuthBody_editServerDetails {
padding-left: 1em; padding-left: 1em;
font-size: 12px; font-size: 12px;
font-weight: normal; font-weight: normal;
@ -47,21 +47,21 @@ limitations under the License.
box-sizing: border-box; box-sizing: border-box;
} }
.mx_Auth_fieldRow { .mx_AuthBody_fieldRow {
display: flex; display: flex;
margin-bottom: 10px; margin-bottom: 10px;
} }
.mx_Auth_fieldRow > * { .mx_AuthBody_fieldRow > * {
margin: 0 5px; margin: 0 5px;
flex: 1; flex: 1;
} }
.mx_Auth_fieldRow > *:first-child { .mx_AuthBody_fieldRow > *:first-child {
margin-left: 0; margin-left: 0;
} }
.mx_Auth_fieldRow > *:last-child { .mx_AuthBody_fieldRow > *:last-child {
margin-right: 0; margin-right: 0;
} }
@ -72,7 +72,7 @@ limitations under the License.
text-decoration: none; text-decoration: none;
} }
.mx_Auth_changeFlow { .mx_AuthBody_changeFlow {
display: block; display: block;
text-align: center; text-align: center;
width: 100%; width: 100%;

View file

@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_Auth_language { .mx_AuthBody_language {
width: 100%; width: 100%;
} }
.mx_Auth_language .mx_Dropdown_input { .mx_AuthBody_language .mx_Dropdown_input {
border: none; border: none;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: $authpage-lang-color; color: $authpage-lang-color;
} }
.mx_Auth_language .mx_Dropdown_arrow { .mx_AuthBody_language .mx_Dropdown_arrow {
background: $authpage-lang-color; background: $authpage-lang-color;
} }

View file

@ -1,27 +0,0 @@
/*
Copyright 2016 OpenMarket Ltd
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.
*/
/**
* Functions for applying common thematic effects to UI elements.
* Ideally this would be themeable.
*/
import Velocity from 'velocity-vector';
import 'velocity-vector/velocity.ui';
export function fieldInputIncorrect(element) {
Velocity(element, "callout.shake", 300);
}

View file

@ -1892,7 +1892,6 @@ export default React.createClass({
idSid={this.state.register_id_sid} idSid={this.state.register_id_sid}
email={this.props.startingFragmentQueryParams.email} email={this.props.startingFragmentQueryParams.email}
referrer={this.props.startingFragmentQueryParams.referrer} referrer={this.props.startingFragmentQueryParams.referrer}
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError} defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()} defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()} defaultIsUrl={this.getDefaultIsUrl()}
@ -1932,7 +1931,6 @@ export default React.createClass({
<Login <Login
onLoggedIn={Lifecycle.setLoggedIn} onLoggedIn={Lifecycle.setLoggedIn}
onRegisterClick={this.onRegisterClick} onRegisterClick={this.onRegisterClick}
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError} defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()} defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()} defaultIsUrl={this.getDefaultIsUrl()}

View file

@ -255,7 +255,7 @@ module.exports = React.createClass({
</form> </form>
{ serverConfigSection } { serverConfigSection }
{ errorText } { errorText }
<a className="mx_Auth_changeFlow" onClick={this.onLoginClick} href="#"> <a className="mx_AuthBody_changeFlow" onClick={this.onLoginClick} href="#">
{ _t('Sign in instead') } { _t('Sign in instead') }
</a> </a>
</div> </div>

View file

@ -66,10 +66,6 @@ module.exports = React.createClass({
// different home server without confusing users. // different home server without confusing users.
fallbackHsUrl: PropTypes.string, fallbackHsUrl: PropTypes.string,
// The default server name to use when the user hasn't specified
// one. This is used when displaying the defaultHsUrl in the UI.
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something // An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl. // went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string, defaultServerDiscoveryError: PropTypes.string,
@ -265,7 +261,10 @@ module.exports = React.createClass({
}, },
onUsernameBlur: function(username) { onUsernameBlur: function(username) {
this.setState({ username: username }); this.setState({
username: username,
discoveryError: null,
});
if (username[0] === "@") { if (username[0] === "@") {
const serverName = username.split(':').slice(1).join(':'); const serverName = username.split(':').slice(1).join(':');
try { try {
@ -285,16 +284,22 @@ module.exports = React.createClass({
}, },
onPhoneNumberChanged: function(phoneNumber) { onPhoneNumberChanged: function(phoneNumber) {
// Validate the phone number entered
if (!PHONE_NUMBER_REGEX.test(phoneNumber)) {
this.setState({ errorText: _t('The phone number entered looks invalid') });
return;
}
this.setState({ this.setState({
phoneNumber: phoneNumber, phoneNumber: phoneNumber,
});
},
onPhoneNumberBlur: function(phoneNumber) {
this.setState({
errorText: null, errorText: null,
}); });
// Validate the phone number entered
if (!PHONE_NUMBER_REGEX.test(phoneNumber)) {
this.setState({
errorText: _t('The phone number entered looks invalid'),
});
}
}, },
onServerConfigChange: function(config) { onServerConfigChange: function(config) {
@ -571,7 +576,7 @@ module.exports = React.createClass({
defaultHsUrl={this.props.defaultHsUrl} defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl} defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange} onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000} delayTimeMs={250}
/>; />;
break; break;
case ServerType.ADVANCED: case ServerType.ADVANCED:
@ -581,7 +586,7 @@ module.exports = React.createClass({
defaultHsUrl={this.props.defaultHsUrl} defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl} defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange} onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000} delayTimeMs={250}
/>; />;
break; break;
} }
@ -649,10 +654,10 @@ module.exports = React.createClass({
onUsernameBlur={this.onUsernameBlur} onUsernameBlur={this.onUsernameBlur}
onPhoneCountryChanged={this.onPhoneCountryChanged} onPhoneCountryChanged={this.onPhoneCountryChanged}
onPhoneNumberChanged={this.onPhoneNumberChanged} onPhoneNumberChanged={this.onPhoneNumberChanged}
onPhoneNumberBlur={this.onPhoneNumberBlur}
onForgotPasswordClick={this.props.onForgotPasswordClick} onForgotPasswordClick={this.props.onForgotPasswordClick}
loginIncorrect={this.state.loginIncorrect} loginIncorrect={this.state.loginIncorrect}
hsUrl={this.state.enteredHomeserverUrl} hsUrl={this.state.enteredHomeserverUrl}
hsName={this.props.defaultServerName}
disableSubmit={this.state.findingHomeserver} disableSubmit={this.state.findingHomeserver}
/> />
); );
@ -684,7 +689,7 @@ module.exports = React.createClass({
let loginAsGuestJsx; let loginAsGuestJsx;
if (this.props.enableGuest) { if (this.props.enableGuest) {
loginAsGuestJsx = loginAsGuestJsx =
<a className="mx_Auth_changeFlow" onClick={this._onLoginAsGuestClick} href="#"> <a className="mx_AuthBody_changeFlow" onClick={this._onLoginAsGuestClick} href="#">
{ _t('Try the app first') } { _t('Try the app first') }
</a>; </a>;
} }
@ -709,7 +714,7 @@ module.exports = React.createClass({
{ errorTextSection } { errorTextSection }
{ this.renderServerComponentForStep() } { this.renderServerComponentForStep() }
{ this.renderLoginComponentForStep() } { this.renderLoginComponentForStep() }
<a className="mx_Auth_changeFlow" onClick={this.onRegisterClick} href="#"> <a className="mx_AuthBody_changeFlow" onClick={this.onRegisterClick} href="#">
{ _t('Create account') } { _t('Create account') }
</a> </a>
{ loginAsGuestJsx } { loginAsGuestJsx }

View file

@ -56,10 +56,6 @@ module.exports = React.createClass({
email: PropTypes.string, email: PropTypes.string,
referrer: PropTypes.string, referrer: PropTypes.string,
// The default server name to use when the user hasn't specified
// one. This is used when displaying the defaultHsUrl in the UI.
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something // An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl. // went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string, defaultServerDiscoveryError: PropTypes.string,
@ -151,6 +147,9 @@ module.exports = React.createClass({
}, },
_replaceClient: async function() { _replaceClient: async function() {
this.setState({
errorText: null,
});
this._matrixClient = Matrix.createClient({ this._matrixClient = Matrix.createClient({
baseUrl: this.state.hsUrl, baseUrl: this.state.hsUrl,
idBaseUrl: this.state.isUrl, idBaseUrl: this.state.isUrl,
@ -390,7 +389,7 @@ module.exports = React.createClass({
defaultHsUrl={this.props.defaultHsUrl} defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl} defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange} onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000} delayTimeMs={250}
/>; />;
break; break;
case ServerType.ADVANCED: case ServerType.ADVANCED:
@ -400,7 +399,7 @@ module.exports = React.createClass({
defaultHsUrl={this.props.defaultHsUrl} defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl} defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange} onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000} delayTimeMs={250}
/>; />;
break; break;
} }
@ -470,7 +469,6 @@ module.exports = React.createClass({
onEditServerDetailsClick={onEditServerDetailsClick} onEditServerDetailsClick={onEditServerDetailsClick}
flows={this.state.flows} flows={this.state.flows}
hsUrl={this.state.hsUrl} hsUrl={this.state.hsUrl}
hsName={this.props.defaultServerName}
/>; />;
} }
}, },
@ -489,7 +487,7 @@ module.exports = React.createClass({
let signIn; let signIn;
if (!this.state.doingUIAuth) { if (!this.state.doingUIAuth) {
signIn = ( signIn = (
<a className="mx_Auth_changeFlow" onClick={this.onLoginClick} href="#"> <a className="mx_AuthBody_changeFlow" onClick={this.onLoginClick} href="#">
{ _t('Sign in instead') } { _t('Sign in instead') }
</a> </a>
); );

View file

@ -32,7 +32,7 @@ export default function LanguageSelector() {
if (SdkConfig.get()['disable_login_language_selector']) return <div />; if (SdkConfig.get()['disable_login_language_selector']) return <div />;
const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown');
return <LanguageDropdown className="mx_Auth_language" return <LanguageDropdown className="mx_AuthBody_language"
onOptionChange={onChange} onOptionChange={onChange}
value={getCurrentLanguage()} value={getCurrentLanguage()}
/>; />;

View file

@ -77,17 +77,18 @@ export default class ModularServerConfig extends React.PureComponent {
}); });
} }
onHomeserverChanged = (ev) => { onHomeserverBlur = (ev) => {
this.setState({hsUrl: ev.target.value}, () => {
this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => {
let hsUrl = this.state.hsUrl.trim().replace(/\/$/, "");
if (hsUrl === "") hsUrl = this.props.defaultHsUrl;
this.props.onServerConfigChange({ this.props.onServerConfigChange({
hsUrl: this.state.hsUrl, hsUrl: this.state.hsUrl,
isUrl: this.props.defaultIsUrl, isUrl: this.props.defaultIsUrl,
}); });
}); });
}); }
onHomeserverChange = (ev) => {
const hsUrl = ev.target.value;
this.setState({ hsUrl });
} }
_waitThenInvoke(existingTimeoutId, fn) { _waitThenInvoke(existingTimeoutId, fn) {
@ -117,7 +118,8 @@ export default class ModularServerConfig extends React.PureComponent {
label={_t("Server Name")} label={_t("Server Name")}
placeholder={this.props.defaultHsUrl} placeholder={this.props.defaultHsUrl}
value={this.state.hsUrl} value={this.state.hsUrl}
onChange={this.onHomeserverChanged} onBlur={this.onHomeserverBlur}
onChange={this.onHomeserverChange}
/> />
</div> </div>
</div> </div>

View file

@ -20,7 +20,6 @@ import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import sdk from '../../../index'; import sdk from '../../../index';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import {fieldInputIncorrect} from '../../../UiEffects';
import SdkConfig from '../../../SdkConfig'; import SdkConfig from '../../../SdkConfig';
/** /**
@ -35,13 +34,13 @@ class PasswordLogin extends React.Component {
onPasswordChanged: function() {}, onPasswordChanged: function() {},
onPhoneCountryChanged: function() {}, onPhoneCountryChanged: function() {},
onPhoneNumberChanged: function() {}, onPhoneNumberChanged: function() {},
onPhoneNumberBlur: function() {},
initialUsername: "", initialUsername: "",
initialPhoneCountry: "", initialPhoneCountry: "",
initialPhoneNumber: "", initialPhoneNumber: "",
initialPassword: "", initialPassword: "",
loginIncorrect: false, loginIncorrect: false,
hsUrl: "", hsUrl: "",
hsName: null,
disableSubmit: false, disableSubmit: false,
} }
@ -61,6 +60,7 @@ class PasswordLogin extends React.Component {
this.onLoginTypeChange = this.onLoginTypeChange.bind(this); this.onLoginTypeChange = this.onLoginTypeChange.bind(this);
this.onPhoneCountryChanged = this.onPhoneCountryChanged.bind(this); this.onPhoneCountryChanged = this.onPhoneCountryChanged.bind(this);
this.onPhoneNumberChanged = this.onPhoneNumberChanged.bind(this); this.onPhoneNumberChanged = this.onPhoneNumberChanged.bind(this);
this.onPhoneNumberBlur = this.onPhoneNumberBlur.bind(this);
this.onPasswordChanged = this.onPasswordChanged.bind(this); this.onPasswordChanged = this.onPasswordChanged.bind(this);
this.isLoginEmpty = this.isLoginEmpty.bind(this); this.isLoginEmpty = this.isLoginEmpty.bind(this);
} }
@ -70,12 +70,6 @@ class PasswordLogin extends React.Component {
this._loginField = null; this._loginField = null;
} }
componentWillReceiveProps(nextProps) {
if (!this.props.loginIncorrect && nextProps.loginIncorrect) {
fieldInputIncorrect(this.isLoginEmpty() ? this._loginField : this._passwordField);
}
}
onSubmitForm(ev) { onSubmitForm(ev) {
ev.preventDefault(); ev.preventDefault();
@ -130,7 +124,7 @@ class PasswordLogin extends React.Component {
} }
onUsernameBlur(ev) { onUsernameBlur(ev) {
this.props.onUsernameBlur(this.state.username); this.props.onUsernameBlur(ev.target.value);
} }
onLoginTypeChange(loginType) { onLoginTypeChange(loginType) {
@ -154,6 +148,10 @@ class PasswordLogin extends React.Component {
this.props.onPhoneNumberChanged(ev.target.value); this.props.onPhoneNumberChanged(ev.target.value);
} }
onPhoneNumberBlur(ev) {
this.props.onPhoneNumberBlur(ev.target.value);
}
onPasswordChanged(ev) { onPasswordChanged(ev) {
this.setState({password: ev.target.value}); this.setState({password: ev.target.value});
this.props.onPasswordChanged(ev.target.value); this.props.onPasswordChanged(ev.target.value);
@ -215,6 +213,7 @@ class PasswordLogin extends React.Component {
type="text" type="text"
name="phoneNumber" name="phoneNumber"
onChange={this.onPhoneNumberChanged} onChange={this.onPhoneNumberChanged}
onBlur={this.onPhoneNumberBlur}
placeholder={_t("Mobile phone number")} placeholder={_t("Mobile phone number")}
value={this.state.phoneNumber} value={this.state.phoneNumber}
autoFocus autoFocus
@ -251,20 +250,18 @@ class PasswordLogin extends React.Component {
} }
let yourMatrixAccountText = _t('Your account'); let yourMatrixAccountText = _t('Your account');
if (this.props.hsName) {
yourMatrixAccountText = _t('Your %(serverName)s account', {serverName: this.props.hsName});
} else {
try { try {
const parsedHsUrl = new URL(this.props.hsUrl); const parsedHsUrl = new URL(this.props.hsUrl);
yourMatrixAccountText = _t('Your %(serverName)s account', {serverName: parsedHsUrl.hostname}); yourMatrixAccountText = _t('Your %(serverName)s account', {
serverName: parsedHsUrl.hostname,
});
} catch (e) { } catch (e) {
// ignore // ignore
} }
}
let editLink = null; let editLink = null;
if (this.props.onEditServerDetailsClick) { if (this.props.onEditServerDetailsClick) {
editLink = <a className="mx_Auth_editServerDetails" editLink = <a className="mx_AuthBody_editServerDetails"
href="#" onClick={this.props.onEditServerDetailsClick} href="#" onClick={this.props.onEditServerDetailsClick}
> >
{_t('Edit')} {_t('Edit')}
@ -341,7 +338,6 @@ PasswordLogin.propTypes = {
onPhoneNumberChanged: PropTypes.func, onPhoneNumberChanged: PropTypes.func,
onPasswordChanged: PropTypes.func, onPasswordChanged: PropTypes.func,
loginIncorrect: PropTypes.bool, loginIncorrect: PropTypes.bool,
hsName: PropTypes.string,
disableSubmit: PropTypes.bool, disableSubmit: PropTypes.bool,
}; };

View file

@ -18,7 +18,6 @@ limitations under the License.
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { fieldInputIncorrect } from '../../../UiEffects';
import sdk from '../../../index'; import sdk from '../../../index';
import Email from '../../../email'; import Email from '../../../email';
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber'; import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
@ -51,6 +50,7 @@ module.exports = React.createClass({
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
onEditServerDetailsClick: PropTypes.func, onEditServerDetailsClick: PropTypes.func,
flows: PropTypes.arrayOf(PropTypes.object).isRequired, flows: PropTypes.arrayOf(PropTypes.object).isRequired,
hsUrl: PropTypes.string,
}, },
getDefaultProps: function() { getDefaultProps: function() {
@ -78,11 +78,11 @@ module.exports = React.createClass({
// is the one from the first invalid field. // is the one from the first invalid field.
// It's not super ideal that this just calls // It's not super ideal that this just calls
// onError once for each invalid field. // onError once for each invalid field.
this.validateField(FIELD_PASSWORD_CONFIRM); this.validateField(FIELD_PASSWORD_CONFIRM, ev.type);
this.validateField(FIELD_PASSWORD); this.validateField(FIELD_PASSWORD, ev.type);
this.validateField(FIELD_USERNAME); this.validateField(FIELD_USERNAME, ev.type);
this.validateField(FIELD_PHONE_NUMBER); this.validateField(FIELD_PHONE_NUMBER, ev.type);
this.validateField(FIELD_EMAIL); this.validateField(FIELD_EMAIL, ev.type);
const self = this; const self = this;
if (this.allFieldsValid()) { if (this.allFieldsValid()) {
@ -139,9 +139,10 @@ module.exports = React.createClass({
return true; return true;
}, },
validateField: function(fieldID) { validateField: function(fieldID, eventType) {
const pwd1 = this.refs.password.value.trim(); const pwd1 = this.refs.password.value.trim();
const pwd2 = this.refs.passwordConfirm.value.trim(); const pwd2 = this.refs.passwordConfirm.value.trim();
const allowEmpty = eventType === "blur";
switch (fieldID) { switch (fieldID) {
case FIELD_EMAIL: { case FIELD_EMAIL: {
@ -162,7 +163,9 @@ module.exports = React.createClass({
} }
case FIELD_USERNAME: { case FIELD_USERNAME: {
const username = this.refs.username.value.trim(); const username = this.refs.username.value.trim();
if (!SAFE_LOCALPART_REGEX.test(username)) { if (allowEmpty && username === '') {
this.markFieldValid(fieldID, true);
} else if (!SAFE_LOCALPART_REGEX.test(username)) {
this.markFieldValid( this.markFieldValid(
fieldID, fieldID,
false, false,
@ -180,7 +183,9 @@ module.exports = React.createClass({
break; break;
} }
case FIELD_PASSWORD: case FIELD_PASSWORD:
if (pwd1 == '') { if (allowEmpty && pwd1 === "") {
this.markFieldValid(fieldID, true);
} else if (pwd1 == '') {
this.markFieldValid( this.markFieldValid(
fieldID, fieldID,
false, false,
@ -210,7 +215,6 @@ module.exports = React.createClass({
fieldValid[fieldID] = val; fieldValid[fieldID] = val;
this.setState({fieldValid: fieldValid}); this.setState({fieldValid: fieldValid});
if (!val) { if (!val) {
fieldInputIncorrect(this.fieldElementById(fieldID));
this.props.onError(errorCode); this.props.onError(errorCode);
} }
}, },
@ -239,13 +243,33 @@ module.exports = React.createClass({
return cls; return cls;
}, },
_onPhoneCountryChange(newVal) { onEmailBlur(ev) {
this.validateField(FIELD_EMAIL, ev.type);
},
onPasswordBlur(ev) {
this.validateField(FIELD_PASSWORD, ev.type);
},
onPasswordConfirmBlur(ev) {
this.validateField(FIELD_PASSWORD_CONFIRM, ev.type);
},
onPhoneCountryChange(newVal) {
this.setState({ this.setState({
phoneCountry: newVal.iso2, phoneCountry: newVal.iso2,
phonePrefix: newVal.prefix, phonePrefix: newVal.prefix,
}); });
}, },
onPhoneNumberBlur(ev) {
this.validateField(FIELD_PHONE_NUMBER, ev.type);
},
onUsernameBlur(ev) {
this.validateField(FIELD_USERNAME, ev.type);
},
_authStepIsRequired(step) { _authStepIsRequired(step) {
// A step is required if no flow exists which does not include that step // A step is required if no flow exists which does not include that step
// (Notwithstanding setups like either email or msisdn being required) // (Notwithstanding setups like either email or msisdn being required)
@ -255,14 +279,7 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
const self = this;
let yourMatrixAccountText = _t('Create your account'); let yourMatrixAccountText = _t('Create your account');
if (this.props.hsName) {
yourMatrixAccountText = _t('Create your %(serverName)s account', {
serverName: this.props.hsName,
});
} else {
try { try {
const parsedHsUrl = new URL(this.props.hsUrl); const parsedHsUrl = new URL(this.props.hsUrl);
yourMatrixAccountText = _t('Create your %(serverName)s account', { yourMatrixAccountText = _t('Create your %(serverName)s account', {
@ -271,11 +288,10 @@ module.exports = React.createClass({
} catch (e) { } catch (e) {
// ignore // ignore
} }
}
let editLink = null; let editLink = null;
if (this.props.onEditServerDetailsClick) { if (this.props.onEditServerDetailsClick) {
editLink = <a className="mx_Auth_editServerDetails" editLink = <a className="mx_AuthBody_editServerDetails"
href="#" onClick={this.props.onEditServerDetailsClick} href="#" onClick={this.props.onEditServerDetailsClick}
> >
{_t('Edit')} {_t('Edit')}
@ -292,8 +308,8 @@ module.exports = React.createClass({
autoFocus={true} placeholder={emailPlaceholder} autoFocus={true} placeholder={emailPlaceholder}
defaultValue={this.props.defaultEmail} defaultValue={this.props.defaultEmail}
className={this._classForField(FIELD_EMAIL, 'mx_Login_field')} className={this._classForField(FIELD_EMAIL, 'mx_Login_field')}
onBlur={function() {self.validateField(FIELD_EMAIL);}} onBlur={this.onEmailBlur}
value={self.state.email} /> value={this.state.email} />
</div> </div>
); );
@ -305,11 +321,12 @@ module.exports = React.createClass({
_t("Phone (optional)"); _t("Phone (optional)");
phoneSection = ( phoneSection = (
<div className="mx_Login_phoneSection"> <div className="mx_Login_phoneSection">
<CountryDropdown ref="phone_country" onOptionChange={this._onPhoneCountryChange} <CountryDropdown ref="phone_country"
className="mx_Login_phoneCountry mx_Login_field_prefix" className="mx_Login_phoneCountry mx_Login_field_prefix"
value={this.state.phoneCountry} value={this.state.phoneCountry}
isSmall={true} isSmall={true}
showPrefix={true} showPrefix={true}
onOptionChange={this.onPhoneCountryChange}
/> />
<input type="text" ref="phoneNumber" <input type="text" ref="phoneNumber"
placeholder={phonePlaceholder} placeholder={phonePlaceholder}
@ -320,8 +337,8 @@ module.exports = React.createClass({
'mx_Login_field', 'mx_Login_field',
'mx_Login_field_has_prefix', 'mx_Login_field_has_prefix',
)} )}
onBlur={function() {self.validateField(FIELD_PHONE_NUMBER);}} onBlur={this.onPhoneNumberBlur}
value={self.state.phoneNumber} value={this.state.phoneNumber}
/> />
</div> </div>
); );
@ -340,24 +357,24 @@ module.exports = React.createClass({
{editLink} {editLink}
</h3> </h3>
<form onSubmit={this.onSubmit}> <form onSubmit={this.onSubmit}>
<div className="mx_Auth_fieldRow"> <div className="mx_AuthBody_fieldRow">
<input type="text" ref="username" <input type="text" ref="username"
placeholder={placeholderUsername} defaultValue={this.props.defaultUsername} placeholder={placeholderUsername} defaultValue={this.props.defaultUsername}
className={this._classForField(FIELD_USERNAME, 'mx_Login_field')} className={this._classForField(FIELD_USERNAME, 'mx_Login_field')}
onBlur={function() {self.validateField(FIELD_USERNAME);}} /> onBlur={this.onUsernameBlur} />
</div> </div>
<div className="mx_Auth_fieldRow"> <div className="mx_AuthBody_fieldRow">
<input type="password" ref="password" <input type="password" ref="password"
className={this._classForField(FIELD_PASSWORD, 'mx_Login_field')} className={this._classForField(FIELD_PASSWORD, 'mx_Login_field')}
onBlur={function() {self.validateField(FIELD_PASSWORD);}} onBlur={this.onPasswordBlur}
placeholder={_t("Password")} defaultValue={this.props.defaultPassword} /> placeholder={_t("Password")} defaultValue={this.props.defaultPassword} />
<input type="password" ref="passwordConfirm" <input type="password" ref="passwordConfirm"
placeholder={_t("Confirm")} placeholder={_t("Confirm")}
className={this._classForField(FIELD_PASSWORD_CONFIRM, 'mx_Login_field')} className={this._classForField(FIELD_PASSWORD_CONFIRM, 'mx_Login_field')}
onBlur={function() {self.validateField(FIELD_PASSWORD_CONFIRM);}} onBlur={this.onPasswordConfirmBlur}
defaultValue={this.props.defaultPassword} /> defaultValue={this.props.defaultPassword} />
</div> </div>
<div className="mx_Auth_fieldRow"> <div className="mx_AuthBody_fieldRow">
{ emailSection } { emailSection }
{ phoneSection } { phoneSection }
</div> </div>

View file

@ -76,30 +76,32 @@ export default class ServerConfig extends React.PureComponent {
}); });
} }
onHomeserverChanged = (ev) => { onHomeserverBlur = (ev) => {
this.setState({hsUrl: ev.target.value}, () => {
this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => {
let hsUrl = this.state.hsUrl.trim().replace(/\/$/, "");
if (hsUrl === "") hsUrl = this.props.defaultHsUrl;
this.props.onServerConfigChange({ this.props.onServerConfigChange({
hsUrl: this.state.hsUrl, hsUrl: this.state.hsUrl,
isUrl: this.state.isUrl, isUrl: this.state.isUrl,
}); });
}); });
});
} }
onIdentityServerChanged = (ev) => { onHomeserverChange = (ev) => {
this.setState({isUrl: ev.target.value}, () => { const hsUrl = ev.target.value;
this.setState({ hsUrl });
}
onIdentityServerBlur = (ev) => {
this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, () => { this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, () => {
let isUrl = this.state.isUrl.trim().replace(/\/$/, "");
if (isUrl === "") isUrl = this.props.defaultIsUrl;
this.props.onServerConfigChange({ this.props.onServerConfigChange({
hsUrl: this.state.hsUrl, hsUrl: this.state.hsUrl,
isUrl: this.state.isUrl, isUrl: this.state.isUrl,
}); });
}); });
}); }
onIdentityServerChange = (ev) => {
const isUrl = ev.target.value;
this.setState({ isUrl });
} }
_waitThenInvoke(existingTimeoutId, fn) { _waitThenInvoke(existingTimeoutId, fn) {
@ -130,13 +132,15 @@ export default class ServerConfig extends React.PureComponent {
label={_t("Homeserver URL")} label={_t("Homeserver URL")}
placeholder={this.props.defaultHsUrl} placeholder={this.props.defaultHsUrl}
value={this.state.hsUrl} value={this.state.hsUrl}
onChange={this.onHomeserverChanged} onBlur={this.onHomeserverBlur}
onChange={this.onHomeserverChange}
/> />
<Field id="mx_ServerConfig_isUrl" <Field id="mx_ServerConfig_isUrl"
label={_t("Identity Server URL")} label={_t("Identity Server URL")}
placeholder={this.props.defaultIsUrl} placeholder={this.props.defaultIsUrl}
value={this.state.isUrl} value={this.state.isUrl}
onChange={this.onIdentityServerChanged} onBlur={this.onIdentityServerBlur}
onChange={this.onIdentityServerChange}
/> />
</div> </div>
</div> </div>