Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

fix set password & email flow possible to get stuck and onBlur murdering your email #1982

Merged
merged 3 commits into from
Jun 21, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/components/structures/UserSettings.js
Original file line number Diff line number Diff line change
@@ -429,7 +429,6 @@ module.exports = React.createClass({
"push notifications on other devices until you log back in to them",
) + ".",
});
dis.dispatch({action: 'password_changed'});
},

_onAddEmailEditFinished: function(value, shouldSubmit) {
4 changes: 3 additions & 1 deletion src/components/views/dialogs/SetEmailDialog.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2018 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.
@@ -36,7 +37,7 @@ export default React.createClass({

getInitialState: function() {
return {
emailAddress: null,
emailAddress: '',
emailBusy: false,
};
},
@@ -127,6 +128,7 @@ export default React.createClass({
const EditableText = sdk.getComponent('elements.EditableText');

const emailInput = this.state.emailBusy ? <Spinner /> : <EditableText
initialValue={this.state.emailAddress}
className="mx_SetEmailDialog_email_input"
autoFocus="true"
placeholder={_t("Email address")}
7 changes: 2 additions & 5 deletions src/components/views/dialogs/SetPasswordDialog.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2018 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.
@@ -79,15 +80,11 @@ export default React.createClass({
Modal.createDialog(WarmFuzzy, {
didSetEmail: res.didSetEmail,
onFinished: () => {
this._onContinueClicked();
this.props.onFinished();
},
});
},

_onContinueClicked: function() {
this.props.onFinished(true);
},

_onPasswordChangeError: function(err) {
let errMsg = err.error || "";
if (err.httpStatus === 403) {
47 changes: 26 additions & 21 deletions src/components/views/elements/EditableText.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 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.
@@ -14,15 +15,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

const React = require('react');
import React from 'react';
import PropTypes from 'prop-types';

const KEY_TAB = 9;
const KEY_SHIFT = 16;
const KEY_WINDOWS = 91;

module.exports = React.createClass({
displayName: 'EditableText',

@@ -66,9 +61,7 @@ module.exports = React.createClass({
},

componentWillReceiveProps: function(nextProps) {
if (nextProps.initialValue !== this.props.initialValue ||
nextProps.initialValue !== this.value
) {
if (nextProps.initialValue !== this.props.initialValue || nextProps.initialValue !== this.value) {
this.value = nextProps.initialValue;
if (this.refs.editable_div) {
this.showPlaceholder(!this.value);
@@ -139,7 +132,7 @@ module.exports = React.createClass({
this.showPlaceholder(false);
}

if (ev.key == "Enter") {
if (ev.key === "Enter") {
ev.stopPropagation();
ev.preventDefault();
}
@@ -156,9 +149,9 @@ module.exports = React.createClass({
this.value = ev.target.textContent;
}

if (ev.key == "Enter") {
if (ev.key === "Enter") {
this.onFinish(ev);
} else if (ev.key == "Escape") {
} else if (ev.key === "Escape") {
this.cancelEdit();
}

@@ -193,7 +186,7 @@ module.exports = React.createClass({
const submit = (ev.key === "Enter") || shouldSubmit;
this.setState({
phase: this.Phases.Display,
}, function() {
}, () => {
if (this.value !== this.props.initialValue) {
self.onValueChanged(submit);
}
@@ -204,23 +197,35 @@ module.exports = React.createClass({
const sel = window.getSelection();
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);
},

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
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 {
// 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}
onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onBlur}></div>;
editableEl = <div ref="editable_div"
contentEditable={true}
className={className}
onKeyDown={this.onKeyDown}
onKeyUp={this.onKeyUp}
onFocus={this.onFocus}
onBlur={this.onBlur} />;
}

return editable_el;
return editableEl;
},
});
16 changes: 2 additions & 14 deletions src/components/views/globals/PasswordNagBar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2018 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.
@@ -14,28 +15,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

import React from 'react';
import sdk from '../../../index';
import Modal from '../../../Modal';
import dis from '../../../dispatcher';
import { _t } from '../../../languageHandler';

export default React.createClass({
onUpdateClicked: function() {
const SetPasswordDialog = sdk.getComponent('dialogs.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',
});
},
});
Modal.createTrackedDialog('Set Password Dialog', 'Password Nag Bar', SetPasswordDialog);
},

render: function() {
7 changes: 5 additions & 2 deletions src/components/views/settings/ChangePassword.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 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.
@@ -14,14 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

const React = require('react');
import PropTypes from 'prop-types';
const MatrixClientPeg = require("../../../MatrixClientPeg");
const Modal = require("../../../Modal");
const sdk = require("../../../index");

import dis from "../../../dispatcher";
import Promise from 'bluebird';
import AccessibleButton from '../elements/AccessibleButton';
import { _t } from '../../../languageHandler';
@@ -143,6 +143,9 @@ module.exports = React.createClass({
});

cli.setPassword(authDict, newPassword).then(() => {
// Notify SessionStore that the user's password was changed
dis.dispatch({action: 'password_changed'});

if (this.props.shouldAskForEmail) {
return this._optionallySetEmail().then((confirmed) => {
this.props.onFinished({