Merge branch 'develop' into rob/apps
This commit is contained in:
commit
d67e7289e8
30 changed files with 1299 additions and 512 deletions
|
@ -35,7 +35,7 @@ import * as Rooms from '../../Rooms';
|
|||
import linkifyMatrix from "../../linkify-matrix";
|
||||
import * as Lifecycle from '../../Lifecycle';
|
||||
// LifecycleStore is not used but does listen to and dispatch actions
|
||||
import LifecycleStore from '../../stores/LifecycleStore';
|
||||
require('../../stores/LifecycleStore');
|
||||
import RoomViewStore from '../../stores/RoomViewStore';
|
||||
import PageTypes from '../../PageTypes';
|
||||
|
||||
|
@ -128,11 +128,6 @@ module.exports = React.createClass({
|
|||
hasNewVersion: false,
|
||||
newVersionReleaseNotes: null,
|
||||
|
||||
// The username to default to when upgrading an account from a guest
|
||||
upgradeUsername: null,
|
||||
// The access token we had for our guest account, used when upgrading to a normal account
|
||||
guestAccessToken: null,
|
||||
|
||||
// Parameters used in the registration dance with the IS
|
||||
register_client_secret: null,
|
||||
register_session_id: null,
|
||||
|
@ -191,7 +186,7 @@ module.exports = React.createClass({
|
|||
componentWillMount: function() {
|
||||
SdkConfig.put(this.props.config);
|
||||
|
||||
RoomViewStore.addListener(this._onRoomViewStoreUpdated);
|
||||
this._roomViewStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdated);
|
||||
this._onRoomViewStoreUpdated();
|
||||
|
||||
if (!UserSettingsStore.getLocalSetting('analyticsOptOut', false)) Analytics.enable();
|
||||
|
@ -300,6 +295,7 @@ module.exports = React.createClass({
|
|||
UDEHandler.stopListening();
|
||||
window.removeEventListener("focus", this.onFocus);
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
this._roomViewStoreToken.remove();
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
|
@ -315,8 +311,6 @@ module.exports = React.createClass({
|
|||
viewUserId: null,
|
||||
loggedIn: false,
|
||||
ready: false,
|
||||
upgradeUsername: null,
|
||||
guestAccessToken: null,
|
||||
};
|
||||
Object.assign(newState, state);
|
||||
this.setState(newState);
|
||||
|
@ -351,25 +345,6 @@ module.exports = React.createClass({
|
|||
screen: 'post_registration',
|
||||
});
|
||||
break;
|
||||
case 'start_upgrade_registration':
|
||||
// also stash our credentials, then if we restore the session,
|
||||
// we can just do it the same way whether we started upgrade
|
||||
// registration or explicitly logged out
|
||||
this.setStateForNewScreen({
|
||||
guestCreds: MatrixClientPeg.getCredentials(),
|
||||
screen: "register",
|
||||
upgradeUsername: MatrixClientPeg.get().getUserIdLocalpart(),
|
||||
guestAccessToken: MatrixClientPeg.get().getAccessToken(),
|
||||
});
|
||||
|
||||
// stop the client: if we are syncing whilst the registration
|
||||
// is completed in another browser, we'll be 401ed for using
|
||||
// a guest access token for a non-guest account.
|
||||
// It will be restarted in onReturnToGuestClick
|
||||
Lifecycle.stopMatrixClient();
|
||||
|
||||
this.notifyNewScreen('register');
|
||||
break;
|
||||
case 'start_password_recovery':
|
||||
this.setStateForNewScreen({
|
||||
screen: 'forgot_password',
|
||||
|
@ -745,8 +720,8 @@ module.exports = React.createClass({
|
|||
title: _t('Create Room'),
|
||||
description: _t('Room name (optional)'),
|
||||
button: _t('Create Room'),
|
||||
onFinished: (should_create, name) => {
|
||||
if (should_create) {
|
||||
onFinished: (shouldCreate, name) => {
|
||||
if (shouldCreate) {
|
||||
const createOpts = {};
|
||||
if (name) createOpts.name = name;
|
||||
createRoom({createOpts}).done();
|
||||
|
@ -1401,8 +1376,6 @@ module.exports = React.createClass({
|
|||
idSid={this.state.register_id_sid}
|
||||
email={this.props.startingFragmentQueryParams.email}
|
||||
referrer={this.props.startingFragmentQueryParams.referrer}
|
||||
username={this.state.upgradeUsername}
|
||||
guestAccessToken={this.state.guestAccessToken}
|
||||
defaultHsUrl={this.getDefaultHsUrl()}
|
||||
defaultIsUrl={this.getDefaultIsUrl()}
|
||||
brand={this.props.config.brand}
|
||||
|
|
|
@ -110,6 +110,13 @@ const ANALYTICS_SETTINGS_LABELS = [
|
|||
},
|
||||
];
|
||||
|
||||
const WEBRTC_SETTINGS_LABELS = [
|
||||
{
|
||||
id: 'webRtcForceTURN',
|
||||
label: 'Disable Peer-to-Peer for 1:1 calls',
|
||||
},
|
||||
];
|
||||
|
||||
// Warning: Each "label" string below must be added to i18n/strings/en_EN.json,
|
||||
// since they will be translated when rendered.
|
||||
const CRYPTO_SETTINGS_LABELS = [
|
||||
|
@ -310,11 +317,6 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
onAvatarPickerClick: function(ev) {
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
dis.dispatch({action: 'view_set_mxid'});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.refs.file_label) {
|
||||
this.refs.file_label.click();
|
||||
}
|
||||
|
@ -389,17 +391,14 @@ module.exports = React.createClass({
|
|||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Success"),
|
||||
description: _t("Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them") + ".",
|
||||
description: _t(
|
||||
"Your password was successfully changed. You will not receive " +
|
||||
"push notifications on other devices until you log back in to them",
|
||||
) + ".",
|
||||
});
|
||||
dis.dispatch({action: 'password_changed'});
|
||||
},
|
||||
|
||||
onUpgradeClicked: function() {
|
||||
dis.dispatch({
|
||||
action: "start_upgrade_registration",
|
||||
});
|
||||
},
|
||||
|
||||
onEnableNotificationsChange: function(event) {
|
||||
UserSettingsStore.setEnableNotifications(event.target.checked);
|
||||
},
|
||||
|
@ -427,7 +426,10 @@ module.exports = React.createClass({
|
|||
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."),
|
||||
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,
|
||||
});
|
||||
|
@ -447,7 +449,7 @@ module.exports = React.createClass({
|
|||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
Modal.createDialog(QuestionDialog, {
|
||||
title: _t("Remove Contact Information?"),
|
||||
description: _t("Remove %(threePid)s?", { threePid : threepid.address }),
|
||||
description: _t("Remove %(threePid)s?", { threePid: threepid.address }),
|
||||
button: _t('Remove'),
|
||||
onFinished: (submit) => {
|
||||
if (submit) {
|
||||
|
@ -489,8 +491,8 @@ module.exports = React.createClass({
|
|||
this.setState({email_add_pending: false});
|
||||
if (err.errcode == 'M_THREEPID_AUTH_FAILED') {
|
||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
let 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.");
|
||||
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,
|
||||
|
@ -608,7 +610,7 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
_renderLanguageSetting: function () {
|
||||
_renderLanguageSetting: function() {
|
||||
const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown');
|
||||
return <div>
|
||||
<label htmlFor="languageSelector">{_t('Interface Language')}</label>
|
||||
|
@ -639,7 +641,7 @@ module.exports = React.createClass({
|
|||
<input id="urlPreviewsDisabled"
|
||||
type="checkbox"
|
||||
defaultChecked={ UserSettingsStore.getUrlPreviewsDisabled() }
|
||||
onChange={ (e) => UserSettingsStore.setUrlPreviewsDisabled(e.target.checked) }
|
||||
onChange={ this._onPreviewsDisabledChanged }
|
||||
/>
|
||||
<label htmlFor="urlPreviewsDisabled">
|
||||
{ _t("Disable inline URL previews by default") }
|
||||
|
@ -647,17 +649,24 @@ module.exports = React.createClass({
|
|||
</div>;
|
||||
},
|
||||
|
||||
_onPreviewsDisabledChanged: function(e) {
|
||||
UserSettingsStore.setUrlPreviewsDisabled(e.target.checked);
|
||||
},
|
||||
|
||||
_renderSyncedSetting: function(setting) {
|
||||
// TODO: this ought to be a separate component so that we don't need
|
||||
// to rebind the onChange each time we render
|
||||
|
||||
const onChange = (e) => {
|
||||
UserSettingsStore.setSyncedSetting(setting.id, e.target.checked);
|
||||
if (setting.fn) setting.fn(e.target.checked);
|
||||
};
|
||||
|
||||
return <div className="mx_UserSettings_toggle" key={ setting.id }>
|
||||
<input id={ setting.id }
|
||||
type="checkbox"
|
||||
defaultChecked={ this._syncedSettings[setting.id] }
|
||||
onChange={
|
||||
(e) => {
|
||||
UserSettingsStore.setSyncedSetting(setting.id, e.target.checked);
|
||||
if (setting.fn) setting.fn(e.target.checked);
|
||||
}
|
||||
}
|
||||
onChange={ onChange }
|
||||
/>
|
||||
<label htmlFor={ setting.id }>
|
||||
{ _t(setting.label) }
|
||||
|
@ -666,22 +675,24 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_renderThemeSelector: function(setting) {
|
||||
// TODO: this ought to be a separate component so that we don't need
|
||||
// to rebind the onChange each time we render
|
||||
const onChange = (e) => {
|
||||
if (e.target.checked) {
|
||||
UserSettingsStore.setSyncedSetting(setting.id, setting.value);
|
||||
}
|
||||
dis.dispatch({
|
||||
action: 'set_theme',
|
||||
value: setting.value,
|
||||
});
|
||||
};
|
||||
return <div className="mx_UserSettings_toggle" key={ setting.id + "_" + setting.value }>
|
||||
<input id={ setting.id + "_" + setting.value }
|
||||
type="radio"
|
||||
name={ setting.id }
|
||||
value={ setting.value }
|
||||
defaultChecked={ this._syncedSettings[setting.id] === setting.value }
|
||||
onChange={ (e) => {
|
||||
if (e.target.checked) {
|
||||
UserSettingsStore.setSyncedSetting(setting.id, setting.value);
|
||||
}
|
||||
dis.dispatch({
|
||||
action: 'set_theme',
|
||||
value: setting.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
onChange={ onChange }
|
||||
/>
|
||||
<label htmlFor={ setting.id + "_" + setting.value }>
|
||||
{ setting.label }
|
||||
|
@ -720,8 +731,10 @@ module.exports = React.createClass({
|
|||
<h3>{ _t("Cryptography") }</h3>
|
||||
<div className="mx_UserSettings_section mx_UserSettings_cryptoSection">
|
||||
<ul>
|
||||
<li><label>{_t("Device ID:")}</label> <span><code>{deviceId}</code></span></li>
|
||||
<li><label>{_t("Device key:")}</label> <span><code><b>{identityKey}</b></code></span></li>
|
||||
<li><label>{_t("Device ID:")}</label>
|
||||
<span><code>{deviceId}</code></span></li>
|
||||
<li><label>{_t("Device key:")}</label>
|
||||
<span><code><b>{identityKey}</b></code></span></li>
|
||||
</ul>
|
||||
{ importExportButtons }
|
||||
</div>
|
||||
|
@ -733,16 +746,18 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_renderLocalSetting: function(setting) {
|
||||
// TODO: this ought to be a separate component so that we don't need
|
||||
// to rebind the onChange each time we render
|
||||
const onChange = (e) => {
|
||||
UserSettingsStore.setLocalSetting(setting.id, e.target.checked);
|
||||
if (setting.fn) setting.fn(e.target.checked);
|
||||
};
|
||||
|
||||
return <div className="mx_UserSettings_toggle" key={ setting.id }>
|
||||
<input id={ setting.id }
|
||||
type="checkbox"
|
||||
defaultChecked={ this._localSettings[setting.id] }
|
||||
onChange={
|
||||
(e) => {
|
||||
UserSettingsStore.setLocalSetting(setting.id, e.target.checked);
|
||||
if (setting.fn) setting.fn(e.target.checked);
|
||||
}
|
||||
}
|
||||
onChange={ onChange }
|
||||
/>
|
||||
<label htmlFor={ setting.id }>
|
||||
{ _t(setting.label) }
|
||||
|
@ -794,26 +809,27 @@ module.exports = React.createClass({
|
|||
if (this.props.enableLabs === false) return null;
|
||||
UserSettingsStore.doTranslations();
|
||||
|
||||
const features = UserSettingsStore.LABS_FEATURES.map((feature) => (
|
||||
<div key={feature.id} className="mx_UserSettings_toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={feature.id}
|
||||
name={feature.id}
|
||||
defaultChecked={ UserSettingsStore.isFeatureEnabled(feature.id) }
|
||||
onChange={(e) => {
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
e.target.checked = false;
|
||||
dis.dispatch({action: 'view_set_mxid'});
|
||||
return;
|
||||
}
|
||||
const features = UserSettingsStore.LABS_FEATURES.map((feature) => {
|
||||
// TODO: this ought to be a separate component so that we don't need
|
||||
// to rebind the onChange each time we render
|
||||
const onChange = (e) => {
|
||||
UserSettingsStore.setFeatureEnabled(feature.id, e.target.checked);
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
UserSettingsStore.setFeatureEnabled(feature.id, e.target.checked);
|
||||
this.forceUpdate();
|
||||
}}/>
|
||||
<label htmlFor={feature.id}>{feature.name}</label>
|
||||
</div>
|
||||
));
|
||||
return (
|
||||
<div key={feature.id} className="mx_UserSettings_toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={feature.id}
|
||||
name={feature.id}
|
||||
defaultChecked={ UserSettingsStore.isFeatureEnabled(feature.id) }
|
||||
onChange={ onChange }
|
||||
/>
|
||||
<label htmlFor={feature.id}>{feature.name}</label>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<h3>{ _t("Labs") }</h3>
|
||||
|
@ -826,9 +842,6 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_renderDeactivateAccount: function() {
|
||||
// We can't deactivate a guest account.
|
||||
if (MatrixClientPeg.get().isGuest()) return null;
|
||||
|
||||
return <div>
|
||||
<h3>{ _t("Deactivate Account") }</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
|
@ -865,9 +878,10 @@ module.exports = React.createClass({
|
|||
if (!this.state.rejectingInvites) {
|
||||
// bind() the invited rooms so any new invites that may come in as this button is clicked
|
||||
// don't inadvertently get rejected as well.
|
||||
const onClick = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
|
||||
reject = (
|
||||
<AccessibleButton className="mx_UserSettings_button danger"
|
||||
onClick={this._onRejectAllInvitesClicked.bind(this, invitedRooms)}>
|
||||
onClick={onClick}>
|
||||
{_t("Reject all %(invitedRooms)s invites", {invitedRooms: invitedRooms.length})}
|
||||
</AccessibleButton>
|
||||
);
|
||||
|
@ -885,8 +899,6 @@ module.exports = React.createClass({
|
|||
const settings = this.state.electron_settings;
|
||||
if (!settings) return;
|
||||
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
return <div>
|
||||
<h3>{ _t('Desktop specific') }</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
|
@ -894,9 +906,7 @@ module.exports = React.createClass({
|
|||
<input type="checkbox"
|
||||
name="auto-launch"
|
||||
defaultChecked={settings['auto-launch']}
|
||||
onChange={(e) => {
|
||||
ipcRenderer.send('settings_set', 'auto-launch', e.target.checked);
|
||||
}}
|
||||
onChange={this._onAutoLaunchChanged}
|
||||
/>
|
||||
<label htmlFor="auto-launch">{_t('Start automatically after system login')}</label>
|
||||
</div>
|
||||
|
@ -904,6 +914,11 @@ module.exports = React.createClass({
|
|||
</div>;
|
||||
},
|
||||
|
||||
_onAutoLaunchChanged: function(e) {
|
||||
const {ipcRenderer} = require('electron');
|
||||
ipcRenderer.send('settings_set', 'auto-launch', e.target.checked);
|
||||
},
|
||||
|
||||
_mapWebRtcDevicesToSpans: function(devices) {
|
||||
return devices.map((device) => <span key={device.deviceId}>{device.label}</span>);
|
||||
},
|
||||
|
@ -937,16 +952,13 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
_renderWebRtcSettings: function() {
|
||||
_renderWebRtcDeviceSettings: function() {
|
||||
if (this.state.mediaDevices === false) {
|
||||
return <div>
|
||||
<h3>{_t('VoIP')}</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
<p className="mx_UserSettings_link" onClick={this._requestMediaPermissions}>
|
||||
{_t('Missing Media Permissions, click here to request.')}
|
||||
</p>
|
||||
</div>
|
||||
</div>;
|
||||
return (
|
||||
<p className="mx_UserSettings_link" onClick={this._requestMediaPermissions}>
|
||||
{_t('Missing Media Permissions, click here to request.')}
|
||||
</p>
|
||||
);
|
||||
} else if (!this.state.mediaDevices) return;
|
||||
|
||||
const Dropdown = sdk.getComponent('elements.Dropdown');
|
||||
|
@ -1000,10 +1012,17 @@ module.exports = React.createClass({
|
|||
}
|
||||
|
||||
return <div>
|
||||
<h3>{_t('VoIP')}</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
{microphoneDropdown}
|
||||
{webcamDropdown}
|
||||
</div>;
|
||||
},
|
||||
|
||||
_renderWebRtcSettings: function() {
|
||||
return <div>
|
||||
<h3>{_t('VoIP')}</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
{ WEBRTC_SETTINGS_LABELS.map(this._renderLocalSetting) }
|
||||
{ this._renderWebRtcDeviceSettings() }
|
||||
</div>
|
||||
</div>;
|
||||
},
|
||||
|
@ -1060,6 +1079,9 @@ module.exports = React.createClass({
|
|||
|
||||
const threepidsSection = this.state.threepids.map((val, pidIndex) => {
|
||||
const id = "3pid-" + val.address;
|
||||
// TODO; make a separate component to avoid having to rebind onClick
|
||||
// each time we render
|
||||
const onRemoveClick = (e) => this.onRemoveThreepidClicked(val);
|
||||
return (
|
||||
<div className="mx_UserSettings_profileTableRow" key={pidIndex}>
|
||||
<div className="mx_UserSettings_profileLabelCell">
|
||||
|
@ -1071,7 +1093,8 @@ module.exports = React.createClass({
|
|||
/>
|
||||
</div>
|
||||
<div className="mx_UserSettings_threepidButton mx_filterFlipColor">
|
||||
<img src="img/cancel-small.svg" width="14" height="14" alt={ _t("Remove") } onClick={this.onRemoveThreepidClicked.bind(this, val)} />
|
||||
<img src="img/cancel-small.svg" width="14" height="14" alt={ _t("Remove") }
|
||||
onClick={onRemoveClick} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1079,7 +1102,7 @@ module.exports = React.createClass({
|
|||
let addEmailSection;
|
||||
if (this.state.email_add_pending) {
|
||||
addEmailSection = <Loader key="_email_add_spinner" />;
|
||||
} else if (!MatrixClientPeg.get().isGuest()) {
|
||||
} else {
|
||||
addEmailSection = (
|
||||
<div className="mx_UserSettings_profileTableRow" key="_newEmail">
|
||||
<div className="mx_UserSettings_profileLabelCell">
|
||||
|
@ -1107,16 +1130,7 @@ module.exports = React.createClass({
|
|||
threepidsSection.push(addEmailSection);
|
||||
threepidsSection.push(addMsisdnSection);
|
||||
|
||||
let accountJsx;
|
||||
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
accountJsx = (
|
||||
<div className="mx_UserSettings_button" onClick={this.onUpgradeClicked}>
|
||||
{ _t("Create an account") }
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
accountJsx = (
|
||||
const accountJsx = (
|
||||
<ChangePassword
|
||||
className="mx_UserSettings_accountTable"
|
||||
rowClassName="mx_UserSettings_profileTableRow"
|
||||
|
@ -1125,10 +1139,10 @@ module.exports = React.createClass({
|
|||
buttonClassName="mx_UserSettings_button mx_UserSettings_changePasswordButton"
|
||||
onError={this.onPasswordChangeError}
|
||||
onFinished={this.onPasswordChanged} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
let notificationArea;
|
||||
if (!MatrixClientPeg.get().isGuest() && this.state.threepids !== undefined) {
|
||||
if (this.state.threepids !== undefined) {
|
||||
notificationArea = (<div>
|
||||
<h3>{ _t("Notifications") }</h3>
|
||||
|
||||
|
@ -1222,7 +1236,12 @@ module.exports = React.createClass({
|
|||
{ _t("Logged in as:") } {this._me}
|
||||
</div>
|
||||
<div className="mx_UserSettings_advanced">
|
||||
{_t('Access Token:')} <span className="mx_UserSettings_advanced_spoiler" onClick={this._showSpoiler} data-spoiler={ MatrixClientPeg.get().getAccessToken() }><{ _t("click to reveal") }></span>
|
||||
{_t('Access Token:')}
|
||||
<span className="mx_UserSettings_advanced_spoiler"
|
||||
onClick={this._showSpoiler}
|
||||
data-spoiler={ MatrixClientPeg.get().getAccessToken() }>
|
||||
<{ _t("click to reveal") }>
|
||||
</span>
|
||||
</div>
|
||||
<div className="mx_UserSettings_advanced">
|
||||
{ _t("Homeserver is") } { MatrixClientPeg.get().getHomeserverUrl() }
|
||||
|
|
|
@ -45,8 +45,6 @@ module.exports = React.createClass({
|
|||
brand: React.PropTypes.string,
|
||||
email: React.PropTypes.string,
|
||||
referrer: React.PropTypes.string,
|
||||
username: React.PropTypes.string,
|
||||
guestAccessToken: React.PropTypes.string,
|
||||
teamServerConfig: React.PropTypes.shape({
|
||||
// Email address to request new teams
|
||||
supportEmail: React.PropTypes.string.isRequired,
|
||||
|
@ -295,17 +293,6 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_makeRegisterRequest: function(auth) {
|
||||
let guestAccessToken = this.props.guestAccessToken;
|
||||
|
||||
if (
|
||||
this.state.formVals.username !== this.props.username ||
|
||||
this.state.hsUrl != this.props.defaultHsUrl
|
||||
) {
|
||||
// don't try to upgrade if we changed our username
|
||||
// or are registering on a different HS
|
||||
guestAccessToken = null;
|
||||
}
|
||||
|
||||
// Only send the bind params if we're sending username / pw params
|
||||
// (Since we need to send no params at all to use the ones saved in the
|
||||
// session).
|
||||
|
@ -320,7 +307,7 @@ module.exports = React.createClass({
|
|||
undefined, // session id: included in the auth dict already
|
||||
auth,
|
||||
bindThreepids,
|
||||
guestAccessToken,
|
||||
null,
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -357,10 +344,6 @@ module.exports = React.createClass({
|
|||
} else if (this.state.busy || this.state.teamServerBusy) {
|
||||
registerBody = <Spinner />;
|
||||
} else {
|
||||
let guestUsername = this.props.username;
|
||||
if (this.state.hsUrl != this.props.defaultHsUrl) {
|
||||
guestUsername = null;
|
||||
}
|
||||
let errorSection;
|
||||
if (this.state.errorText) {
|
||||
errorSection = <div className="mx_Login_error">{this.state.errorText}</div>;
|
||||
|
@ -374,7 +357,6 @@ module.exports = React.createClass({
|
|||
defaultPhoneNumber={this.state.formVals.phoneNumber}
|
||||
defaultPassword={this.state.formVals.password}
|
||||
teamsConfig={this.state.teamsConfig}
|
||||
guestUsername={guestUsername}
|
||||
minPasswordLength={MIN_PASSWORD_LENGTH}
|
||||
onError={this.onFormValidationFailed}
|
||||
onRegisterClick={this.onFormSubmit}
|
||||
|
|
|
@ -24,6 +24,7 @@ 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;
|
||||
|
@ -102,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);
|
||||
|
@ -112,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);
|
||||
}
|
||||
|
@ -238,6 +241,11 @@ module.exports = React.createClass({
|
|||
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);
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
});
|
|
@ -54,11 +54,6 @@ module.exports = React.createClass({
|
|||
})).required,
|
||||
}),
|
||||
|
||||
// A username that will be used if no username is entered.
|
||||
// Specifying this param will also warn the user that entering
|
||||
// a different username will cause a fresh account to be generated.
|
||||
guestUsername: React.PropTypes.string,
|
||||
|
||||
minPasswordLength: React.PropTypes.number,
|
||||
onError: React.PropTypes.func,
|
||||
onRegisterClick: React.PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
|
||||
|
@ -123,7 +118,7 @@ module.exports = React.createClass({
|
|||
_doSubmit: function(ev) {
|
||||
let email = this.refs.email.value.trim();
|
||||
var promise = this.props.onRegisterClick({
|
||||
username: this.refs.username.value.trim() || this.props.guestUsername,
|
||||
username: this.refs.username.value.trim(),
|
||||
password: this.refs.password.value.trim(),
|
||||
email: email,
|
||||
phoneCountry: this.state.phoneCountry,
|
||||
|
@ -191,7 +186,7 @@ module.exports = React.createClass({
|
|||
break;
|
||||
case FIELD_USERNAME:
|
||||
// XXX: SPEC-1
|
||||
var username = this.refs.username.value.trim() || this.props.guestUsername;
|
||||
var username = this.refs.username.value.trim();
|
||||
if (encodeURIComponent(username) != username) {
|
||||
this.markFieldValid(
|
||||
field_id,
|
||||
|
@ -339,9 +334,6 @@ module.exports = React.createClass({
|
|||
);
|
||||
|
||||
let placeholderUserName = _t("User name");
|
||||
if (this.props.guestUsername) {
|
||||
placeholderUserName += " " + _t("(default: %(userName)s)", {userName: this.props.guestUsername});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -354,9 +346,6 @@ module.exports = React.createClass({
|
|||
className={this._classForField(FIELD_USERNAME, 'mx_Login_field')}
|
||||
onBlur={function() {self.validateField(FIELD_USERNAME);}} />
|
||||
<br />
|
||||
{ this.props.guestUsername ?
|
||||
<div className="mx_Login_fieldLabel">{_t("Setting a user name will create a fresh account")}</div> : null
|
||||
}
|
||||
<input type="password" ref="password"
|
||||
className={this._classForField(FIELD_PASSWORD, 'mx_Login_field')}
|
||||
onBlur={function() {self.validateField(FIELD_PASSWORD);}}
|
||||
|
|
|
@ -62,8 +62,8 @@ module.exports = React.createClass({
|
|||
var url = ContentRepo.getHttpUriForMxc(
|
||||
MatrixClientPeg.get().getHomeserverUrl(),
|
||||
ev.getContent().url,
|
||||
14 * window.devicePixelRatio,
|
||||
14 * window.devicePixelRatio,
|
||||
Math.ceil(14 * window.devicePixelRatio),
|
||||
Math.ceil(14 * window.devicePixelRatio),
|
||||
'crop'
|
||||
);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ function parseIntWithDefault(val, def) {
|
|||
const BannedUser = React.createClass({
|
||||
propTypes: {
|
||||
member: React.PropTypes.object.isRequired, // js-sdk RoomMember
|
||||
reason: React.PropTypes.string,
|
||||
},
|
||||
|
||||
_onUnbanClick: function() {
|
||||
|
@ -73,10 +74,11 @@ const BannedUser = React.createClass({
|
|||
>
|
||||
{ _t('Unban') }
|
||||
</AccessibleButton>
|
||||
{this.props.member.userId}
|
||||
<strong>{this.props.member.name}</strong> {this.props.member.userId}
|
||||
{this.props.reason ? " " +_t('Reason') + ": " + this.props.reason : ""}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
@ -576,26 +578,24 @@ module.exports = React.createClass({
|
|||
{ _t('Never send encrypted messages to unverified devices in this room from this device') }.
|
||||
</label>;
|
||||
|
||||
if (!isEncrypted &&
|
||||
roomState.mayClientSendStateEvent("m.room.encryption", cli)) {
|
||||
if (!isEncrypted && roomState.mayClientSendStateEvent("m.room.encryption", cli)) {
|
||||
return (
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" ref="encrypt" onClick={ this.onEnableEncryptionClick }/>
|
||||
<img className="mx_RoomSettings_e2eIcon" src="img/e2e-unencrypted.svg" width="12" height="12" />
|
||||
<img className="mx_RoomSettings_e2eIcon mx_filterFlipColor" src="img/e2e-unencrypted.svg" width="12" height="12" />
|
||||
{ _t('Enable encryption') } { _t('(warning: cannot be disabled again!)') }
|
||||
</label>
|
||||
{ settings }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<label>
|
||||
{ isEncrypted
|
||||
? <img className="mx_RoomSettings_e2eIcon" src="img/e2e-verified.svg" width="10" height="12" />
|
||||
: <img className="mx_RoomSettings_e2eIcon" src="img/e2e-unencrypted.svg" width="12" height="12" />
|
||||
? <img className="mx_RoomSettings_e2eIcon mx_filterFlipColor" src="img/e2e-verified.svg" width="10" height="12" />
|
||||
: <img className="mx_RoomSettings_e2eIcon mx_filterFlipColor" src="img/e2e-unencrypted.svg" width="12" height="12" />
|
||||
}
|
||||
{ isEncrypted ? _t("Encryption is enabled in this room") : _t("Encryption is not enabled in this room") }.
|
||||
</label>
|
||||
|
@ -664,16 +664,17 @@ module.exports = React.createClass({
|
|||
userLevelsSection = <div>{ _t('No users have specific privileges in this room') }.</div>;
|
||||
}
|
||||
|
||||
var banned = this.props.room.getMembersWithMembership("ban");
|
||||
var bannedUsersSection;
|
||||
const banned = this.props.room.getMembersWithMembership("ban");
|
||||
let bannedUsersSection;
|
||||
if (banned.length) {
|
||||
bannedUsersSection =
|
||||
<div>
|
||||
<h3>{ _t('Banned users') }</h3>
|
||||
<ul className="mx_RoomSettings_banned">
|
||||
{banned.map(function(member) {
|
||||
const banEvent = member.events.member.getContent();
|
||||
return (
|
||||
<BannedUser key={member.userId} member={member} />
|
||||
<BannedUser key={member.userId} member={member} reason={banEvent.reason} />
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue