Merge branch 'develop' into rav/handle_received_room_key_requests
This commit is contained in:
commit
a0534e7477
106 changed files with 6339 additions and 1548 deletions
|
@ -24,8 +24,10 @@ import DMRoomMap from '../../../utils/DMRoomMap';
|
|||
import Modal from '../../../Modal';
|
||||
import AccessibleButton from '../elements/AccessibleButton';
|
||||
import q from 'q';
|
||||
import dis from '../../../dispatcher';
|
||||
|
||||
const TRUNCATE_QUERY_LIST = 40;
|
||||
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "ChatInviteDialog",
|
||||
|
@ -40,13 +42,13 @@ module.exports = React.createClass({
|
|||
roomId: React.PropTypes.string,
|
||||
button: React.PropTypes.string,
|
||||
focus: React.PropTypes.bool,
|
||||
onFinished: React.PropTypes.func.isRequired
|
||||
onFinished: React.PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
value: "",
|
||||
focus: true
|
||||
focus: true,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -54,12 +56,20 @@ module.exports = React.createClass({
|
|||
return {
|
||||
error: false,
|
||||
|
||||
// List of AddressTile.InviteAddressType objects represeting
|
||||
// List of AddressTile.InviteAddressType objects representing
|
||||
// the list of addresses we're going to invite
|
||||
inviteList: [],
|
||||
|
||||
// List of AddressTile.InviteAddressType objects represeting
|
||||
// the set of autocompletion results for the current search
|
||||
// Whether a search is ongoing
|
||||
busy: false,
|
||||
// An error message generated during the user directory search
|
||||
searchError: null,
|
||||
// Whether the server supports the user_directory API
|
||||
serverSupportsUserDirectory: true,
|
||||
// The query being searched for
|
||||
query: "",
|
||||
// List of AddressTile.InviteAddressType objects representing
|
||||
// the set of auto-completion results for the current search
|
||||
// query.
|
||||
queryList: [],
|
||||
};
|
||||
|
@ -70,7 +80,6 @@ module.exports = React.createClass({
|
|||
// Set the cursor at the end of the text input
|
||||
this.refs.textinput.value = this.props.value;
|
||||
}
|
||||
this._updateUserList();
|
||||
},
|
||||
|
||||
onButtonClick: function() {
|
||||
|
@ -94,7 +103,7 @@ module.exports = React.createClass({
|
|||
const ChatCreateOrReuseDialog = sdk.getComponent(
|
||||
"views.dialogs.ChatCreateOrReuseDialog",
|
||||
);
|
||||
Modal.createDialog(ChatCreateOrReuseDialog, {
|
||||
const close = Modal.createDialog(ChatCreateOrReuseDialog, {
|
||||
userId: userId,
|
||||
onFinished: (success) => {
|
||||
this.props.onFinished(success);
|
||||
|
@ -104,14 +113,16 @@ module.exports = React.createClass({
|
|||
action: 'start_chat',
|
||||
user_id: userId,
|
||||
});
|
||||
close(true);
|
||||
},
|
||||
onExistingRoomSelected: (roomId) => {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
user_id: roomId,
|
||||
room_id: roomId,
|
||||
});
|
||||
close(true);
|
||||
},
|
||||
});
|
||||
}).close;
|
||||
} else {
|
||||
this._startChat(inviteList);
|
||||
}
|
||||
|
@ -137,15 +148,15 @@ module.exports = React.createClass({
|
|||
} else if (e.keyCode === 38) { // up arrow
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.addressSelector.moveSelectionUp();
|
||||
if (this.addressSelector) this.addressSelector.moveSelectionUp();
|
||||
} else if (e.keyCode === 40) { // down arrow
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.addressSelector.moveSelectionDown();
|
||||
if (this.addressSelector) this.addressSelector.moveSelectionDown();
|
||||
} else if (this.state.queryList.length > 0 && (e.keyCode === 188 || e.keyCode === 13 || e.keyCode === 9)) { // comma or enter or tab
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.addressSelector.chooseSelection();
|
||||
if (this.addressSelector) this.addressSelector.chooseSelection();
|
||||
} else if (this.refs.textinput.value.length === 0 && this.state.inviteList.length && e.keyCode === 8) { // backspace
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
@ -168,74 +179,36 @@ module.exports = React.createClass({
|
|||
|
||||
onQueryChanged: function(ev) {
|
||||
const query = ev.target.value.toLowerCase();
|
||||
let queryList = [];
|
||||
|
||||
if (query.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.queryChangedDebouncer) {
|
||||
clearTimeout(this.queryChangedDebouncer);
|
||||
}
|
||||
this.queryChangedDebouncer = setTimeout(() => {
|
||||
// Only do search if there is something to search
|
||||
if (query.length > 0 && query != '@') {
|
||||
this._userList.forEach((user) => {
|
||||
if (user.userId.toLowerCase().indexOf(query) === -1 &&
|
||||
user.displayName.toLowerCase().indexOf(query) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Return objects, structure of which is defined
|
||||
// by InviteAddressType
|
||||
queryList.push({
|
||||
addressType: 'mx',
|
||||
address: user.userId,
|
||||
displayName: user.displayName,
|
||||
avatarMxc: user.avatarUrl,
|
||||
isKnown: true,
|
||||
order: user.getLastActiveTs(),
|
||||
});
|
||||
});
|
||||
|
||||
queryList = queryList.sort((a,b) => {
|
||||
return a.order < b.order;
|
||||
});
|
||||
|
||||
// If the query is a valid address, add an entry for that
|
||||
// This is important, otherwise there's no way to invite
|
||||
// a perfectly valid address if there are close matches.
|
||||
const addrType = getAddressType(query);
|
||||
if (addrType !== null) {
|
||||
queryList.unshift({
|
||||
addressType: addrType,
|
||||
address: query,
|
||||
isKnown: false,
|
||||
});
|
||||
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
|
||||
if (addrType == 'email') {
|
||||
this._lookupThreepid(addrType, query).done();
|
||||
}
|
||||
// Only do search if there is something to search
|
||||
if (query.length > 0 && query != '@' && query.length >= 2) {
|
||||
this.queryChangedDebouncer = setTimeout(() => {
|
||||
if (this.state.serverSupportsUserDirectory) {
|
||||
this._doUserDirectorySearch(query);
|
||||
} else {
|
||||
this._doLocalSearch(query);
|
||||
}
|
||||
}
|
||||
}, QUERY_USER_DIRECTORY_DEBOUNCE_MS);
|
||||
} else {
|
||||
this.setState({
|
||||
queryList: queryList,
|
||||
error: false,
|
||||
}, () => {
|
||||
this.addressSelector.moveSelectionTop();
|
||||
queryList: [],
|
||||
query: "",
|
||||
searchError: null,
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
},
|
||||
|
||||
onDismissed: function(index) {
|
||||
var self = this;
|
||||
return function() {
|
||||
return () => {
|
||||
var inviteList = self.state.inviteList.slice();
|
||||
inviteList.splice(index, 1);
|
||||
self.setState({
|
||||
inviteList: inviteList,
|
||||
queryList: [],
|
||||
query: "",
|
||||
});
|
||||
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
|
||||
};
|
||||
|
@ -254,10 +227,108 @@ module.exports = React.createClass({
|
|||
this.setState({
|
||||
inviteList: inviteList,
|
||||
queryList: [],
|
||||
query: "",
|
||||
});
|
||||
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
|
||||
},
|
||||
|
||||
_doUserDirectorySearch: function(query) {
|
||||
this.setState({
|
||||
busy: true,
|
||||
query,
|
||||
searchError: null,
|
||||
});
|
||||
MatrixClientPeg.get().searchUserDirectory({
|
||||
term: query,
|
||||
}).then((resp) => {
|
||||
// The query might have changed since we sent the request, so ignore
|
||||
// responses for anything other than the latest query.
|
||||
if (this.state.query !== query) {
|
||||
return;
|
||||
}
|
||||
this._processResults(resp.results, query);
|
||||
}).catch((err) => {
|
||||
console.error('Error whilst searching user directory: ', err);
|
||||
this.setState({
|
||||
searchError: err.errcode ? err.message : _t('Something went wrong!'),
|
||||
});
|
||||
if (err.errcode === 'M_UNRECOGNIZED') {
|
||||
this.setState({
|
||||
serverSupportsUserDirectory: false,
|
||||
});
|
||||
// Do a local search immediately
|
||||
this._doLocalSearch(query);
|
||||
}
|
||||
}).done(() => {
|
||||
this.setState({
|
||||
busy: false,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_doLocalSearch: function(query) {
|
||||
this.setState({
|
||||
query,
|
||||
searchError: null,
|
||||
});
|
||||
const results = [];
|
||||
MatrixClientPeg.get().getUsers().forEach((user) => {
|
||||
if (user.userId.toLowerCase().indexOf(query) === -1 &&
|
||||
user.displayName.toLowerCase().indexOf(query) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Put results in the format of the new API
|
||||
results.push({
|
||||
user_id: user.userId,
|
||||
display_name: user.displayName,
|
||||
avatar_url: user.avatarUrl,
|
||||
});
|
||||
});
|
||||
this._processResults(results, query);
|
||||
},
|
||||
|
||||
_processResults: function(results, query) {
|
||||
const queryList = [];
|
||||
results.forEach((user) => {
|
||||
if (user.user_id === MatrixClientPeg.get().credentials.userId) {
|
||||
return;
|
||||
}
|
||||
// Return objects, structure of which is defined
|
||||
// by InviteAddressType
|
||||
queryList.push({
|
||||
addressType: 'mx',
|
||||
address: user.user_id,
|
||||
displayName: user.display_name,
|
||||
avatarMxc: user.avatar_url,
|
||||
isKnown: true,
|
||||
});
|
||||
});
|
||||
|
||||
// If the query is a valid address, add an entry for that
|
||||
// This is important, otherwise there's no way to invite
|
||||
// a perfectly valid address if there are close matches.
|
||||
const addrType = getAddressType(query);
|
||||
if (addrType !== null) {
|
||||
queryList.unshift({
|
||||
addressType: addrType,
|
||||
address: query,
|
||||
isKnown: false,
|
||||
});
|
||||
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
|
||||
if (addrType == 'email') {
|
||||
this._lookupThreepid(addrType, query).done();
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
queryList,
|
||||
error: false,
|
||||
}, () => {
|
||||
if (this.addressSelector) this.addressSelector.moveSelectionTop();
|
||||
});
|
||||
},
|
||||
|
||||
_getDirectMessageRooms: function(addr) {
|
||||
const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
|
||||
const dmRooms = dmRoomMap.getDMRoomsForUserId(addr);
|
||||
|
@ -342,16 +413,6 @@ module.exports = React.createClass({
|
|||
this.props.onFinished(true, addrTexts);
|
||||
},
|
||||
|
||||
_updateUserList: function() {
|
||||
// Get all the users
|
||||
this._userList = MatrixClientPeg.get().getUsers();
|
||||
// Remove current user
|
||||
const meIx = this._userList.findIndex((u) => {
|
||||
return u.userId === MatrixClientPeg.get().credentials.userId;
|
||||
});
|
||||
this._userList.splice(meIx, 1);
|
||||
},
|
||||
|
||||
_isOnInviteList: function(uid) {
|
||||
for (let i = 0; i < this.state.inviteList.length; i++) {
|
||||
if (
|
||||
|
@ -419,6 +480,7 @@ module.exports = React.createClass({
|
|||
this.setState({
|
||||
inviteList: inviteList,
|
||||
queryList: [],
|
||||
query: "",
|
||||
});
|
||||
if (this._cancelThreepidLookup) this._cancelThreepidLookup();
|
||||
return inviteList;
|
||||
|
@ -454,7 +516,7 @@ module.exports = React.createClass({
|
|||
displayName: res.displayname,
|
||||
avatarMxc: res.avatar_url,
|
||||
isKnown: true,
|
||||
}]
|
||||
}],
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -486,23 +548,27 @@ module.exports = React.createClass({
|
|||
placeholder={this.props.placeholder}
|
||||
defaultValue={this.props.value}
|
||||
autoFocus={this.props.focus}>
|
||||
</textarea>
|
||||
</textarea>,
|
||||
);
|
||||
|
||||
var error;
|
||||
var addressSelector;
|
||||
let error;
|
||||
let addressSelector;
|
||||
if (this.state.error) {
|
||||
error = <div className="mx_ChatInviteDialog_error">{_t("You have entered an invalid contact. Try using their Matrix ID or email address.")}</div>;
|
||||
} else if (this.state.searchError) {
|
||||
error = <div className="mx_ChatInviteDialog_error">{this.state.searchError}</div>;
|
||||
} else if (
|
||||
this.state.query.length > 0 &&
|
||||
this.state.queryList.length === 0 &&
|
||||
!this.state.busy
|
||||
) {
|
||||
error = <div className="mx_ChatInviteDialog_error">{_t("No results")}</div>;
|
||||
} else {
|
||||
const addressSelectorHeader = <div className="mx_ChatInviteDialog_addressSelectHeader">
|
||||
Searching known users
|
||||
</div>;
|
||||
addressSelector = (
|
||||
<AddressSelector ref={(ref) => {this.addressSelector = ref;}}
|
||||
addressList={ this.state.queryList }
|
||||
onSelected={ this.onSelected }
|
||||
truncateAt={ TRUNCATE_QUERY_LIST }
|
||||
header={ addressSelectorHeader }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ export default class DeactivateAccountDialog extends React.Component {
|
|||
passwordBoxClass = 'error';
|
||||
}
|
||||
|
||||
const okLabel = this.state.busy ? <Loader /> : 'Deactivate Account';
|
||||
const okLabel = this.state.busy ? <Loader /> : _t('Deactivate Account');
|
||||
const okEnabled = this.state.confirmButtonEnabled && !this.state.busy;
|
||||
|
||||
let cancelButton = null;
|
||||
|
|
|
@ -78,7 +78,7 @@ export default React.createClass({
|
|||
<AccessibleButton onClick={this._onDismissClick}
|
||||
className="mx_UserSettings_button"
|
||||
>
|
||||
Dismiss
|
||||
{_t("Dismiss")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,72 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
* Modal.createDialog(NeedToRegisterDialog, {
|
||||
* title: "some text", (default: "Registration required")
|
||||
* description: "some more text",
|
||||
* onFinished: someFunction,
|
||||
* });
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import dis from '../../../dispatcher';
|
||||
import sdk from '../../../index';
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'NeedToRegisterDialog',
|
||||
propTypes: {
|
||||
title: React.PropTypes.string,
|
||||
description: React.PropTypes.oneOfType([
|
||||
React.PropTypes.element,
|
||||
React.PropTypes.string,
|
||||
]),
|
||||
onFinished: React.PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
onRegisterClicked: function() {
|
||||
dis.dispatch({
|
||||
action: "start_upgrade_registration",
|
||||
});
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
return (
|
||||
<BaseDialog className="mx_NeedToRegisterDialog"
|
||||
onFinished={this.props.onFinished}
|
||||
title={this.props.title || _t('Registration required')}
|
||||
>
|
||||
<div className="mx_Dialog_content">
|
||||
{this.props.description || _t('A registered account is required for this action')}
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button className="mx_Dialog_primary" onClick={this.props.onFinished} autoFocus={true}>
|
||||
{_t("Cancel")}
|
||||
</button>
|
||||
<button onClick={this.onRegisterClicked}>
|
||||
{_t("Register")}
|
||||
</button>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
},
|
||||
});
|
|
@ -18,7 +18,7 @@ import React from 'react';
|
|||
import sdk from '../../../index';
|
||||
import SdkConfig from '../../../SdkConfig';
|
||||
import Modal from '../../../Modal';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { _t, _tJsx } from '../../../languageHandler';
|
||||
|
||||
|
||||
export default React.createClass({
|
||||
|
@ -44,8 +44,11 @@ export default React.createClass({
|
|||
|
||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||
bugreport = (
|
||||
<p>Otherwise, <a onClick={this._sendBugReport} href='#'>
|
||||
click here</a> to send a bug report.
|
||||
<p>
|
||||
{_tJsx(
|
||||
"Otherwise, <a>click here</a> to send a bug report.",
|
||||
/<a>(.*?)<\/a>/, (sub) => <a onClick={this._sendBugReport} key="bugreport" href='#'>{sub}</a>,
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
|
164
src/components/views/dialogs/SetEmailDialog.js
Normal file
164
src/components/views/dialogs/SetEmailDialog.js
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright 2017 Vector Creations 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 sdk from '../../../index';
|
||||
import Email from '../../../email';
|
||||
import AddThreepid from '../../../AddThreepid';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Modal from '../../../Modal';
|
||||
|
||||
|
||||
/**
|
||||
* Prompt the user to set an email address.
|
||||
*
|
||||
* On success, `onFinished(true)` is called.
|
||||
*/
|
||||
export default React.createClass({
|
||||
displayName: 'SetEmailDialog',
|
||||
propTypes: {
|
||||
onFinished: React.PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
emailAddress: null,
|
||||
emailBusy: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
},
|
||||
|
||||
onEmailAddressChanged: function(value) {
|
||||
this.setState({
|
||||
emailAddress: value,
|
||||
});
|
||||
},
|
||||
|
||||
onSubmit: function() {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
|
||||
const emailAddress = this.state.emailAddress;
|
||||
if (!Email.looksValid(emailAddress)) {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Invalid Email Address"),
|
||||
description: _t("This doesn't appear to be a valid email address"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
this._addThreepid = new AddThreepid();
|
||||
// we always bind emails when registering, so let's do the
|
||||
// same here.
|
||||
this._addThreepid.addEmailAddress(emailAddress, true).done(() => {
|
||||
Modal.createDialog(QuestionDialog, {
|
||||
title: _t("Verification Pending"),
|
||||
description: _t(
|
||||
"Please check your email and click on the link it contains. Once this " +
|
||||
"is done, click continue.",
|
||||
),
|
||||
button: _t('Continue'),
|
||||
onFinished: this.onEmailDialogFinished,
|
||||
});
|
||||
}, (err) => {
|
||||
this.setState({emailBusy: false});
|
||||
console.error("Unable to add email address " + emailAddress + " " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to add email address"),
|
||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||
});
|
||||
});
|
||||
this.setState({emailBusy: true});
|
||||
},
|
||||
|
||||
onCancelled: function() {
|
||||
this.props.onFinished(false);
|
||||
},
|
||||
|
||||
onEmailDialogFinished: function(ok) {
|
||||
if (ok) {
|
||||
this.verifyEmailAddress();
|
||||
} else {
|
||||
this.setState({emailBusy: false});
|
||||
}
|
||||
},
|
||||
|
||||
verifyEmailAddress: function() {
|
||||
this._addThreepid.checkEmailLinkClicked().done(() => {
|
||||
this.props.onFinished(true);
|
||||
}, (err) => {
|
||||
this.setState({emailBusy: false});
|
||||
if (err.errcode == 'M_THREEPID_AUTH_FAILED') {
|
||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
const message = _t("Unable to verify email address.") + " " +
|
||||
_t("Please check your email and click on the link it contains. Once this is done, click continue.");
|
||||
Modal.createDialog(QuestionDialog, {
|
||||
title: _t("Verification Pending"),
|
||||
description: message,
|
||||
button: _t('Continue'),
|
||||
onFinished: this.onEmailDialogFinished,
|
||||
});
|
||||
} else {
|
||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
console.error("Unable to verify email address: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to verify email address."),
|
||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
const Spinner = sdk.getComponent('elements.Spinner');
|
||||
const EditableText = sdk.getComponent('elements.EditableText');
|
||||
|
||||
const emailInput = this.state.emailBusy ? <Spinner /> : <EditableText
|
||||
className="mx_SetEmailDialog_email_input"
|
||||
placeholder={ _t("Email address") }
|
||||
placeholderClassName="mx_SetEmailDialog_email_input_placeholder"
|
||||
blurToCancel={ false }
|
||||
onValueChanged={ this.onEmailAddressChanged } />;
|
||||
|
||||
return (
|
||||
<BaseDialog className="mx_SetEmailDialog"
|
||||
onFinished={this.onCancelled}
|
||||
title={this.props.title}
|
||||
>
|
||||
<div className="mx_Dialog_content">
|
||||
<p>
|
||||
{ _t('This will allow you to reset your password and receive notifications.') }
|
||||
</p>
|
||||
{ emailInput }
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<input className="mx_Dialog_primary"
|
||||
type="submit"
|
||||
value={_t("Continue")}
|
||||
onClick={this.onSubmit}
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
value={_t("Cancel")}
|
||||
onClick={this.onCancelled}
|
||||
/>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
},
|
||||
});
|
|
@ -125,7 +125,7 @@ export default React.createClass({
|
|||
break;
|
||||
case "M_INVALID_USERNAME":
|
||||
newState.usernameError = _t(
|
||||
'Username invalid: %(errMessage)',
|
||||
'Username invalid: %(errMessage)s',
|
||||
{ errMessage: err.message},
|
||||
);
|
||||
break;
|
||||
|
@ -139,8 +139,8 @@ export default React.createClass({
|
|||
break;
|
||||
default:
|
||||
newState.usernameError = _t(
|
||||
'An error occurred: %(errMessage)',
|
||||
{ errMessage: err.message },
|
||||
'An error occurred: %(error_string)s',
|
||||
{ error_string: err.message },
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ export default React.createClass({
|
|||
console.log("UnknownDeviceDialog closed by escape");
|
||||
this.props.onFinished();
|
||||
}}
|
||||
title='Room contains unknown devices'
|
||||
title={_t('Room contains unknown devices')}
|
||||
>
|
||||
<GeminiScrollbar autoshow={false} className="mx_Dialog_content">
|
||||
<h4>
|
||||
|
@ -162,7 +162,7 @@ export default React.createClass({
|
|||
this.props.onFinished();
|
||||
Resend.resendUnsentEvents(this.props.room);
|
||||
}}>
|
||||
Send anyway
|
||||
{_t("Send anyway")}
|
||||
</button>
|
||||
<button className="mx_Dialog_primary" autoFocus={ true }
|
||||
onClick={() => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue