Merge branch 'develop' into rob/apps

This commit is contained in:
Robert Swain 2017-06-13 15:50:43 +02:00
commit d67e7289e8
30 changed files with 1299 additions and 512 deletions

View file

@ -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}

View file

@ -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() }>&lt;{ _t("click to reveal") }&gt;</span>
{_t('Access Token:')}
<span className="mx_UserSettings_advanced_spoiler"
onClick={this._showSpoiler}
data-spoiler={ MatrixClientPeg.get().getAccessToken() }>
&lt;{ _t("click to reveal") }&gt;
</span>
</div>
<div className="mx_UserSettings_advanced">
{ _t("Homeserver is") } { MatrixClientPeg.get().getHomeserverUrl() }

View file

@ -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}

View file

@ -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);

View file

@ -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>
);
},
});

View file

@ -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);}}

View file

@ -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'
);

View file

@ -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>