Merge pull request #200 from matrix-org/matthew/loginfixes

Bring back lost functionality on login/register/password-reset screens
This commit is contained in:
Matthew Hodgson 2016-03-15 15:21:32 +00:00
commit 672a5cb89c
8 changed files with 206 additions and 86 deletions

View file

@ -25,6 +25,7 @@ var matrixClient = null;
var localStorage = window.localStorage; var localStorage = window.localStorage;
function deviceId() { function deviceId() {
// XXX: is Math.random()'s deterministicity a problem here?
var id = Math.floor(Math.random()*16777215).toString(16); var id = Math.floor(Math.random()*16777215).toString(16);
id = "W" + "000000".substring(id.length) + id; id = "W" + "000000".substring(id.length) + id;
if (localStorage) { if (localStorage) {
@ -34,7 +35,7 @@ function deviceId() {
return id; return id;
} }
function createClient(hs_url, is_url, user_id, access_token, guestAccess) { function createClientForPeg(hs_url, is_url, user_id, access_token, guestAccess) {
var opts = { var opts = {
baseUrl: hs_url, baseUrl: hs_url,
idBaseUrl: is_url, idBaseUrl: is_url,
@ -68,7 +69,7 @@ if (localStorage) {
var guestAccess = new GuestAccess(localStorage); var guestAccess = new GuestAccess(localStorage);
if (access_token && user_id && hs_url) { if (access_token && user_id && hs_url) {
console.log("Restoring session for %s", user_id); console.log("Restoring session for %s", user_id);
createClient(hs_url, is_url, user_id, access_token, guestAccess); createClientForPeg(hs_url, is_url, user_id, access_token, guestAccess);
} }
else { else {
console.log("Session not found."); console.log("Session not found.");
@ -91,7 +92,7 @@ class MatrixClient {
// FIXME, XXX: this all seems very convoluted :( // FIXME, XXX: this all seems very convoluted :(
// //
// if we replace the singleton using URLs we bypass our createClient() // if we replace the singleton using URLs we bypass our createClientForPeg()
// global helper function... but if we replace it using // global helper function... but if we replace it using
// an access_token we don't? // an access_token we don't?
// //
@ -105,6 +106,7 @@ class MatrixClient {
baseUrl: hs_url, baseUrl: hs_url,
idBaseUrl: is_url idBaseUrl: is_url
}); });
// XXX: factor this out with the localStorage setting in replaceUsingAccessToken // XXX: factor this out with the localStorage setting in replaceUsingAccessToken
if (localStorage) { if (localStorage) {
try { try {
@ -123,11 +125,11 @@ class MatrixClient {
try { try {
localStorage.clear(); localStorage.clear();
} catch (e) { } catch (e) {
console.warn("Error using local storage"); console.warn("Error clearing local storage", e);
} }
} }
this.guestAccess.markAsGuest(Boolean(isGuest)); this.guestAccess.markAsGuest(Boolean(isGuest));
createClient(hs_url, is_url, user_id, access_token, this.guestAccess); createClientForPeg(hs_url, is_url, user_id, access_token, this.guestAccess);
if (localStorage) { if (localStorage) {
try { try {
localStorage.setItem("mx_hs_url", hs_url); localStorage.setItem("mx_hs_url", hs_url);
@ -136,7 +138,7 @@ class MatrixClient {
localStorage.setItem("mx_access_token", access_token); localStorage.setItem("mx_access_token", access_token);
console.log("Session persisted for %s", user_id); console.log("Session persisted for %s", user_id);
} catch (e) { } catch (e) {
console.warn("Error using local storage: can't persist session!"); console.warn("Error using local storage: can't persist session!", e);
} }
} else { } else {
console.warn("No local storage available: can't persist session!"); console.warn("No local storage available: can't persist session!");

View file

@ -85,6 +85,32 @@ module.exports = React.createClass({
}; };
}, },
getCurrentHsUrl: function() {
if (MatrixClientPeg.get()) {
return MatrixClientPeg.get().getHomeserverUrl();
}
else if (window.localStorage && window.localStorage.getItem("mx_hs_url")) {
return window.localStorage.getItem("mx_hs_url");
}
else if (this.props.config) {
return this.props.config.default_hs_url
}
return "https://matrix.org";
},
getCurrentIsUrl: function() {
if (MatrixClientPeg.get()) {
return MatrixClientPeg.get().getIdentityServerUrl();
}
else if (window.localStorage && window.localStorage.getItem("mx_is_url")) {
return window.localStorage.getItem("mx_is_url");
}
else if (this.props.config) {
return this.props.config.default_is_url
}
return "https://matrix.org";
},
componentWillMount: function() { componentWillMount: function() {
this.favicon = new Favico({animation: 'none'}); this.favicon = new Favico({animation: 'none'});
}, },
@ -92,8 +118,8 @@ module.exports = React.createClass({
componentDidMount: function() { componentDidMount: function() {
this._autoRegisterAsGuest = false; this._autoRegisterAsGuest = false;
if (this.props.enableGuest) { if (this.props.enableGuest) {
if (!this.props.config || !this.props.config.default_hs_url) { if (!this.getCurrentHsUrl()) {
console.error("Cannot enable guest access: No supplied config prop for HS/IS URLs"); console.error("Cannot enable guest access: can't determine HS URL to use");
} }
else if (this.props.startingQueryParams.client_secret && this.props.startingQueryParams.sid) { else if (this.props.startingQueryParams.client_secret && this.props.startingQueryParams.sid) {
console.log("Not registering as guest; registration."); console.log("Not registering as guest; registration.");
@ -167,19 +193,19 @@ module.exports = React.createClass({
_registerAsGuest: function() { _registerAsGuest: function() {
var self = this; var self = this;
var config = this.props.config; console.log("Doing guest login on %s", this.getCurrentHsUrl());
console.log("Doing guest login on %s", config.default_hs_url); var hsUrl = this.getCurrentHsUrl();
MatrixClientPeg.replaceUsingUrls( var isUrl = this.getCurrentIsUrl();
config.default_hs_url, config.default_is_url
); MatrixClientPeg.replaceUsingUrls(hsUrl, isUrl);
MatrixClientPeg.get().registerGuest().done(function(creds) { MatrixClientPeg.get().registerGuest().done(function(creds) {
console.log("Registered as guest: %s", creds.user_id); console.log("Registered as guest: %s", creds.user_id);
self._setAutoRegisterAsGuest(false); self._setAutoRegisterAsGuest(false);
self.onLoggedIn({ self.onLoggedIn({
userId: creds.user_id, userId: creds.user_id,
accessToken: creds.access_token, accessToken: creds.access_token,
homeserverUrl: config.default_hs_url, homeserverUrl: hsUrl,
identityServerUrl: config.default_is_url, identityServerUrl: isUrl,
guest: true guest: true
}); });
}, function(err) { }, function(err) {
@ -201,6 +227,9 @@ module.exports = React.createClass({
case 'logout': case 'logout':
if (window.localStorage) { if (window.localStorage) {
window.localStorage.clear(); window.localStorage.clear();
// preserve our HS & IS URLs for convenience
window.localStorage.setItem("mx_hs_url", this.getCurrentHsUrl());
window.localStorage.setItem("mx_is_url", this.getCurrentIsUrl());
} }
Notifier.stop(); Notifier.stop();
UserActivity.stop(); UserActivity.stop();
@ -744,7 +773,7 @@ module.exports = React.createClass({
} }
} }
else { else {
console.error("Unknown screen : %s", screen); console.info("Ignoring showScreen for '%s'", screen);
} }
}, },
@ -908,6 +937,8 @@ module.exports = React.createClass({
var NewVersionBar = sdk.getComponent('globals.NewVersionBar'); var NewVersionBar = sdk.getComponent('globals.NewVersionBar');
var ForgotPassword = sdk.getComponent('structures.login.ForgotPassword'); var ForgotPassword = sdk.getComponent('structures.login.ForgotPassword');
// work out the HS URL prompts we should show for
// needs to be before normal PageTypes as you are logged in technically // needs to be before normal PageTypes as you are logged in technically
if (this.state.screen == 'post_registration') { if (this.state.screen == 'post_registration') {
return ( return (
@ -1004,26 +1035,34 @@ module.exports = React.createClass({
username={this.state.upgradeUsername} username={this.state.upgradeUsername}
disableUsernameChanges={Boolean(this.state.upgradeUsername)} disableUsernameChanges={Boolean(this.state.upgradeUsername)}
guestAccessToken={this.state.guestAccessToken} guestAccessToken={this.state.guestAccessToken}
hsUrl={this.props.config.default_hs_url} defaultHsUrl={this.props.config.default_hs_url}
isUrl={this.props.config.default_is_url} defaultIsUrl={this.props.config.default_is_url}
customHsUrl={this.getCurrentHsUrl()}
customIsUrl={this.getCurrentIsUrl()}
registrationUrl={this.props.registrationUrl} registrationUrl={this.props.registrationUrl}
onLoggedIn={this.onRegistered} onLoggedIn={this.onRegistered}
onLoginClick={this.onLoginClick} /> onLoginClick={this.onLoginClick}
onRegisterClick={this.onRegisterClick} />
); );
} else if (this.state.screen == 'forgot_password') { } else if (this.state.screen == 'forgot_password') {
return ( return (
<ForgotPassword <ForgotPassword
homeserverUrl={this.props.config.default_hs_url} defaultHsUrl={this.props.config.default_hs_url}
identityServerUrl={this.props.config.default_is_url} defaultIsUrl={this.props.config.default_is_url}
onComplete={this.onLoginClick} /> customHsUrl={this.getCurrentHsUrl()}
customIsUrl={this.getCurrentIsUrl()}
onComplete={this.onLoginClick}
onLoginClick={this.onLoginClick} />
); );
} else { } else {
return ( return (
<Login <Login
onLoggedIn={this.onLoggedIn} onLoggedIn={this.onLoggedIn}
onRegisterClick={this.onRegisterClick} onRegisterClick={this.onRegisterClick}
homeserverUrl={this.props.config.default_hs_url} defaultHsUrl={this.props.config.default_hs_url}
identityServerUrl={this.props.config.default_is_url} defaultIsUrl={this.props.config.default_is_url}
customHsUrl={this.getCurrentHsUrl()}
customIsUrl={this.getCurrentIsUrl()}
onForgotPasswordClick={this.onForgotPasswordClick} onForgotPasswordClick={this.onForgotPasswordClick}
onLoginAsGuestClick={this.props.enableGuest && this.props.config && this.props.config.default_hs_url ? this._registerAsGuest: undefined} onLoginAsGuestClick={this.props.enableGuest && this.props.config && this.props.config.default_hs_url ? this._registerAsGuest: undefined}
/> />

View file

@ -27,8 +27,12 @@ module.exports = React.createClass({
displayName: 'ForgotPassword', displayName: 'ForgotPassword',
propTypes: { propTypes: {
homeserverUrl: React.PropTypes.string, defaultHsUrl: React.PropTypes.string,
identityServerUrl: React.PropTypes.string, defaultIsUrl: React.PropTypes.string,
customHsUrl: React.PropTypes.string,
customIsUrl: React.PropTypes.string,
onLoginClick: React.PropTypes.func,
onRegisterClick: React.PropTypes.func,
onComplete: React.PropTypes.func.isRequired onComplete: React.PropTypes.func.isRequired
}, },
@ -152,8 +156,9 @@ module.exports = React.createClass({
else { else {
resetPasswordJsx = ( resetPasswordJsx = (
<div> <div>
To reset your password, enter the email address linked to your account: <div className="mx_Login_prompt">
<br /> To reset your password, enter the email address linked to your account:
</div>
<div> <div>
<form onSubmit={this.onSubmitForm}> <form onSubmit={this.onSubmitForm}>
<input className="mx_Login_field" ref="user" type="text" <input className="mx_Login_field" ref="user" type="text"
@ -175,11 +180,21 @@ module.exports = React.createClass({
</form> </form>
<ServerConfig ref="serverConfig" <ServerConfig ref="serverConfig"
withToggleButton={true} withToggleButton={true}
defaultHsUrl={this.props.homeserverUrl} defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.identityServerUrl} defaultIsUrl={this.props.defaultIsUrl}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
onHsUrlChanged={this.onHsUrlChanged} onHsUrlChanged={this.onHsUrlChanged}
onIsUrlChanged={this.onIsUrlChanged} onIsUrlChanged={this.onIsUrlChanged}
delayTimeMs={0}/> delayTimeMs={0}/>
<div className="mx_Login_error">
</div>
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
Return to login
</a>
<a className="mx_Login_create" onClick={this.props.onRegisterClick} href="#">
Create a new account
</a>
<LoginFooter /> <LoginFooter />
</div> </div>
</div> </div>

View file

@ -30,28 +30,29 @@ var ServerConfig = require("../../views/login/ServerConfig");
module.exports = React.createClass({displayName: 'Login', module.exports = React.createClass({displayName: 'Login',
propTypes: { propTypes: {
onLoggedIn: React.PropTypes.func.isRequired, onLoggedIn: React.PropTypes.func.isRequired,
homeserverUrl: React.PropTypes.string,
identityServerUrl: React.PropTypes.string, customHsUrl: React.PropTypes.string,
customIsUrl: React.PropTypes.string,
defaultHsUrl: React.PropTypes.string,
defaultIsUrl: React.PropTypes.string,
// login shouldn't know or care how registration is done. // login shouldn't know or care how registration is done.
onRegisterClick: React.PropTypes.func.isRequired, onRegisterClick: React.PropTypes.func.isRequired,
// login shouldn't care how password recovery is done. // login shouldn't care how password recovery is done.
onForgotPasswordClick: React.PropTypes.func, onForgotPasswordClick: React.PropTypes.func,
onLoginAsGuestClick: React.PropTypes.func, onLoginAsGuestClick: React.PropTypes.func,
}, },
getDefaultProps: function() {
return {
homeserverUrl: 'https://matrix.org/',
identityServerUrl: 'https://matrix.org'
};
},
getInitialState: function() { getInitialState: function() {
return { return {
busy: false, busy: false,
errorText: null, errorText: null,
enteredHomeserverUrl: this.props.homeserverUrl, enteredHomeserverUrl: this.props.customHsUrl || this.props.defaultHsUrl,
enteredIdentityServerUrl: this.props.identityServerUrl enteredIdentityServerUrl: this.props.customIsUrl || this.props.defaultIsUrl,
// used for preserving username when changing homeserver
username: "",
}; };
}, },
@ -76,12 +77,26 @@ module.exports = React.createClass({displayName: 'Login',
}); });
}, },
onUsernameChanged: function(username) {
this.setState({ username: username });
},
onHsUrlChanged: function(newHsUrl) { onHsUrlChanged: function(newHsUrl) {
this._initLoginLogic(newHsUrl); var self = this;
this.setState({
enteredHomeserverUrl: newHsUrl
}, function() {
self._initLoginLogic(newHsUrl);
});
}, },
onIsUrlChanged: function(newIsUrl) { onIsUrlChanged: function(newIsUrl) {
this._initLoginLogic(null, newIsUrl); var self = this;
this.setState({
enteredIdentityServerUrl: newIsUrl
}, function() {
self._initLoginLogic(null, newIsUrl);
});
}, },
_initLoginLogic: function(hsUrl, isUrl) { _initLoginLogic: function(hsUrl, isUrl) {
@ -162,6 +177,8 @@ module.exports = React.createClass({displayName: 'Login',
return ( return (
<PasswordLogin <PasswordLogin
onSubmit={this.onPasswordLogin} onSubmit={this.onPasswordLogin}
initialUsername={this.state.username}
onUsernameChanged={this.onUsernameChanged}
onForgotPasswordClick={this.props.onForgotPasswordClick} /> onForgotPasswordClick={this.props.onForgotPasswordClick} />
); );
case 'm.login.cas': case 'm.login.cas':
@ -203,8 +220,10 @@ module.exports = React.createClass({displayName: 'Login',
{ this.componentForStep(this._getCurrentFlowStep()) } { this.componentForStep(this._getCurrentFlowStep()) }
<ServerConfig ref="serverConfig" <ServerConfig ref="serverConfig"
withToggleButton={true} withToggleButton={true}
defaultHsUrl={this.props.homeserverUrl} customHsUrl={this.props.customHsUrl}
defaultIsUrl={this.props.identityServerUrl} customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onHsUrlChanged={this.onHsUrlChanged} onHsUrlChanged={this.onHsUrlChanged}
onIsUrlChanged={this.onIsUrlChanged} onIsUrlChanged={this.onIsUrlChanged}
delayTimeMs={1000}/> delayTimeMs={1000}/>
@ -216,7 +235,6 @@ module.exports = React.createClass({displayName: 'Login',
Create a new account Create a new account
</a> </a>
{ loginAsGuestJsx } { loginAsGuestJsx }
<br/>
<LoginFooter /> <LoginFooter />
</div> </div>
</div> </div>

View file

@ -36,8 +36,10 @@ module.exports = React.createClass({
sessionId: React.PropTypes.string, sessionId: React.PropTypes.string,
registrationUrl: React.PropTypes.string, registrationUrl: React.PropTypes.string,
idSid: React.PropTypes.string, idSid: React.PropTypes.string,
hsUrl: React.PropTypes.string, customHsUrl: React.PropTypes.string,
isUrl: React.PropTypes.string, customIsUrl: React.PropTypes.string,
defaultHsUrl: React.PropTypes.string,
defaultIsUrl: React.PropTypes.string,
email: React.PropTypes.string, email: React.PropTypes.string,
username: React.PropTypes.string, username: React.PropTypes.string,
guestAccessToken: React.PropTypes.string, guestAccessToken: React.PropTypes.string,
@ -50,8 +52,6 @@ module.exports = React.createClass({
return { return {
busy: false, busy: false,
errorText: null, errorText: null,
enteredHomeserverUrl: this.props.hsUrl,
enteredIdentityServerUrl: this.props.isUrl
}; };
}, },
@ -59,7 +59,7 @@ module.exports = React.createClass({
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
// attach this to the instance rather than this.state since it isn't UI // attach this to the instance rather than this.state since it isn't UI
this.registerLogic = new Signup.Register( this.registerLogic = new Signup.Register(
this.props.hsUrl, this.props.isUrl this.props.customHsUrl, this.props.customIsUrl
); );
this.registerLogic.setClientSecret(this.props.clientSecret); this.registerLogic.setClientSecret(this.props.clientSecret);
this.registerLogic.setSessionId(this.props.sessionId); this.registerLogic.setSessionId(this.props.sessionId);
@ -242,11 +242,15 @@ module.exports = React.createClass({
{busySpinner} {busySpinner}
<ServerConfig ref="serverConfig" <ServerConfig ref="serverConfig"
withToggleButton={true} withToggleButton={true}
defaultHsUrl={this.state.enteredHomeserverUrl} customHsUrl={this.props.customHsUrl}
defaultIsUrl={this.state.enteredIdentityServerUrl} customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onHsUrlChanged={this.onHsUrlChanged} onHsUrlChanged={this.onHsUrlChanged}
onIsUrlChanged={this.onIsUrlChanged} onIsUrlChanged={this.onIsUrlChanged}
delayTimeMs={1000} /> delayTimeMs={1000} />
<div className="mx_Login_error">
</div>
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#"> <a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
I already have an account I already have an account
</a> </a>
@ -256,11 +260,13 @@ module.exports = React.createClass({
render: function() { render: function() {
var LoginHeader = sdk.getComponent('login.LoginHeader'); var LoginHeader = sdk.getComponent('login.LoginHeader');
var LoginFooter = sdk.getComponent('login.LoginFooter');
return ( return (
<div className="mx_Login"> <div className="mx_Login">
<div className="mx_Login_box"> <div className="mx_Login_box">
<LoginHeader /> <LoginHeader />
{this._getRegisterContentJsx()} {this._getRegisterContentJsx()}
<LoginFooter />
</div> </div>
</div> </div>
); );

View file

@ -31,12 +31,11 @@ module.exports = React.createClass({
servers by specifying a different Home server URL. servers by specifying a different Home server URL.
<br/> <br/>
This allows you to use this app with an existing Matrix account on This allows you to use this app with an existing Matrix account on
a different Home server. a different home server.
<br/> <br/>
<br/> <br/>
You can also set a custom Identity server but this will affect You can also set a custom identity server but this will typically prevent
people&#39;s ability to find you if you use a server in a group other interaction with users based on email address.
than the main Matrix.org group.
</span> </span>
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">

View file

@ -23,13 +23,26 @@ var ReactDOM = require('react-dom');
module.exports = React.createClass({displayName: 'PasswordLogin', module.exports = React.createClass({displayName: 'PasswordLogin',
propTypes: { propTypes: {
onSubmit: React.PropTypes.func.isRequired, // fn(username, password) onSubmit: React.PropTypes.func.isRequired, // fn(username, password)
onForgotPasswordClick: React.PropTypes.func // fn() onForgotPasswordClick: React.PropTypes.func, // fn()
initialUsername: React.PropTypes.string,
initialPassword: React.PropTypes.string,
onUsernameChanged: React.PropTypes.func,
onPasswordChanged: React.PropTypes.func,
},
getDefaultProps: function() {
return {
onUsernameChanged: function() {},
onPasswordChanged: function() {},
initialUsername: "",
initialPassword: "",
};
}, },
getInitialState: function() { getInitialState: function() {
return { return {
username: "", username: this.props.initialUsername,
password: "" password: this.props.initialPassword,
}; };
}, },
@ -40,10 +53,12 @@ module.exports = React.createClass({displayName: 'PasswordLogin',
onUsernameChanged: function(ev) { onUsernameChanged: function(ev) {
this.setState({username: ev.target.value}); this.setState({username: ev.target.value});
this.props.onUsernameChanged(ev.target.value);
}, },
onPasswordChanged: function(ev) { onPasswordChanged: function(ev) {
this.setState({password: ev.target.value}); this.setState({password: ev.target.value});
this.props.onPasswordChanged(ev.target.value);
}, },
render: function() { render: function() {

View file

@ -29,8 +29,21 @@ module.exports = React.createClass({
propTypes: { propTypes: {
onHsUrlChanged: React.PropTypes.func, onHsUrlChanged: React.PropTypes.func,
onIsUrlChanged: React.PropTypes.func, onIsUrlChanged: React.PropTypes.func,
defaultHsUrl: React.PropTypes.string,
defaultIsUrl: React.PropTypes.string, // default URLs are defined in config.json (or the hardcoded defaults)
// they are used if the user has not overridden them with a custom URL.
// In other words, if the custom URL is blank, the default is used.
defaultHsUrl: React.PropTypes.string, // e.g. https://matrix.org
defaultIsUrl: React.PropTypes.string, // e.g. https://vector.im
// custom URLs are explicitly provided by the user and override the
// default URLs. The user enters them via the component's input fields,
// which is reflected on these properties whenever on..UrlChanged fires.
// They are persisted in localStorage by MatrixClientPeg, and so can
// override the default URLs when the component initially loads.
customHsUrl: React.PropTypes.string,
customIsUrl: React.PropTypes.string,
withToggleButton: React.PropTypes.bool, withToggleButton: React.PropTypes.bool,
delayTimeMs: React.PropTypes.number // time to wait before invoking onChanged delayTimeMs: React.PropTypes.number // time to wait before invoking onChanged
}, },
@ -39,6 +52,8 @@ module.exports = React.createClass({
return { return {
onHsUrlChanged: function() {}, onHsUrlChanged: function() {},
onIsUrlChanged: function() {}, onIsUrlChanged: function() {},
customHsUrl: "",
customIsUrl: "",
withToggleButton: false, withToggleButton: false,
delayTimeMs: 0 delayTimeMs: 0
}; };
@ -46,19 +61,21 @@ module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
hs_url: this.props.defaultHsUrl, hs_url: this.props.customHsUrl,
is_url: this.props.defaultIsUrl, is_url: this.props.customIsUrl,
original_hs_url: this.props.defaultHsUrl, // if withToggleButton is false, then show the config all the time given we have no way otherwise of making it visible
original_is_url: this.props.defaultIsUrl, configVisible: !this.props.withToggleButton ||
// no toggle button = show, toggle button = hide (this.props.customHsUrl !== this.props.defaultHsUrl) ||
configVisible: !this.props.withToggleButton (this.props.customIsUrl !== this.props.defaultIsUrl)
} }
}, },
onHomeserverChanged: function(ev) { onHomeserverChanged: function(ev) {
this.setState({hs_url: ev.target.value}, function() { this.setState({hs_url: ev.target.value}, function() {
this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, function() { this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, function() {
this.props.onHsUrlChanged(this.state.hs_url.replace(/\/$/, "")); var hsUrl = this.state.hs_url.trim().replace(/\/$/, "");
if (hsUrl === "") hsUrl = this.props.defaultHsUrl;
this.props.onHsUrlChanged(hsUrl);
}); });
}); });
}, },
@ -66,7 +83,9 @@ module.exports = React.createClass({
onIdentityServerChanged: function(ev) { onIdentityServerChanged: function(ev) {
this.setState({is_url: ev.target.value}, function() { this.setState({is_url: ev.target.value}, function() {
this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, function() { this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, function() {
this.props.onIsUrlChanged(this.state.is_url.replace(/\/$/, "")); var isUrl = this.state.is_url.trim().replace(/\/$/, "");
if (isUrl === "") isUrl = this.props.defaultIsUrl;
this.props.onIsUrlChanged(isUrl);
}); });
}); });
}, },
@ -78,18 +97,18 @@ module.exports = React.createClass({
return setTimeout(fn.bind(this), this.props.delayTimeMs); return setTimeout(fn.bind(this), this.props.delayTimeMs);
}, },
getHsUrl: function() { onServerConfigVisibleChange: function(visible, ev) {
return this.state.hs_url;
},
getIsUrl: function() {
return this.state.is_url;
},
onServerConfigVisibleChange: function(ev) {
this.setState({ this.setState({
configVisible: ev.target.checked configVisible: visible
}); });
if (!visible) {
this.props.onHsUrlChanged(this.props.defaultHsUrl);
this.props.onIsUrlChanged(this.props.defaultIsUrl);
}
else {
this.props.onHsUrlChanged(this.state.hs_url);
this.props.onIsUrlChanged(this.state.is_url);
}
}, },
showHelpPopup: function() { showHelpPopup: function() {
@ -104,12 +123,19 @@ module.exports = React.createClass({
var toggleButton; var toggleButton;
if (this.props.withToggleButton) { if (this.props.withToggleButton) {
toggleButton = ( toggleButton = (
<div> <div style={{ textAlign: 'center' }}>
<input className="mx_Login_checkbox" id="advanced" type="checkbox" <input className="mx_Login_radio" id="basic" name="configVisible" type="radio"
checked={!this.state.configVisible}
onChange={this.onServerConfigVisibleChange.bind(this, false)} />
<label className="mx_Login_label" htmlFor="basic">
Default server
</label>
&nbsp;&nbsp;
<input className="mx_Login_radio" id="advanced" name="configVisible" type="radio"
checked={this.state.configVisible} checked={this.state.configVisible}
onChange={this.onServerConfigVisibleChange} /> onChange={this.onServerConfigVisibleChange.bind(this, true)} />
<label className="mx_Login_label" htmlFor="advanced"> <label className="mx_Login_label" htmlFor="advanced">
Use custom server options (advanced) Custom server
</label> </label>
</div> </div>
); );
@ -124,14 +150,14 @@ module.exports = React.createClass({
Home server URL Home server URL
</label> </label>
<input className="mx_Login_field" id="hsurl" type="text" <input className="mx_Login_field" id="hsurl" type="text"
placeholder={this.state.original_hs_url} placeholder={this.props.defaultHsUrl}
value={this.state.hs_url} value={this.state.hs_url}
onChange={this.onHomeserverChanged} /> onChange={this.onHomeserverChanged} />
<label className="mx_Login_label mx_ServerConfig_islabel" htmlFor="isurl"> <label className="mx_Login_label mx_ServerConfig_islabel" htmlFor="isurl">
Identity server URL Identity server URL
</label> </label>
<input className="mx_Login_field" id="isurl" type="text" <input className="mx_Login_field" id="isurl" type="text"
placeholder={this.state.original_is_url} placeholder={this.props.defaultIsUrl}
value={this.state.is_url} value={this.state.is_url}
onChange={this.onIdentityServerChanged} /> onChange={this.onIdentityServerChanged} />
<a className="mx_ServerConfig_help" href="#" onClick={this.showHelpPopup}> <a className="mx_ServerConfig_help" href="#" onClick={this.showHelpPopup}>