diff --git a/res/css/_components.scss b/res/css/_components.scss
index 6e681894e3..ff22ad9eab 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -97,6 +97,7 @@
@import "./views/elements/_RoleButton.scss";
@import "./views/elements/_Spinner.scss";
@import "./views/elements/_SyntaxHighlight.scss";
+@import "./views/elements/_TextWithTooltip.scss";
@import "./views/elements/_ToggleSwitch.scss";
@import "./views/elements/_ToolTipButton.scss";
@import "./views/elements/_Tooltip.scss";
diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss
index 2cf6276557..4eff5c33e4 100644
--- a/res/css/structures/auth/_Login.scss
+++ b/res/css/structures/auth/_Login.scss
@@ -79,3 +79,7 @@ limitations under the License.
.mx_Login_type_dropdown {
min-width: 200px;
}
+
+.mx_Login_underlinedServerName {
+ border-bottom: 1px dashed $accent-color;
+}
diff --git a/res/css/views/elements/_TextWithTooltip.scss b/res/css/views/elements/_TextWithTooltip.scss
new file mode 100644
index 0000000000..5b34e7a3be
--- /dev/null
+++ b/res/css/views/elements/_TextWithTooltip.scss
@@ -0,0 +1,19 @@
+/*
+Copyright 2019 New Vector 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.
+*/
+
+.mx_TextWithTooltip_tooltip {
+ display: none;
+}
\ No newline at end of file
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 4198980a17..38f597f673 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -203,9 +203,12 @@ export default React.createClass({
};
},
- // TODO: TravisR - Remove this or put it somewhere else
getFallbackHsUrl: function() {
- return this.props.config.fallback_hs_url;
+ if (this.props.serverConfig.isDefault) {
+ return this.props.config.fallback_hs_url;
+ } else {
+ return null;
+ }
},
getServerProperties() {
diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js
index 5316235fe0..2ea39ad657 100644
--- a/src/components/structures/auth/ForgotPassword.js
+++ b/src/components/structures/auth/ForgotPassword.js
@@ -124,13 +124,7 @@ module.exports = React.createClass({
});
},
- async onServerDetailsNextPhaseClick(ev) {
- ev.stopPropagation();
- // TODO: TravisR - Capture the user's input somehow else
- if (this._serverConfigRef) {
- // Just to make sure the user's input gets captured
- await this._serverConfigRef.validateServer();
- }
+ async onServerDetailsNextPhaseClick() {
this.setState({
phase: PHASE_FORGOT,
});
@@ -160,25 +154,19 @@ module.exports = React.createClass({
renderServerDetails() {
const ServerConfig = sdk.getComponent("auth.ServerConfig");
- const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
if (SdkConfig.get()['disable_custom_urls']) {
return null;
}
- // TODO: TravisR - Pull out server discovery from ServerConfig to disable the next button?
- return
-
this._serverConfigRef = r}
- serverConfig={this.props.serverConfig}
- onServerConfigChange={this.props.onServerConfigChange}
- delayTimeMs={0} />
-
- {_t("Next")}
-
- ;
+ return ;
},
renderForgot() {
@@ -194,9 +182,17 @@ module.exports = React.createClass({
serverName: this.props.serverConfig.hsName,
});
if (this.props.serverConfig.hsNameIsDifferent) {
- // TODO: TravisR - Use tooltip to underline
+ const TextWithTooltip = sdk.getComponent("elements.TextWithTooltip");
+
yourMatrixAccountText = _t('Your Matrix account on ', {}, {
- 'underlinedServerName': () => {this.props.serverConfig.hsName},
+ 'underlinedServerName': () => {
+ return
+ {this.props.serverConfig.hsName}
+ ;
+ },
});
}
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index 3fc7aad50d..393c640604 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -20,7 +20,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import { _t, _td } from '../../../languageHandler';
+import {_t, _td} from '../../../languageHandler';
import sdk from '../../../index';
import Login from '../../../Login';
import SdkConfig from '../../../SdkConfig';
@@ -287,13 +287,7 @@ module.exports = React.createClass({
this.props.onRegisterClick();
},
- async onServerDetailsNextPhaseClick(ev) {
- ev.stopPropagation();
- // TODO: TravisR - Capture the user's input somehow else
- if (this._serverConfigRef) {
- // Just to make sure the user's input gets captured
- await this._serverConfigRef.validateServer();
- }
+ async onServerDetailsNextPhaseClick() {
this.setState({
phase: PHASE_LOGIN,
});
@@ -425,7 +419,6 @@ module.exports = React.createClass({
renderServerComponent() {
const ServerConfig = sdk.getComponent("auth.ServerConfig");
- const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
if (SdkConfig.get()['disable_custom_urls']) {
return null;
@@ -435,26 +428,19 @@ module.exports = React.createClass({
return null;
}
- const serverDetails = this._serverConfigRef = r}
+ const serverDetailsProps = {};
+ if (PHASES_ENABLED) {
+ serverDetailsProps.onAfterSubmit = this.onServerDetailsNextPhaseClick;
+ serverDetailsProps.submitText = _t("Next");
+ serverDetailsProps.submitClass = "mx_Login_submit";
+ }
+
+ return ;
-
- let nextButton = null;
- if (PHASES_ENABLED) {
- // TODO: TravisR - Pull out server discovery from ServerConfig to disable the next button?
- nextButton =
- {_t("Next")}
- ;
- }
-
- return
- {serverDetails}
- {nextButton}
-
;
},
renderLoginComponentForStep() {
diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js
index faab8190bd..f516816033 100644
--- a/src/components/structures/auth/Registration.js
+++ b/src/components/structures/auth/Registration.js
@@ -286,13 +286,7 @@ module.exports = React.createClass({
});
},
- async onServerDetailsNextPhaseClick(ev) {
- ev.stopPropagation();
- // TODO: TravisR - Capture the user's input somehow else
- if (this._serverConfigRef) {
- // Just to make sure the user's input gets captured
- await this._serverConfigRef.validateServer();
- }
+ async onServerDetailsNextPhaseClick() {
this.setState({
phase: PHASE_REGISTRATION,
});
@@ -337,7 +331,6 @@ module.exports = React.createClass({
const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector");
const ServerConfig = sdk.getComponent("auth.ServerConfig");
const ModularServerConfig = sdk.getComponent("auth.ModularServerConfig");
- const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
if (SdkConfig.get()['disable_custom_urls']) {
return null;
@@ -354,45 +347,41 @@ module.exports = React.createClass({
;
}
+ const serverDetailsProps = {};
+ if (PHASES_ENABLED) {
+ serverDetailsProps.onAfterSubmit = this.onServerDetailsNextPhaseClick;
+ serverDetailsProps.submitText = _t("Next");
+ serverDetailsProps.submitClass = "mx_Login_submit";
+ }
+
let serverDetails = null;
switch (this.state.serverType) {
case ServerType.FREE:
break;
case ServerType.PREMIUM:
serverDetails = this._serverConfigRef = r}
serverConfig={this.props.serverConfig}
onServerConfigChange={this.props.onServerConfigChange}
delayTimeMs={250}
+ {...serverDetailsProps}
/>;
break;
case ServerType.ADVANCED:
serverDetails = this._serverConfigRef = r}
serverConfig={this.props.serverConfig}
onServerConfigChange={this.props.onServerConfigChange}
delayTimeMs={250}
+ {...serverDetailsProps}
/>;
break;
}
- let nextButton = null;
- if (PHASES_ENABLED) {
- // TODO: TravisR - Pull out server discovery from ServerConfig to disable the next button?
- nextButton =
- {_t("Next")}
- ;
- }
-
return
{serverDetails}
- {nextButton}
;
},
diff --git a/src/components/views/auth/ModularServerConfig.js b/src/components/views/auth/ModularServerConfig.js
index ea22577dbd..5a3bc23596 100644
--- a/src/components/views/auth/ModularServerConfig.js
+++ b/src/components/views/auth/ModularServerConfig.js
@@ -41,6 +41,16 @@ export default class ModularServerConfig extends React.PureComponent {
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
delayTimeMs: PropTypes.number, // time to wait before invoking onChanged
+
+ // Called after the component calls onServerConfigChange
+ onAfterSubmit: PropTypes.func,
+
+ // Optional text for the submit button. If falsey, no button will be shown.
+ submitText: PropTypes.string,
+
+ // Optional class for the submit button. Only applies if the submit button
+ // is to be rendered.
+ submitClass: PropTypes.string,
};
static defaultProps = {
@@ -119,6 +129,16 @@ export default class ModularServerConfig extends React.PureComponent {
this.setState({ hsUrl });
};
+ onSubmit = async (ev) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+ await this.validateServer();
+
+ if (this.props.onAfterSubmit) {
+ this.props.onAfterSubmit();
+ }
+ };
+
_waitThenInvoke(existingTimeoutId, fn) {
if (existingTimeoutId) {
clearTimeout(existingTimeoutId);
@@ -128,6 +148,16 @@ export default class ModularServerConfig extends React.PureComponent {
render() {
const Field = sdk.getComponent('elements.Field');
+ const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
+
+ const submitButton = this.props.submitText
+ ? {this.props.submitText}
+ : null;
return (
@@ -141,15 +171,18 @@ export default class ModularServerConfig extends React.PureComponent {
,
},
)}
-
-
-
+
);
}
diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js
index f5b2aec210..825bffdc84 100644
--- a/src/components/views/auth/PasswordLogin.js
+++ b/src/components/views/auth/PasswordLogin.js
@@ -279,9 +279,17 @@ export default class PasswordLogin extends React.Component {
serverName: this.props.serverConfig.hsName,
});
if (this.props.serverConfig.hsNameIsDifferent) {
- // TODO: TravisR - Use tooltip to underline
+ const TextWithTooltip = sdk.getComponent("elements.TextWithTooltip");
+
signInToText = _t('Sign in to your Matrix account on ', {}, {
- 'underlinedServerName': () => {this.props.serverConfig.hsName},
+ 'underlinedServerName': () => {
+ return
+ {this.props.serverConfig.hsName}
+ ;
+ },
});
}
diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js
index 0eecc6b826..b1af6ea42c 100644
--- a/src/components/views/auth/RegistrationForm.js
+++ b/src/components/views/auth/RegistrationForm.js
@@ -516,9 +516,17 @@ module.exports = React.createClass({
serverName: this.props.serverConfig.hsName,
});
if (this.props.serverConfig.hsNameIsDifferent) {
- // TODO: TravisR - Use tooltip to underline
+ const TextWithTooltip = sdk.getComponent("elements.TextWithTooltip");
+
yourMatrixAccountText = _t('Create your Matrix account on ', {}, {
- 'underlinedServerName': () => {this.props.serverConfig.hsName},
+ 'underlinedServerName': () => {
+ return
+ {this.props.serverConfig.hsName}
+ ;
+ },
});
}
diff --git a/src/components/views/auth/ServerConfig.js b/src/components/views/auth/ServerConfig.js
index 096e461efe..3967f49f18 100644
--- a/src/components/views/auth/ServerConfig.js
+++ b/src/components/views/auth/ServerConfig.js
@@ -30,12 +30,22 @@ import SdkConfig from "../../../SdkConfig";
export default class ServerConfig extends React.PureComponent {
static propTypes = {
- onServerConfigChange: PropTypes.func,
+ onServerConfigChange: PropTypes.func.isRequired,
// The current configuration that the user is expecting to change.
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
delayTimeMs: PropTypes.number, // time to wait before invoking onChanged
+
+ // Called after the component calls onServerConfigChange
+ onAfterSubmit: PropTypes.func,
+
+ // Optional text for the submit button. If falsey, no button will be shown.
+ submitText: PropTypes.string,
+
+ // Optional class for the submit button. Only applies if the submit button
+ // is to be rendered.
+ submitClass: PropTypes.string,
};
static defaultProps = {
@@ -124,6 +134,16 @@ export default class ServerConfig extends React.PureComponent {
this.setState({ isUrl });
};
+ onSubmit = async (ev) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+ await this.validateServer();
+
+ if (this.props.onAfterSubmit) {
+ this.props.onAfterSubmit();
+ }
+ };
+
_waitThenInvoke(existingTimeoutId, fn) {
if (existingTimeoutId) {
clearTimeout(existingTimeoutId);
@@ -138,11 +158,21 @@ export default class ServerConfig extends React.PureComponent {
render() {
const Field = sdk.getComponent('elements.Field');
+ const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const errorText = this.state.errorText
? {this.state.errorText}
: null;
+ const submitButton = this.props.submitText
+ ? {this.props.submitText}
+ : null;
+
return (
{_t("Other servers")}
@@ -152,24 +182,27 @@ export default class ServerConfig extends React.PureComponent {
,
})}
{errorText}
-
-
-
-
+
);
}
diff --git a/src/components/views/elements/TextWithTooltip.js b/src/components/views/elements/TextWithTooltip.js
new file mode 100644
index 0000000000..61c3a2125a
--- /dev/null
+++ b/src/components/views/elements/TextWithTooltip.js
@@ -0,0 +1,56 @@
+/*
+ Copyright 2019 New Vector 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.
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import sdk from '../../../index';
+
+export default class TextWithTooltip extends React.Component {
+ static propTypes = {
+ class: PropTypes.string,
+ tooltip: PropTypes.string.isRequired,
+ };
+
+ constructor() {
+ super();
+
+ this.state = {
+ hover: false,
+ };
+ }
+
+ onMouseOver = () => {
+ this.setState({hover: true});
+ };
+
+ onMouseOut = () => {
+ this.setState({hover: false});
+ };
+
+ render() {
+ const Tooltip = sdk.getComponent("elements.Tooltip");
+
+ return (
+
+ {this.props.children}
+
+
+ );
+ }
+}
diff --git a/src/components/views/elements/Tooltip.js b/src/components/views/elements/Tooltip.js
index 1cc82978ed..1d6b54f413 100644
--- a/src/components/views/elements/Tooltip.js
+++ b/src/components/views/elements/Tooltip.js
@@ -79,6 +79,10 @@ module.exports = React.createClass({
let offset = 0;
if (parentBox.height > MIN_TOOLTIP_HEIGHT) {
offset = Math.floor((parentBox.height - MIN_TOOLTIP_HEIGHT) / 2);
+ } else {
+ // The tooltip is larger than the parent height: figure out what offset
+ // we need so that we're still centered.
+ offset = Math.floor(parentBox.height - MIN_TOOLTIP_HEIGHT);
}
style.top = (parentBox.top - 2) + window.pageYOffset + offset;
style.left = 6 + parentBox.right + window.pageXOffset;
diff --git a/src/utils/AutoDiscoveryUtils.js b/src/utils/AutoDiscoveryUtils.js
index 318c706136..0850039344 100644
--- a/src/utils/AutoDiscoveryUtils.js
+++ b/src/utils/AutoDiscoveryUtils.js
@@ -26,6 +26,8 @@ export class ValidatedServerConfig {
isUrl: string;
identityEnabled: boolean;
+
+ isDefault: boolean;
}
export default class AutoDiscoveryUtils {
@@ -99,6 +101,7 @@ export default class AutoDiscoveryUtils {
hsNameIsDifferent: url.hostname !== preferredHomeserverName,
isUrl: preferredIdentityUrl,
identityEnabled: !SdkConfig.get()['disable_identity_server'],
+ isDefault: false,
});
}
}