Merge pull request #1982 from matrix-org/t3chguy/nvl/fix_set_password-email_flow

fix set password & email flow possible to get stuck and onBlur murdering your email
This commit is contained in:
Michael Telatynski 2018-06-21 11:42:53 +01:00 committed by GitHub
commit a0207fb7fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 38 additions and 44 deletions

View file

@ -429,7 +429,6 @@ module.exports = React.createClass({
"push notifications on other devices until you log back in to them", "push notifications on other devices until you log back in to them",
) + ".", ) + ".",
}); });
dis.dispatch({action: 'password_changed'});
}, },
_onAddEmailEditFinished: function(value, shouldSubmit) { _onAddEmailEditFinished: function(value, shouldSubmit) {

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
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.
@ -36,7 +37,7 @@ export default React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
emailAddress: null, emailAddress: '',
emailBusy: false, emailBusy: false,
}; };
}, },
@ -127,6 +128,7 @@ export default React.createClass({
const EditableText = sdk.getComponent('elements.EditableText'); const EditableText = sdk.getComponent('elements.EditableText');
const emailInput = this.state.emailBusy ? <Spinner /> : <EditableText const emailInput = this.state.emailBusy ? <Spinner /> : <EditableText
initialValue={this.state.emailAddress}
className="mx_SetEmailDialog_email_input" className="mx_SetEmailDialog_email_input"
autoFocus="true" autoFocus="true"
placeholder={_t("Email address")} placeholder={_t("Email address")}

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
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.
@ -79,15 +80,11 @@ export default React.createClass({
Modal.createDialog(WarmFuzzy, { Modal.createDialog(WarmFuzzy, {
didSetEmail: res.didSetEmail, didSetEmail: res.didSetEmail,
onFinished: () => { onFinished: () => {
this._onContinueClicked(); this.props.onFinished();
}, },
}); });
}, },
_onContinueClicked: function() {
this.props.onFinished(true);
},
_onPasswordChangeError: function(err) { _onPasswordChangeError: function(err) {
let errMsg = err.error || ""; let errMsg = err.error || "";
if (err.httpStatus === 403) { if (err.httpStatus === 403) {

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
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.
@ -14,15 +15,9 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
'use strict'; import React from 'react';
const React = require('react');
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
const KEY_TAB = 9;
const KEY_SHIFT = 16;
const KEY_WINDOWS = 91;
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'EditableText', displayName: 'EditableText',
@ -66,9 +61,7 @@ module.exports = React.createClass({
}, },
componentWillReceiveProps: function(nextProps) { componentWillReceiveProps: function(nextProps) {
if (nextProps.initialValue !== this.props.initialValue || if (nextProps.initialValue !== this.props.initialValue || nextProps.initialValue !== this.value) {
nextProps.initialValue !== this.value
) {
this.value = nextProps.initialValue; this.value = nextProps.initialValue;
if (this.refs.editable_div) { if (this.refs.editable_div) {
this.showPlaceholder(!this.value); this.showPlaceholder(!this.value);
@ -139,7 +132,7 @@ module.exports = React.createClass({
this.showPlaceholder(false); this.showPlaceholder(false);
} }
if (ev.key == "Enter") { if (ev.key === "Enter") {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
} }
@ -156,9 +149,9 @@ module.exports = React.createClass({
this.value = ev.target.textContent; this.value = ev.target.textContent;
} }
if (ev.key == "Enter") { if (ev.key === "Enter") {
this.onFinish(ev); this.onFinish(ev);
} else if (ev.key == "Escape") { } else if (ev.key === "Escape") {
this.cancelEdit(); this.cancelEdit();
} }
@ -193,7 +186,7 @@ module.exports = React.createClass({
const submit = (ev.key === "Enter") || shouldSubmit; const submit = (ev.key === "Enter") || shouldSubmit;
this.setState({ this.setState({
phase: this.Phases.Display, phase: this.Phases.Display,
}, function() { }, () => {
if (this.value !== this.props.initialValue) { if (this.value !== this.props.initialValue) {
self.onValueChanged(submit); self.onValueChanged(submit);
} }
@ -204,23 +197,35 @@ module.exports = React.createClass({
const sel = window.getSelection(); const sel = window.getSelection();
sel.removeAllRanges(); sel.removeAllRanges();
if (this.props.blurToCancel) {this.cancelEdit();} else {this.onFinish(ev, this.props.blurToSubmit);} if (this.props.blurToCancel) {
this.cancelEdit();
} else {
this.onFinish(ev, this.props.blurToSubmit);
}
this.showPlaceholder(!this.value); this.showPlaceholder(!this.value);
}, },
render: function() { render: function() {
let editable_el; const {className, editable, initialValue, label, labelClassName} = this.props;
let editableEl;
if (!this.props.editable || (this.state.phase == this.Phases.Display && (this.props.label || this.props.labelClassName) && !this.value)) { if (!editable || (this.state.phase === this.Phases.Display && (label || labelClassName) && !this.value)) {
// show the label // show the label
editable_el = <div className={this.props.className + " " + this.props.labelClassName} onClick={this.onClickDiv}>{ this.props.label || this.props.initialValue }</div>; editableEl = <div className={className + " " + labelClassName} onClick={this.onClickDiv}>
{ label || initialValue }
</div>;
} else { } else {
// show the content editable div, but manually manage its contents as react and contentEditable don't play nice together // show the content editable div, but manually manage its contents as react and contentEditable don't play nice together
editable_el = <div ref="editable_div" contentEditable="true" className={this.props.className} editableEl = <div ref="editable_div"
onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onBlur}></div>; contentEditable={true}
className={className}
onKeyDown={this.onKeyDown}
onKeyUp={this.onKeyUp}
onFocus={this.onFocus}
onBlur={this.onBlur} />;
} }
return editable_el; return editableEl;
}, },
}); });

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
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.
@ -14,28 +15,15 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
'use strict';
import React from 'react'; import React from 'react';
import sdk from '../../../index'; import sdk from '../../../index';
import Modal from '../../../Modal'; import Modal from '../../../Modal';
import dis from '../../../dispatcher';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
export default React.createClass({ export default React.createClass({
onUpdateClicked: function() { onUpdateClicked: function() {
const SetPasswordDialog = sdk.getComponent('dialogs.SetPasswordDialog'); const SetPasswordDialog = sdk.getComponent('dialogs.SetPasswordDialog');
Modal.createTrackedDialog('Set Password Dialog', 'Password Nag Bar', SetPasswordDialog, { Modal.createTrackedDialog('Set Password Dialog', 'Password Nag Bar', SetPasswordDialog);
onFinished: (passwordChanged) => {
if (!passwordChanged) {
return;
}
// Notify SessionStore that the user's password was changed
dis.dispatch({
action: 'password_changed',
});
},
});
}, },
render: function() { render: function() {

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
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.
@ -14,14 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
'use strict';
const React = require('react'); const React = require('react');
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
const MatrixClientPeg = require("../../../MatrixClientPeg"); const MatrixClientPeg = require("../../../MatrixClientPeg");
const Modal = require("../../../Modal"); const Modal = require("../../../Modal");
const sdk = require("../../../index"); const sdk = require("../../../index");
import dis from "../../../dispatcher";
import Promise from 'bluebird'; import Promise from 'bluebird';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
@ -143,6 +143,9 @@ module.exports = React.createClass({
}); });
cli.setPassword(authDict, newPassword).then(() => { cli.setPassword(authDict, newPassword).then(() => {
// Notify SessionStore that the user's password was changed
dis.dispatch({action: 'password_changed'});
if (this.props.shouldAskForEmail) { if (this.props.shouldAskForEmail) {
return this._optionallySetEmail().then((confirmed) => { return this._optionallySetEmail().then((confirmed) => {
this.props.onFinished({ this.props.onFinished({