Fix merge conflict

This commit is contained in:
Stefan Parviainen 2017-10-02 17:57:22 +02:00
commit a96169e80e
74 changed files with 506 additions and 438 deletions

View file

@ -40,6 +40,19 @@ module.exports = {
}], }],
"react/jsx-key": ["error"], "react/jsx-key": ["error"],
// Assert no spacing in JSX curly brackets
// <Element prop={ consideredError} prop={notConsideredError} />
//
// https://github.com/yannickcr/eslint-plugin-react/blob/HEAD/docs/rules/jsx-curly-spacing.md
"react/jsx-curly-spacing": ["error", {"when": "never", "children": {"when": "always"}}],
// Assert spacing before self-closing JSX tags, and no spacing before or
// after the closing slash, and no spacing after the opening bracket of
// the opening tag or closing tag.
//
// https://github.com/yannickcr/eslint-plugin-react/blob/HEAD/docs/rules/jsx-tag-spacing.md
"react/jsx-tag-spacing": ["error"],
/** flowtype **/ /** flowtype **/
"flowtype/require-parameter-type": ["warn", { "flowtype/require-parameter-type": ["warn", {
"excludeArrowFunctions": true, "excludeArrowFunctions": true,

View file

@ -21,9 +21,7 @@ npm run test -- --no-colors
npm run lintall -- -f checkstyle -o eslint.xml || true npm run lintall -- -f checkstyle -o eslint.xml || true
# re-run the linter, excluding any files known to have errors or warnings. # re-run the linter, excluding any files known to have errors or warnings.
./node_modules/.bin/eslint --max-warnings 0 \ npm run lintwithexclusions
--ignore-path .eslintignore.errorfiles \
src test
# delete the old tarball, if it exists # delete the old tarball, if it exists
rm -f matrix-react-sdk-*.tgz rm -f matrix-react-sdk-*.tgz

View file

@ -39,6 +39,7 @@
"start": "parallelshell \"npm run build:watch\" \"npm run reskindex:watch\"", "start": "parallelshell \"npm run build:watch\" \"npm run reskindex:watch\"",
"lint": "eslint src/", "lint": "eslint src/",
"lintall": "eslint src/ test/", "lintall": "eslint src/ test/",
"lintwithexclusions": "eslint --max-warnings 0 --ignore-path .eslintignore.errorfiles src test",
"clean": "rimraf lib", "clean": "rimraf lib",
"prepublish": "npm run clean && npm run build && git rev-parse HEAD > git-revision.txt", "prepublish": "npm run clean && npm run build && git rev-parse HEAD > git-revision.txt",
"test": "karma start --single-run=true --browsers ChromeHeadless", "test": "karma start --single-run=true --browsers ChromeHeadless",
@ -99,7 +100,7 @@
"eslint-config-google": "^0.7.1", "eslint-config-google": "^0.7.1",
"eslint-plugin-babel": "^4.0.1", "eslint-plugin-babel": "^4.0.1",
"eslint-plugin-flowtype": "^2.30.0", "eslint-plugin-flowtype": "^2.30.0",
"eslint-plugin-react": "^6.9.0", "eslint-plugin-react": "^7.4.0",
"expect": "^1.16.0", "expect": "^1.16.0",
"json-loader": "^0.5.3", "json-loader": "^0.5.3",
"karma": "^1.7.0", "karma": "^1.7.0",

View file

@ -6,6 +6,4 @@ npm run test
./.travis-test-riot.sh ./.travis-test-riot.sh
# run the linter, but exclude any files known to have errors or warnings. # run the linter, but exclude any files known to have errors or warnings.
./node_modules/.bin/eslint --max-warnings 0 \ npm run lintwithexclusions
--ignore-path .eslintignore.errorfiles \
src test

View file

@ -27,7 +27,7 @@ export function showGroupInviteDialog(groupId) {
description: _t("Who would you like to add to this group?"), description: _t("Who would you like to add to this group?"),
placeholder: _t("Name or matrix ID"), placeholder: _t("Name or matrix ID"),
button: _t("Invite to Group"), button: _t("Invite to Group"),
validAddressTypes: ['mx'], validAddressTypes: ['mx-user-id'],
onFinished: (success, addrs) => { onFinished: (success, addrs) => {
if (!success) return; if (!success) return;
@ -45,7 +45,7 @@ export function showGroupAddRoomDialog(groupId) {
placeholder: _t("Room name or alias"), placeholder: _t("Room name or alias"),
button: _t("Add to group"), button: _t("Add to group"),
pickerType: 'room', pickerType: 'room',
validAddressTypes: ['mx'], validAddressTypes: ['mx-room-id'],
onFinished: (success, addrs) => { onFinished: (success, addrs) => {
if (!success) return; if (!success) return;

View file

@ -28,7 +28,7 @@ export function inviteToRoom(roomId, addr) {
if (addrType == 'email') { if (addrType == 'email') {
return MatrixClientPeg.get().inviteByEmail(roomId, addr); return MatrixClientPeg.get().inviteByEmail(roomId, addr);
} else if (addrType == 'mx') { } else if (addrType == 'mx-user-id') {
return MatrixClientPeg.get().invite(roomId, addr); return MatrixClientPeg.get().invite(roomId, addr);
} else { } else {
throw new Error('Unsupported address'); throw new Error('Unsupported address');

View file

@ -254,7 +254,7 @@ const commands = {
title: _t("Ignored user"), title: _t("Ignored user"),
description: ( description: (
<div> <div>
<p>{_t("You are now ignoring %(userId)s", {userId: userId})}</p> <p>{ _t("You are now ignoring %(userId)s", {userId: userId}) }</p>
</div> </div>
), ),
hasCancelButton: false, hasCancelButton: false,
@ -281,7 +281,7 @@ const commands = {
title: _t("Unignored user"), title: _t("Unignored user"),
description: ( description: (
<div> <div>
<p>{_t("You are no longer ignoring %(userId)s", {userId: userId})}</p> <p>{ _t("You are no longer ignoring %(userId)s", {userId: userId}) }</p>
</div> </div>
), ),
hasCancelButton: false, hasCancelButton: false,

View file

@ -16,11 +16,12 @@ limitations under the License.
const emailRegex = /^\S+@\S+\.\S+$/; const emailRegex = /^\S+@\S+\.\S+$/;
const mxidRegex = /^@\S+:\S+$/; const mxUserIdRegex = /^@\S+:\S+$/;
const mxRoomIdRegex = /^!\S+:\S+$/;
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
export const addressTypes = [ export const addressTypes = [
'mx', 'email', 'mx-user-id', 'mx-room-id', 'email',
]; ];
// PropType definition for an object describing // PropType definition for an object describing
@ -41,13 +42,16 @@ export const UserAddressType = PropTypes.shape({
export function getAddressType(inputText) { export function getAddressType(inputText) {
const isEmailAddress = emailRegex.test(inputText); const isEmailAddress = emailRegex.test(inputText);
const isMatrixId = mxidRegex.test(inputText); const isUserId = mxUserIdRegex.test(inputText);
const isRoomId = mxRoomIdRegex.test(inputText);
// sanity check the input for user IDs // sanity check the input for user IDs
if (isEmailAddress) { if (isEmailAddress) {
return 'email'; return 'email';
} else if (isMatrixId) { } else if (isUserId) {
return 'mx'; return 'mx-user-id';
} else if (isRoomId) {
return 'mx-room-id';
} else { } else {
return null; return null;
} }

View file

@ -35,7 +35,7 @@ export default {
}, },
{ {
name: "-", name: "-",
id: 'feature_flair', id: 'feature_groups',
default: false, default: false,
}, },
], ],
@ -43,7 +43,7 @@ export default {
// horrible but it works. The locality makes this somewhat more palatable. // horrible but it works. The locality makes this somewhat more palatable.
doTranslations: function() { doTranslations: function() {
this.LABS_FEATURES[0].name = _t("Matrix Apps"); this.LABS_FEATURES[0].name = _t("Matrix Apps");
this.LABS_FEATURES[1].name = _t("Flair"); this.LABS_FEATURES[1].name = _t("Groups");
}, },
loadProfileInfo: function() { loadProfileInfo: function() {

View file

@ -136,13 +136,13 @@ export default React.createClass({
) } ) }
</p> </p>
<div className='error'> <div className='error'>
{this.state.errStr} { this.state.errStr }
</div> </div>
<div className='mx_E2eKeysDialog_inputTable'> <div className='mx_E2eKeysDialog_inputTable'>
<div className='mx_E2eKeysDialog_inputRow'> <div className='mx_E2eKeysDialog_inputRow'>
<div className='mx_E2eKeysDialog_inputLabel'> <div className='mx_E2eKeysDialog_inputLabel'>
<label htmlFor='passphrase1'> <label htmlFor='passphrase1'>
{_t("Enter passphrase")} { _t("Enter passphrase") }
</label> </label>
</div> </div>
<div className='mx_E2eKeysDialog_inputCell'> <div className='mx_E2eKeysDialog_inputCell'>
@ -155,7 +155,7 @@ export default React.createClass({
<div className='mx_E2eKeysDialog_inputRow'> <div className='mx_E2eKeysDialog_inputRow'>
<div className='mx_E2eKeysDialog_inputLabel'> <div className='mx_E2eKeysDialog_inputLabel'>
<label htmlFor='passphrase2'> <label htmlFor='passphrase2'>
{_t("Confirm passphrase")} { _t("Confirm passphrase") }
</label> </label>
</div> </div>
<div className='mx_E2eKeysDialog_inputCell'> <div className='mx_E2eKeysDialog_inputCell'>
@ -172,7 +172,7 @@ export default React.createClass({
disabled={disableForm} disabled={disableForm}
/> />
<button onClick={this._onCancelClick} disabled={disableForm}> <button onClick={this._onCancelClick} disabled={disableForm}>
{_t("Cancel")} { _t("Cancel") }
</button> </button>
</div> </div>
</form> </form>

View file

@ -134,13 +134,13 @@ export default React.createClass({
) } ) }
</p> </p>
<div className='error'> <div className='error'>
{this.state.errStr} { this.state.errStr }
</div> </div>
<div className='mx_E2eKeysDialog_inputTable'> <div className='mx_E2eKeysDialog_inputTable'>
<div className='mx_E2eKeysDialog_inputRow'> <div className='mx_E2eKeysDialog_inputRow'>
<div className='mx_E2eKeysDialog_inputLabel'> <div className='mx_E2eKeysDialog_inputLabel'>
<label htmlFor='importFile'> <label htmlFor='importFile'>
{_t("File to import")} { _t("File to import") }
</label> </label>
</div> </div>
<div className='mx_E2eKeysDialog_inputCell'> <div className='mx_E2eKeysDialog_inputCell'>
@ -153,14 +153,14 @@ export default React.createClass({
<div className='mx_E2eKeysDialog_inputRow'> <div className='mx_E2eKeysDialog_inputRow'>
<div className='mx_E2eKeysDialog_inputLabel'> <div className='mx_E2eKeysDialog_inputLabel'>
<label htmlFor='passphrase'> <label htmlFor='passphrase'>
{_t("Enter passphrase")} { _t("Enter passphrase") }
</label> </label>
</div> </div>
<div className='mx_E2eKeysDialog_inputCell'> <div className='mx_E2eKeysDialog_inputCell'>
<input ref='passphrase' id='passphrase' <input ref='passphrase' id='passphrase'
size='64' type='password' size='64' type='password'
onChange={this._onFormChange} onChange={this._onFormChange}
disabled={disableForm}/> disabled={disableForm} />
</div> </div>
</div> </div>
</div> </div>
@ -170,7 +170,7 @@ export default React.createClass({
disabled={!this.state.enableSubmit || disableForm} disabled={!this.state.enableSubmit || disableForm}
/> />
<button onClick={this._onCancelClick} disabled={disableForm}> <button onClick={this._onCancelClick} disabled={disableForm}>
{_t("Cancel")} { _t("Cancel") }
</button> </button>
</div> </div>
</form> </form>

View file

@ -129,7 +129,7 @@ export default class CommandProvider extends AutocompleteProvider {
component: (<TextualCompletion component: (<TextualCompletion
title={result.command} title={result.command}
subtitle={result.args} subtitle={result.args}
description={ _t(result.description) } description={_t(result.description)}
/>), />),
range, range,
}; };
@ -150,7 +150,7 @@ export default class CommandProvider extends AutocompleteProvider {
renderCompletions(completions: [React.Component]): ?React.Component { renderCompletions(completions: [React.Component]): ?React.Component {
return <div className="mx_Autocomplete_Completion_container_block"> return <div className="mx_Autocomplete_Completion_container_block">
{completions} { completions }
</div>; </div>;
} }
} }

View file

@ -106,7 +106,7 @@ export default class RoomProvider extends AutocompleteProvider {
renderCompletions(completions: [React.Component]): ?React.Component { renderCompletions(completions: [React.Component]): ?React.Component {
return <div className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate"> return <div className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate">
{completions} { completions }
</div>; </div>;
} }
} }

View file

@ -72,7 +72,7 @@ const CategoryRoomList = React.createClass({
placeholder: _t("Room name or alias"), placeholder: _t("Room name or alias"),
button: _t("Add to summary"), button: _t("Add to summary"),
pickerType: 'room', pickerType: 'room',
validAddressTypes: ['mx'], validAddressTypes: ['mx-room-id'],
groupId: this.props.groupId, groupId: this.props.groupId,
onFinished: (success, addrs) => { onFinished: (success, addrs) => {
if (!success) return; if (!success) return;
@ -106,9 +106,9 @@ const CategoryRoomList = React.createClass({
const TintableSvg = sdk.getComponent("elements.TintableSvg"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
const addButton = this.props.editing ? const addButton = this.props.editing ?
(<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddRoomsClicked}> (<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddRoomsClicked}>
<TintableSvg src="img/icons-create-room.svg" width="64" height="64"/> <TintableSvg src="img/icons-create-room.svg" width="64" height="64" />
<div className="mx_GroupView_featuredThings_addButton_label"> <div className="mx_GroupView_featuredThings_addButton_label">
{_t('Add a Room')} { _t('Add a Room') }
</div> </div>
</AccessibleButton>) : <div />; </AccessibleButton>) : <div />;
@ -117,17 +117,19 @@ const CategoryRoomList = React.createClass({
key={r.room_id} key={r.room_id}
groupId={this.props.groupId} groupId={this.props.groupId}
editing={this.props.editing} editing={this.props.editing}
summaryInfo={r}/>; summaryInfo={r} />;
}); });
let catHeader = <div />; let catHeader = <div />;
if (this.props.category && this.props.category.profile) { if (this.props.category && this.props.category.profile) {
catHeader = <div className="mx_GroupView_featuredThings_category">{this.props.category.profile.name}</div>; catHeader = <div className="mx_GroupView_featuredThings_category">
{ this.props.category.profile.name }
</div>;
} }
return <div className="mx_GroupView_featuredThings_container"> return <div className="mx_GroupView_featuredThings_container">
{catHeader} { catHeader }
{roomNodes} { roomNodes }
{addButton} { addButton }
</div>; </div>;
}, },
}); });
@ -179,20 +181,26 @@ const FeaturedRoom = React.createClass({
render: function() { render: function() {
const RoomAvatar = sdk.getComponent("avatars.RoomAvatar"); const RoomAvatar = sdk.getComponent("avatars.RoomAvatar");
const roomName = this.props.summaryInfo.profile.name ||
this.props.summaryInfo.profile.canonical_alias ||
_t("Unnamed Room");
const oobData = { const oobData = {
roomId: this.props.summaryInfo.room_id, roomId: this.props.summaryInfo.room_id,
avatarUrl: this.props.summaryInfo.profile.avatar_url, avatarUrl: this.props.summaryInfo.profile.avatar_url,
name: this.props.summaryInfo.profile.name, name: roomName,
}; };
let permalink = null; let permalink = null;
if (this.props.summaryInfo.profile && this.props.summaryInfo.profile.canonical_alias) { if (this.props.summaryInfo.profile && this.props.summaryInfo.profile.canonical_alias) {
permalink = 'https://matrix.to/#/' + this.props.summaryInfo.profile.canonical_alias; permalink = 'https://matrix.to/#/' + this.props.summaryInfo.profile.canonical_alias;
} }
let roomNameNode = null; let roomNameNode = null;
if (permalink) { if (permalink) {
roomNameNode = <a href={permalink} onClick={this.onClick} >{this.props.summaryInfo.profile.name}</a>; roomNameNode = <a href={permalink} onClick={this.onClick} >{ roomName }</a>;
} else { } else {
roomNameNode = <span>{this.props.summaryInfo.profile.name}</span>; roomNameNode = <span>{ roomName }</span>;
} }
const deleteButton = this.props.editing ? const deleteButton = this.props.editing ?
@ -202,13 +210,13 @@ const FeaturedRoom = React.createClass({
width="14" width="14"
height="14" height="14"
alt="Delete" alt="Delete"
onClick={this.onDeleteClicked}/> onClick={this.onDeleteClicked} />
: <div />; : <div />;
return <AccessibleButton className="mx_GroupView_featuredThing" onClick={this.onClick}> return <AccessibleButton className="mx_GroupView_featuredThing" onClick={this.onClick}>
<RoomAvatar oobData={oobData} width={64} height={64} /> <RoomAvatar oobData={oobData} width={64} height={64} />
<div className="mx_GroupView_featuredThing_name">{roomNameNode}</div> <div className="mx_GroupView_featuredThing_name">{ roomNameNode }</div>
{deleteButton} { deleteButton }
</AccessibleButton>; </AccessibleButton>;
}, },
}); });
@ -237,8 +245,9 @@ const RoleUserList = React.createClass({
description: _t("Who would you like to add to this summary?"), description: _t("Who would you like to add to this summary?"),
placeholder: _t("Name or matrix ID"), placeholder: _t("Name or matrix ID"),
button: _t("Add to summary"), button: _t("Add to summary"),
validAddressTypes: ['mx'], validAddressTypes: ['mx-user-id'],
groupId: this.props.groupId, groupId: this.props.groupId,
shouldOmitSelf: false,
onFinished: (success, addrs) => { onFinished: (success, addrs) => {
if (!success) return; if (!success) return;
const errorList = []; const errorList = [];
@ -271,9 +280,9 @@ const RoleUserList = React.createClass({
const TintableSvg = sdk.getComponent("elements.TintableSvg"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
const addButton = this.props.editing ? const addButton = this.props.editing ?
(<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}> (<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}>
<TintableSvg src="img/icons-create-room.svg" width="64" height="64"/> <TintableSvg src="img/icons-create-room.svg" width="64" height="64" />
<div className="mx_GroupView_featuredThings_addButton_label"> <div className="mx_GroupView_featuredThings_addButton_label">
{_t('Add a User')} { _t('Add a User') }
</div> </div>
</AccessibleButton>) : <div />; </AccessibleButton>) : <div />;
const userNodes = this.props.users.map((u) => { const userNodes = this.props.users.map((u) => {
@ -281,16 +290,16 @@ const RoleUserList = React.createClass({
key={u.user_id} key={u.user_id}
summaryInfo={u} summaryInfo={u}
editing={this.props.editing} editing={this.props.editing}
groupId={this.props.groupId}/>; groupId={this.props.groupId} />;
}); });
let roleHeader = <div />; let roleHeader = <div />;
if (this.props.role && this.props.role.profile) { if (this.props.role && this.props.role.profile) {
roleHeader = <div className="mx_GroupView_featuredThings_category">{this.props.role.profile.name}</div>; roleHeader = <div className="mx_GroupView_featuredThings_category">{ this.props.role.profile.name }</div>;
} }
return <div className="mx_GroupView_featuredThings_container"> return <div className="mx_GroupView_featuredThings_container">
{roleHeader} { roleHeader }
{userNodes} { userNodes }
{addButton} { addButton }
</div>; </div>;
}, },
}); });
@ -342,7 +351,7 @@ const FeaturedUser = React.createClass({
const name = this.props.summaryInfo.displayname || this.props.summaryInfo.user_id; const name = this.props.summaryInfo.displayname || this.props.summaryInfo.user_id;
const permalink = 'https://matrix.to/#/' + this.props.summaryInfo.user_id; const permalink = 'https://matrix.to/#/' + this.props.summaryInfo.user_id;
const userNameNode = <a href={permalink} onClick={this.onClick}>{name}</a>; const userNameNode = <a href={permalink} onClick={this.onClick}>{ name }</a>;
const httpUrl = MatrixClientPeg.get() const httpUrl = MatrixClientPeg.get()
.mxcUrlToHttp(this.props.summaryInfo.avatar_url, 64, 64); .mxcUrlToHttp(this.props.summaryInfo.avatar_url, 64, 64);
@ -353,13 +362,13 @@ const FeaturedUser = React.createClass({
width="14" width="14"
height="14" height="14"
alt="Delete" alt="Delete"
onClick={this.onDeleteClicked}/> onClick={this.onDeleteClicked} />
: <div />; : <div />;
return <AccessibleButton className="mx_GroupView_featuredThing" onClick={this.onClick}> return <AccessibleButton className="mx_GroupView_featuredThing" onClick={this.onClick}>
<BaseAvatar name={name} url={httpUrl} width={64} height={64} /> <BaseAvatar name={name} url={httpUrl} width={64} height={64} />
<div className="mx_GroupView_featuredThing_name">{userNameNode}</div> <div className="mx_GroupView_featuredThing_name">{ userNameNode }</div>
{deleteButton} { deleteButton }
</AccessibleButton>; </AccessibleButton>;
}, },
}); });
@ -625,7 +634,7 @@ export default React.createClass({
const defaultCategoryNode = <CategoryRoomList const defaultCategoryNode = <CategoryRoomList
rooms={defaultCategoryRooms} rooms={defaultCategoryRooms}
groupId={this.props.groupId} groupId={this.props.groupId}
editing={this.state.editing}/>; editing={this.state.editing} />;
const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => { const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => {
const cat = summary.rooms_section.categories[catId]; const cat = summary.rooms_section.categories[catId];
return <CategoryRoomList return <CategoryRoomList
@ -633,15 +642,15 @@ export default React.createClass({
rooms={categoryRooms[catId]} rooms={categoryRooms[catId]}
category={cat} category={cat}
groupId={this.props.groupId} groupId={this.props.groupId}
editing={this.state.editing}/>; editing={this.state.editing} />;
}); });
return <div className="mx_GroupView_featuredThings"> return <div className="mx_GroupView_featuredThings">
<div className="mx_GroupView_featuredThings_header"> <div className="mx_GroupView_featuredThings_header">
{_t('Featured Rooms:')} { _t('Featured Rooms:') }
</div> </div>
{defaultCategoryNode} { defaultCategoryNode }
{categoryRoomNodes} { categoryRoomNodes }
</div>; </div>;
}, },
@ -666,7 +675,7 @@ export default React.createClass({
const noRoleNode = <RoleUserList const noRoleNode = <RoleUserList
users={noRoleUsers} users={noRoleUsers}
groupId={this.props.groupId} groupId={this.props.groupId}
editing={this.state.editing}/>; editing={this.state.editing} />;
const roleUserNodes = Object.keys(roleUsers).map((roleId) => { const roleUserNodes = Object.keys(roleUsers).map((roleId) => {
const role = summary.users_section.roles[roleId]; const role = summary.users_section.roles[roleId];
return <RoleUserList return <RoleUserList
@ -674,15 +683,15 @@ export default React.createClass({
users={roleUsers[roleId]} users={roleUsers[roleId]}
role={role} role={role}
groupId={this.props.groupId} groupId={this.props.groupId}
editing={this.state.editing}/>; editing={this.state.editing} />;
}); });
return <div className="mx_GroupView_featuredThings"> return <div className="mx_GroupView_featuredThings">
<div className="mx_GroupView_featuredThings_header"> <div className="mx_GroupView_featuredThings_header">
{_t('Featured Users:')} { _t('Featured Users:') }
</div> </div>
{noRoleNode} { noRoleNode }
{roleUserNodes} { roleUserNodes }
</div>; </div>;
}, },
@ -701,18 +710,18 @@ export default React.createClass({
return <div className="mx_GroupView_membershipSection mx_GroupView_membershipSection_invited"> return <div className="mx_GroupView_membershipSection mx_GroupView_membershipSection_invited">
<div className="mx_GroupView_membershipSection_description"> <div className="mx_GroupView_membershipSection_description">
{_t("%(inviter)s has invited you to join this group", {inviter: group.inviter.userId})} { _t("%(inviter)s has invited you to join this group", {inviter: group.inviter.userId}) }
</div> </div>
<div className="mx_GroupView_membership_buttonContainer"> <div className="mx_GroupView_membership_buttonContainer">
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton" <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
onClick={this._onAcceptInviteClick} onClick={this._onAcceptInviteClick}
> >
{_t("Accept")} { _t("Accept") }
</AccessibleButton> </AccessibleButton>
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton" <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
onClick={this._onRejectInviteClick} onClick={this._onRejectInviteClick}
> >
{_t("Decline")} { _t("Decline") }
</AccessibleButton> </AccessibleButton>
</div> </div>
</div>; </div>;
@ -733,13 +742,13 @@ export default React.createClass({
publicisedButton = <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton" publicisedButton = <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
onClick={this._onPubliciseOffClick} onClick={this._onPubliciseOffClick}
> >
{_t("Unpublish")} { _t("Unpublish") }
</AccessibleButton>; </AccessibleButton>;
} }
publicisedSection = <div className="mx_GroupView_membershipSubSection"> publicisedSection = <div className="mx_GroupView_membershipSubSection">
{_t("This group is published on your profile")} { _t("This group is published on your profile") }
<div className="mx_GroupView_membership_buttonContainer"> <div className="mx_GroupView_membership_buttonContainer">
{publicisedButton} { publicisedButton }
</div> </div>
</div>; </div>;
} else { } else {
@ -747,13 +756,13 @@ export default React.createClass({
publicisedButton = <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton" publicisedButton = <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
onClick={this._onPubliciseOnClick} onClick={this._onPubliciseOnClick}
> >
{_t("Publish")} { _t("Publish") }
</AccessibleButton>; </AccessibleButton>;
} }
publicisedSection = <div className="mx_GroupView_membershipSubSection"> publicisedSection = <div className="mx_GroupView_membershipSubSection">
{_t("This group is not published on your profile")} { _t("This group is not published on your profile") }
<div className="mx_GroupView_membership_buttonContainer"> <div className="mx_GroupView_membership_buttonContainer">
{publicisedButton} { publicisedButton }
</div> </div>
</div>; </div>;
} }
@ -761,17 +770,17 @@ export default React.createClass({
return <div className="mx_GroupView_membershipSection mx_GroupView_membershipSection_joined"> return <div className="mx_GroupView_membershipSection mx_GroupView_membershipSection_joined">
<div className="mx_GroupView_membershipSubSection"> <div className="mx_GroupView_membershipSubSection">
<div className="mx_GroupView_membershipSection_description"> <div className="mx_GroupView_membershipSection_description">
{youAreAMemberText} { youAreAMemberText }
</div> </div>
<div className="mx_GroupView_membership_buttonContainer"> <div className="mx_GroupView_membership_buttonContainer">
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton" <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
onClick={this._onLeaveClick} onClick={this._onLeaveClick}
> >
{_t("Leave")} { _t("Leave") }
</AccessibleButton> </AccessibleButton>
</div> </div>
</div> </div>
{publicisedSection} { publicisedSection }
</div>; </div>;
} }
@ -811,15 +820,15 @@ export default React.createClass({
avatarNode = ( avatarNode = (
<div className="mx_GroupView_avatarPicker"> <div className="mx_GroupView_avatarPicker">
<label htmlFor="avatarInput" className="mx_GroupView_avatarPicker_label"> <label htmlFor="avatarInput" className="mx_GroupView_avatarPicker_label">
{avatarImage} { avatarImage }
</label> </label>
<div className="mx_GroupView_avatarPicker_edit"> <div className="mx_GroupView_avatarPicker_edit">
<label htmlFor="avatarInput" className="mx_GroupView_avatarPicker_label"> <label htmlFor="avatarInput" className="mx_GroupView_avatarPicker_label">
<img src="img/camera.svg" <img src="img/camera.svg"
alt={ _t("Upload avatar") } title={ _t("Upload avatar") } alt={_t("Upload avatar")} title={_t("Upload avatar")}
width="17" height="15" /> width="17" height="15" />
</label> </label>
<input id="avatarInput" className="mx_GroupView_uploadInput" type="file" onChange={this._onAvatarSelected}/> <input id="avatarInput" className="mx_GroupView_uploadInput" type="file" onChange={this._onAvatarSelected} />
</div> </div>
</div> </div>
); );
@ -839,13 +848,13 @@ export default React.createClass({
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton" <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
onClick={this._onSaveClick} key="_saveButton" onClick={this._onSaveClick} key="_saveButton"
> >
{_t('Save')} { _t('Save') }
</AccessibleButton>, </AccessibleButton>,
); );
rightButtons.push( rightButtons.push(
<AccessibleButton className='mx_GroupView_textButton' onClick={this._onCancelClick} key="_cancelButton"> <AccessibleButton className="mx_RoomHeader_cancelButton" onClick={this._onCancelClick} key="_cancelButton">
<img src="img/cancel.svg" className='mx_filterFlipColor' <img src="img/cancel.svg" className="mx_filterFlipColor"
width="18" height="18" alt={_t("Cancel")}/> width="18" height="18" alt={_t("Cancel")} />
</AccessibleButton>, </AccessibleButton>,
); );
roomBody = <div> roomBody = <div>
@ -853,8 +862,8 @@ export default React.createClass({
onChange={this._onLongDescChange} onChange={this._onLongDescChange}
tabIndex="3" tabIndex="3"
/> />
{this._getFeaturedRoomsNode()} { this._getFeaturedRoomsNode() }
{this._getFeaturedUsersNode()} { this._getFeaturedUsersNode() }
</div>; </div>;
} else { } else {
const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null; const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null;
@ -865,41 +874,41 @@ export default React.createClass({
/>; />;
if (summary.profile && summary.profile.name) { if (summary.profile && summary.profile.name) {
nameNode = <div> nameNode = <div>
<span>{summary.profile.name}</span> <span>{ summary.profile.name }</span>
<span className="mx_GroupView_header_groupid"> <span className="mx_GroupView_header_groupid">
({this.props.groupId}) ({ this.props.groupId })
</span> </span>
</div>; </div>;
} else { } else {
nameNode = <span>{this.props.groupId}</span>; nameNode = <span>{ this.props.groupId }</span>;
} }
shortDescNode = <span>{summary.profile.short_description}</span>; shortDescNode = <span>{ summary.profile.short_description }</span>;
let description = null; let description = null;
if (summary.profile && summary.profile.long_description) { if (summary.profile && summary.profile.long_description) {
description = sanitizedHtmlNode(summary.profile.long_description); description = sanitizedHtmlNode(summary.profile.long_description);
} }
roomBody = <div> roomBody = <div>
{this._getMembershipSection()} { this._getMembershipSection() }
<div className="mx_GroupView_groupDesc">{description}</div> <div className="mx_GroupView_groupDesc">{ description }</div>
{this._getFeaturedRoomsNode()} { this._getFeaturedRoomsNode() }
{this._getFeaturedUsersNode()} { this._getFeaturedUsersNode() }
</div>; </div>;
if (summary.user && summary.user.is_privileged) { if (summary.user && summary.user.is_privileged) {
rightButtons.push( rightButtons.push(
<AccessibleButton className="mx_GroupHeader_button" <AccessibleButton className="mx_GroupHeader_button"
onClick={this._onEditClick} title={_t("Edit Group")} key="_editButton" onClick={this._onEditClick} title={_t("Edit Group")} key="_editButton"
> >
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16"/> <TintableSvg src="img/icons-settings-room.svg" width="16" height="16" />
</AccessibleButton>, </AccessibleButton>,
); );
} }
if (this.props.collapsedRhs) { if (this.props.collapsedRhs) {
rightButtons.push( rightButtons.push(
<AccessibleButton className="mx_GroupHeader_button" <AccessibleButton className="mx_GroupHeader_button"
onClick={this._onShowRhsClick} title={ _t('Show panel') } key="_maximiseButton" onClick={this._onShowRhsClick} title={_t('Show panel')} key="_maximiseButton"
> >
<TintableSvg src="img/maximise.svg" width="10" height="16"/> <TintableSvg src="img/maximise.svg" width="10" height="16" />
</AccessibleButton>, </AccessibleButton>,
); );
} }
@ -912,40 +921,40 @@ export default React.createClass({
<div className={classnames(headerClasses)}> <div className={classnames(headerClasses)}>
<div className="mx_GroupView_header_leftCol"> <div className="mx_GroupView_header_leftCol">
<div className="mx_GroupView_header_avatar"> <div className="mx_GroupView_header_avatar">
{avatarNode} { avatarNode }
</div> </div>
<div className="mx_GroupView_header_info"> <div className="mx_GroupView_header_info">
<div className="mx_GroupView_header_name"> <div className="mx_GroupView_header_name">
{nameNode} { nameNode }
</div> </div>
<div className="mx_GroupView_header_shortDesc"> <div className="mx_GroupView_header_shortDesc">
{shortDescNode} { shortDescNode }
</div> </div>
</div> </div>
</div> </div>
<div className="mx_GroupView_header_rightCol"> <div className="mx_GroupView_header_rightCol">
{rightButtons} { rightButtons }
</div> </div>
</div> </div>
{roomBody} { roomBody }
</div> </div>
); );
} else if (this.state.error) { } else if (this.state.error) {
if (this.state.error.httpStatus === 404) { if (this.state.error.httpStatus === 404) {
return ( return (
<div className="mx_GroupView_error"> <div className="mx_GroupView_error">
Group {this.props.groupId} not found Group { this.props.groupId } not found
</div> </div>
); );
} else { } else {
let extraText; let extraText;
if (this.state.error.errcode === 'M_UNRECOGNIZED') { if (this.state.error.errcode === 'M_UNRECOGNIZED') {
extraText = <div>{_t('This Home server does not support groups')}</div>; extraText = <div>{ _t('This Home server does not support groups') }</div>;
} }
return ( return (
<div className="mx_GroupView_error"> <div className="mx_GroupView_error">
Failed to load {this.props.groupId} Failed to load { this.props.groupId }
{extraText} { extraText }
</div> </div>
); );
} }

View file

@ -853,7 +853,7 @@ module.exports = React.createClass({
title: _t("Leave room"), title: _t("Leave room"),
description: ( description: (
<span> <span>
{_t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name})} { _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) }
</span> </span>
), ),
onFinished: (shouldLeave) => { onFinished: (shouldLeave) => {
@ -1450,7 +1450,7 @@ module.exports = React.createClass({
return ( return (
<div className="mx_MatrixChat_splash"> <div className="mx_MatrixChat_splash">
<Spinner /> <Spinner />
<a href="#" className="mx_MatrixChat_splashButtons" onClick={ this.onLogoutClick }> <a href="#" className="mx_MatrixChat_splashButtons" onClick={this.onLogoutClick}>
{ _t('Logout') } { _t('Logout') }
</a> </a>
</div> </div>

View file

@ -39,7 +39,7 @@ const GroupTile = React.createClass({
}, },
render: function() { render: function() {
return <a onClick={this.onClick} href="#">{this.props.groupId}</a>; return <a onClick={this.onClick} href="#">{ this.props.groupId }</a>;
}, },
}); });
@ -90,51 +90,51 @@ export default withMatrixClient(React.createClass({
); );
}); });
content = <div> content = <div>
<div>{_t('You are a member of these groups:')}</div> <div>{ _t('You are a member of these groups:') }</div>
{groupNodes} { groupNodes }
</div>; </div>;
} else if (this.state.error) { } else if (this.state.error) {
content = <div className="mx_MyGroups_error"> content = <div className="mx_MyGroups_error">
{_t('Error whilst fetching joined groups')} { _t('Error whilst fetching joined groups') }
</div>; </div>;
} else { } else {
content = <Loader />; content = <Loader />;
} }
return <div className="mx_MyGroups"> return <div className="mx_MyGroups">
<SimpleRoomHeader title={ _t("Groups") } /> <SimpleRoomHeader title={_t("Groups")} icon="img/icons-groups.svg" />
<div className='mx_MyGroups_joinCreateBox'> <div className='mx_MyGroups_joinCreateBox'>
<div className="mx_MyGroups_createBox"> <div className="mx_MyGroups_createBox">
<div className="mx_MyGroups_joinCreateHeader"> <div className="mx_MyGroups_joinCreateHeader">
{_t('Create a new group')} { _t('Create a new group') }
</div> </div>
<AccessibleButton className='mx_MyGroups_joinCreateButton' onClick={this._onCreateGroupClick}> <AccessibleButton className='mx_MyGroups_joinCreateButton' onClick={this._onCreateGroupClick}>
<TintableSvg src="img/icons-create-room.svg" width="50" height="50" /> <TintableSvg src="img/icons-create-room.svg" width="50" height="50" />
</AccessibleButton> </AccessibleButton>
{_t( { _t(
'Create a group to represent your community! '+ 'Create a group to represent your community! '+
'Define a set of rooms and your own custom homepage '+ 'Define a set of rooms and your own custom homepage '+
'to mark out your space in the Matrix universe.', 'to mark out your space in the Matrix universe.',
)} ) }
</div> </div>
<div className="mx_MyGroups_joinBox"> <div className="mx_MyGroups_joinBox">
<div className="mx_MyGroups_joinCreateHeader"> <div className="mx_MyGroups_joinCreateHeader">
{_t('Join an existing group')} { _t('Join an existing group') }
</div> </div>
<AccessibleButton className='mx_MyGroups_joinCreateButton' onClick={this._onJoinGroupClick}> <AccessibleButton className='mx_MyGroups_joinCreateButton' onClick={this._onJoinGroupClick}>
<TintableSvg src="img/icons-create-room.svg" width="50" height="50" /> <TintableSvg src="img/icons-create-room.svg" width="50" height="50" />
</AccessibleButton> </AccessibleButton>
{_tJsx( { _tJsx(
'To join an existing group you\'ll have to '+ 'To join an existing group you\'ll have to '+
'know its group identifier; this will look '+ 'know its group identifier; this will look '+
'something like <i>+example:matrix.org</i>.', 'something like <i>+example:matrix.org</i>.',
/<i>(.*)<\/i>/, /<i>(.*)<\/i>/,
(sub) => <i>{sub}</i>, (sub) => <i>{ sub }</i>,
)} ) }
</div> </div>
</div> </div>
<div className="mx_MyGroups_content"> <div className="mx_MyGroups_content">
{content} { content }
</div> </div>
</div>; </div>;
}, },

View file

@ -52,7 +52,7 @@ const gHVersionLabel = function(repo, token='') {
} else { } else {
url = `https://github.com/${repo}/commit/${token.split('-')[0]}`; url = `https://github.com/${repo}/commit/${token.split('-')[0]}`;
} }
return <a target="_blank" rel="noopener" href={url}>{token}</a>; return <a target="_blank" rel="noopener" href={url}>{ token }</a>;
}; };
// Enumerate some simple 'flip a bit' UI settings (if any). // Enumerate some simple 'flip a bit' UI settings (if any).
@ -674,7 +674,7 @@ module.exports = React.createClass({
<div> <div>
<h3>Referral</h3> <h3>Referral</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
{_t("Refer a friend to Riot:")} <a href={href}>{href}</a> { _t("Refer a friend to Riot:") } <a href={href}>{ href }</a>
</div> </div>
</div> </div>
); );
@ -693,7 +693,7 @@ module.exports = React.createClass({
_renderLanguageSetting: function() { _renderLanguageSetting: function() {
const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown');
return <div> return <div>
<label htmlFor="languageSelector">{_t('Interface Language')}</label> <label htmlFor="languageSelector">{ _t('Interface Language') }</label>
<LanguageDropdown ref="language" onOptionChange={this.onLanguageChange} <LanguageDropdown ref="language" onOptionChange={this.onLanguageChange}
className="mx_UserSettings_language" className="mx_UserSettings_language"
value={this.state.language} value={this.state.language}
@ -716,7 +716,7 @@ module.exports = React.createClass({
<table> <table>
<tbody> <tbody>
<tr> <tr>
<td><strong>{_t('Autocomplete Delay (ms):')}</strong></td> <td><strong>{ _t('Autocomplete Delay (ms):') }</strong></td>
<td> <td>
<input <input
type="number" type="number"
@ -737,8 +737,8 @@ module.exports = React.createClass({
return <div className="mx_UserSettings_toggle"> return <div className="mx_UserSettings_toggle">
<input id="urlPreviewsDisabled" <input id="urlPreviewsDisabled"
type="checkbox" type="checkbox"
defaultChecked={ UserSettingsStore.getUrlPreviewsDisabled() } defaultChecked={UserSettingsStore.getUrlPreviewsDisabled()}
onChange={ this._onPreviewsDisabledChanged } onChange={this._onPreviewsDisabledChanged}
/> />
<label htmlFor="urlPreviewsDisabled"> <label htmlFor="urlPreviewsDisabled">
{ _t("Disable inline URL previews by default") } { _t("Disable inline URL previews by default") }
@ -759,13 +759,13 @@ module.exports = React.createClass({
if (setting.fn) setting.fn(e.target.checked); if (setting.fn) setting.fn(e.target.checked);
}; };
return <div className="mx_UserSettings_toggle" key={ setting.id }> return <div className="mx_UserSettings_toggle" key={setting.id}>
<input id={ setting.id } <input id={setting.id}
type="checkbox" type="checkbox"
defaultChecked={ this._syncedSettings[setting.id] } defaultChecked={this._syncedSettings[setting.id]}
onChange={ onChange } onChange={onChange}
/> />
<label htmlFor={ setting.id }> <label htmlFor={setting.id}>
{ _t(setting.label) } { _t(setting.label) }
</label> </label>
</div>; </div>;
@ -784,15 +784,15 @@ module.exports = React.createClass({
value: setting.value, value: setting.value,
}); });
}; };
return <div className="mx_UserSettings_toggle" key={ setting.id + "_" + setting.value }> return <div className="mx_UserSettings_toggle" key={setting.id + "_" + setting.value}>
<input id={ setting.id + "_" + setting.value } <input id={setting.id + "_" + setting.value}
type="radio" type="radio"
name={ setting.id } name={setting.id}
value={ setting.value } value={setting.value}
checked={ this._syncedSettings[setting.id] === setting.value } checked={this._syncedSettings[setting.id] === setting.value}
onChange={ onChange } onChange={onChange}
/> />
<label htmlFor={ setting.id + "_" + setting.value }> <label htmlFor={setting.id + "_" + setting.value}>
{ _t(setting.label) } { _t(setting.label) }
</label> </label>
</div>; </div>;
@ -829,10 +829,10 @@ module.exports = React.createClass({
<h3>{ _t("Cryptography") }</h3> <h3>{ _t("Cryptography") }</h3>
<div className="mx_UserSettings_section mx_UserSettings_cryptoSection"> <div className="mx_UserSettings_section mx_UserSettings_cryptoSection">
<ul> <ul>
<li><label>{_t("Device ID:")}</label> <li><label>{ _t("Device ID:") }</label>
<span><code>{deviceId}</code></span></li> <span><code>{ deviceId }</code></span></li>
<li><label>{_t("Device key:")}</label> <li><label>{ _t("Device key:") }</label>
<span><code><b>{identityKey}</b></code></span></li> <span><code><b>{ identityKey }</b></code></span></li>
</ul> </ul>
{ importExportButtons } { importExportButtons }
</div> </div>
@ -851,11 +851,11 @@ module.exports = React.createClass({
<h3>{ _t("Ignored Users") }</h3> <h3>{ _t("Ignored Users") }</h3>
<div className="mx_UserSettings_section mx_UserSettings_ignoredUsersSection"> <div className="mx_UserSettings_section mx_UserSettings_ignoredUsersSection">
<ul> <ul>
{this.state.ignoredUsers.map(function(userId) { { this.state.ignoredUsers.map(function(userId) {
return (<IgnoredUser key={userId} return (<IgnoredUser key={userId}
userId={userId} userId={userId}
onUnignored={updateHandler}></IgnoredUser>); onUnignored={updateHandler}></IgnoredUser>);
})} }) }
</ul> </ul>
</div> </div>
</div> </div>
@ -871,13 +871,13 @@ module.exports = React.createClass({
if (setting.fn) setting.fn(e.target.checked); if (setting.fn) setting.fn(e.target.checked);
}; };
return <div className="mx_UserSettings_toggle" key={ setting.id }> return <div className="mx_UserSettings_toggle" key={setting.id}>
<input id={ setting.id } <input id={setting.id}
type="checkbox" type="checkbox"
defaultChecked={ this._localSettings[setting.id] } defaultChecked={this._localSettings[setting.id]}
onChange={ onChange } onChange={onChange}
/> />
<label htmlFor={ setting.id }> <label htmlFor={setting.id}>
{ _t(setting.label) } { _t(setting.label) }
</label> </label>
</div>; </div>;
@ -887,8 +887,8 @@ module.exports = React.createClass({
const DevicesPanel = sdk.getComponent('settings.DevicesPanel'); const DevicesPanel = sdk.getComponent('settings.DevicesPanel');
return ( return (
<div> <div>
<h3>{_t("Devices")}</h3> <h3>{ _t("Devices") }</h3>
<DevicesPanel className="mx_UserSettings_section"/> <DevicesPanel className="mx_UserSettings_section" />
</div> </div>
); );
}, },
@ -903,7 +903,7 @@ module.exports = React.createClass({
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
<p>{ _t("Found a bug?") }</p> <p>{ _t("Found a bug?") }</p>
<button className="mx_UserSettings_button danger" <button className="mx_UserSettings_button danger"
onClick={this._onBugReportClicked}>{_t('Report it')} onClick={this._onBugReportClicked}>{ _t('Report it') }
</button> </button>
</div> </div>
</div> </div>
@ -911,13 +911,13 @@ module.exports = React.createClass({
}, },
_renderAnalyticsControl: function() { _renderAnalyticsControl: function() {
if (!SdkConfig.get().piwik) return <div/>; if (!SdkConfig.get().piwik) return <div />;
return <div> return <div>
<h3>{ _t('Analytics') }</h3> <h3>{ _t('Analytics') }</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
{_t('Riot collects anonymous analytics to allow us to improve the application.')} { _t('Riot collects anonymous analytics to allow us to improve the application.') }
{ANALYTICS_SETTINGS_LABELS.map( this._renderLocalSetting )} { ANALYTICS_SETTINGS_LABELS.map( this._renderLocalSetting ) }
</div> </div>
</div>; </div>;
}, },
@ -947,10 +947,10 @@ module.exports = React.createClass({
type="checkbox" type="checkbox"
id={feature.id} id={feature.id}
name={feature.id} name={feature.id}
defaultChecked={ UserSettingsStore.isFeatureEnabled(feature.id) } defaultChecked={UserSettingsStore.isFeatureEnabled(feature.id)}
onChange={ onChange } onChange={onChange}
/> />
<label htmlFor={feature.id}>{feature.name}</label> <label htmlFor={feature.id}>{ feature.name }</label>
</div>); </div>);
}); });
@ -964,7 +964,7 @@ module.exports = React.createClass({
<h3>{ _t("Labs") }</h3> <h3>{ _t("Labs") }</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
<p>{ _t("These are experimental features that may break in unexpected ways") }. { _t("Use with caution") }.</p> <p>{ _t("These are experimental features that may break in unexpected ways") }. { _t("Use with caution") }.</p>
{features} { features }
</div> </div>
</div> </div>
); );
@ -997,10 +997,10 @@ module.exports = React.createClass({
const platform = PlatformPeg.get(); const platform = PlatformPeg.get();
if ('canSelfUpdate' in platform && platform.canSelfUpdate() && 'startUpdateCheck' in platform) { if ('canSelfUpdate' in platform && platform.canSelfUpdate() && 'startUpdateCheck' in platform) {
return <div> return <div>
<h3>{_t('Updates')}</h3> <h3>{ _t('Updates') }</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
<AccessibleButton className="mx_UserSettings_button" onClick={platform.startUpdateCheck}> <AccessibleButton className="mx_UserSettings_button" onClick={platform.startUpdateCheck}>
{_t('Check for update')} { _t('Check for update') }
</AccessibleButton> </AccessibleButton>
</div> </div>
</div>; </div>;
@ -1026,7 +1026,7 @@ module.exports = React.createClass({
reject = ( reject = (
<AccessibleButton className="mx_UserSettings_button danger" <AccessibleButton className="mx_UserSettings_button danger"
onClick={onClick}> onClick={onClick}>
{_t("Reject all %(invitedRooms)s invites", {invitedRooms: invitedRooms.length})} { _t("Reject all %(invitedRooms)s invites", {invitedRooms: invitedRooms.length}) }
</AccessibleButton> </AccessibleButton>
); );
} }
@ -1034,7 +1034,7 @@ module.exports = React.createClass({
return <div> return <div>
<h3>{ _t("Bulk Options") }</h3> <h3>{ _t("Bulk Options") }</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
{reject} { reject }
</div> </div>
</div>; </div>;
}, },
@ -1052,7 +1052,7 @@ module.exports = React.createClass({
defaultChecked={settings['auto-launch']} defaultChecked={settings['auto-launch']}
onChange={this._onAutoLaunchChanged} onChange={this._onAutoLaunchChanged}
/> />
<label htmlFor="auto-launch">{_t('Start automatically after system login')}</label> <label htmlFor="auto-launch">{ _t('Start automatically after system login') }</label>
</div> </div>
</div> </div>
</div>; </div>;
@ -1064,7 +1064,7 @@ module.exports = React.createClass({
}, },
_mapWebRtcDevicesToSpans: function(devices) { _mapWebRtcDevicesToSpans: function(devices) {
return devices.map((device) => <span key={device.deviceId}>{device.label}</span>); return devices.map((device) => <span key={device.deviceId}>{ device.label }</span>);
}, },
_setAudioInput: function(deviceId) { _setAudioInput: function(deviceId) {
@ -1100,15 +1100,15 @@ module.exports = React.createClass({
if (this.state.mediaDevices === false) { if (this.state.mediaDevices === false) {
return ( return (
<p className="mx_UserSettings_link" onClick={this._requestMediaPermissions}> <p className="mx_UserSettings_link" onClick={this._requestMediaPermissions}>
{_t('Missing Media Permissions, click here to request.')} { _t('Missing Media Permissions, click here to request.') }
</p> </p>
); );
} else if (!this.state.mediaDevices) return; } else if (!this.state.mediaDevices) return;
const Dropdown = sdk.getComponent('elements.Dropdown'); const Dropdown = sdk.getComponent('elements.Dropdown');
let microphoneDropdown = <p>{_t('No Microphones detected')}</p>; let microphoneDropdown = <p>{ _t('No Microphones detected') }</p>;
let webcamDropdown = <p>{_t('No Webcams detected')}</p>; let webcamDropdown = <p>{ _t('No Webcams detected') }</p>;
const defaultOption = { const defaultOption = {
deviceId: '', deviceId: '',
@ -1125,12 +1125,12 @@ module.exports = React.createClass({
} }
microphoneDropdown = <div> microphoneDropdown = <div>
<h4>{_t('Microphone')}</h4> <h4>{ _t('Microphone') }</h4>
<Dropdown <Dropdown
className="mx_UserSettings_webRtcDevices_dropdown" className="mx_UserSettings_webRtcDevices_dropdown"
value={this.state.activeAudioInput || defaultInput} value={this.state.activeAudioInput || defaultInput}
onOptionChange={this._setAudioInput}> onOptionChange={this._setAudioInput}>
{this._mapWebRtcDevicesToSpans(audioInputs)} { this._mapWebRtcDevicesToSpans(audioInputs) }
</Dropdown> </Dropdown>
</div>; </div>;
} }
@ -1145,25 +1145,25 @@ module.exports = React.createClass({
} }
webcamDropdown = <div> webcamDropdown = <div>
<h4>{_t('Camera')}</h4> <h4>{ _t('Camera') }</h4>
<Dropdown <Dropdown
className="mx_UserSettings_webRtcDevices_dropdown" className="mx_UserSettings_webRtcDevices_dropdown"
value={this.state.activeVideoInput || defaultInput} value={this.state.activeVideoInput || defaultInput}
onOptionChange={this._setVideoInput}> onOptionChange={this._setVideoInput}>
{this._mapWebRtcDevicesToSpans(videoInputs)} { this._mapWebRtcDevicesToSpans(videoInputs) }
</Dropdown> </Dropdown>
</div>; </div>;
} }
return <div> return <div>
{microphoneDropdown} { microphoneDropdown }
{webcamDropdown} { webcamDropdown }
</div>; </div>;
}, },
_renderWebRtcSettings: function() { _renderWebRtcSettings: function() {
return <div> return <div>
<h3>{_t('VoIP')}</h3> <h3>{ _t('VoIP') }</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
{ WEBRTC_SETTINGS_LABELS.map(this._renderLocalSetting) } { WEBRTC_SETTINGS_LABELS.map(this._renderLocalSetting) }
{ this._renderWebRtcDeviceSettings() } { this._renderWebRtcDeviceSettings() }
@ -1229,7 +1229,7 @@ module.exports = React.createClass({
return ( return (
<div className="mx_UserSettings_profileTableRow" key={pidIndex}> <div className="mx_UserSettings_profileTableRow" key={pidIndex}>
<div className="mx_UserSettings_profileLabelCell"> <div className="mx_UserSettings_profileLabelCell">
<label htmlFor={id}>{this.nameForMedium(val.medium)}</label> <label htmlFor={id}>{ this.nameForMedium(val.medium) }</label>
</div> </div>
<div className="mx_UserSettings_profileInputCell"> <div className="mx_UserSettings_profileInputCell">
<input type="text" key={val.address} id={id} <input type="text" key={val.address} id={id}
@ -1237,7 +1237,7 @@ module.exports = React.createClass({
/> />
</div> </div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor"> <div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<img src="img/cancel-small.svg" width="14" height="14" alt={ _t("Remove") } <img src="img/cancel-small.svg" width="14" height="14" alt={_t("Remove")}
onClick={onRemoveClick} /> onClick={onRemoveClick} />
</div> </div>
</div> </div>
@ -1250,16 +1250,16 @@ module.exports = React.createClass({
addEmailSection = ( addEmailSection = (
<div className="mx_UserSettings_profileTableRow" key="_newEmail"> <div className="mx_UserSettings_profileTableRow" key="_newEmail">
<div className="mx_UserSettings_profileLabelCell"> <div className="mx_UserSettings_profileLabelCell">
<label>{_t('Email')}</label> <label>{ _t('Email') }</label>
</div> </div>
<div className="mx_UserSettings_profileInputCell"> <div className="mx_UserSettings_profileInputCell">
<EditableText <EditableText
ref="add_email_input" ref="add_email_input"
className="mx_UserSettings_editable" className="mx_UserSettings_editable"
placeholderClassName="mx_UserSettings_threepidPlaceholder" placeholderClassName="mx_UserSettings_threepidPlaceholder"
placeholder={ _t("Add email address") } placeholder={_t("Add email address")}
blurToCancel={ false } blurToCancel={false}
onValueChanged={ this._onAddEmailEditFinished } /> onValueChanged={this._onAddEmailEditFinished} />
</div> </div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor"> <div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<img src="img/plus.svg" width="14" height="14" alt={_t("Add")} onClick={this._addEmail} /> <img src="img/plus.svg" width="14" height="14" alt={_t("Add")} onClick={this._addEmail} />
@ -1307,8 +1307,8 @@ module.exports = React.createClass({
return ( return (
<div className="mx_UserSettings"> <div className="mx_UserSettings">
<SimpleRoomHeader <SimpleRoomHeader
title={ _t("Settings") } title={_t("Settings")}
onCancelClick={ this.props.onClose } onCancelClick={this.props.onClose}
/> />
<GeminiScrollbar className="mx_UserSettings_body" <GeminiScrollbar className="mx_UserSettings_body"
@ -1326,21 +1326,21 @@ module.exports = React.createClass({
<ChangeDisplayName /> <ChangeDisplayName />
</div> </div>
</div> </div>
{threepidsSection} { threepidsSection }
</div> </div>
<div className="mx_UserSettings_avatarPicker"> <div className="mx_UserSettings_avatarPicker">
<div onClick={ this.onAvatarPickerClick }> <div onClick={this.onAvatarPickerClick}>
<ChangeAvatar ref="changeAvatar" initialAvatarUrl={avatarUrl} <ChangeAvatar ref="changeAvatar" initialAvatarUrl={avatarUrl}
showUploadSection={false} className="mx_UserSettings_avatarPicker_img"/> showUploadSection={false} className="mx_UserSettings_avatarPicker_img" />
</div> </div>
<div className="mx_UserSettings_avatarPicker_edit"> <div className="mx_UserSettings_avatarPicker_edit">
<label htmlFor="avatarInput" ref="file_label"> <label htmlFor="avatarInput" ref="file_label">
<img src="img/camera.svg" className="mx_filterFlipColor" <img src="img/camera.svg" className="mx_filterFlipColor"
alt={ _t("Upload avatar") } title={ _t("Upload avatar") } alt={_t("Upload avatar")} title={_t("Upload avatar")}
width="17" height="15" /> width="17" height="15" />
</label> </label>
<input id="avatarInput" type="file" onChange={this.onAvatarSelected}/> <input id="avatarInput" type="file" onChange={this.onAvatarSelected} />
</div> </div>
</div> </div>
</div> </div>
@ -1357,37 +1357,37 @@ module.exports = React.createClass({
</div> : null </div> : null
} }
{accountJsx} { accountJsx }
</div> </div>
{this._renderReferral()} { this._renderReferral() }
{notificationArea} { notificationArea }
{this._renderUserInterfaceSettings()} { this._renderUserInterfaceSettings() }
{this._renderLabs()} { this._renderLabs() }
{this._renderWebRtcSettings()} { this._renderWebRtcSettings() }
{this._renderDevicesPanel()} { this._renderDevicesPanel() }
{this._renderCryptoInfo()} { this._renderCryptoInfo() }
{this._renderIgnoredUsers()} { this._renderIgnoredUsers() }
{this._renderBulkOptions()} { this._renderBulkOptions() }
{this._renderBugReport()} { this._renderBugReport() }
{PlatformPeg.get().isElectron() && this._renderElectronSettings()} { PlatformPeg.get().isElectron() && this._renderElectronSettings() }
{this._renderAnalyticsControl()} { this._renderAnalyticsControl() }
<h3>{ _t("Advanced") }</h3> <h3>{ _t("Advanced") }</h3>
<div className="mx_UserSettings_section"> <div className="mx_UserSettings_section">
<div className="mx_UserSettings_advanced"> <div className="mx_UserSettings_advanced">
{ _t("Logged in as:") } {this._me} { _t("Logged in as:") } { this._me }
</div> </div>
<div className="mx_UserSettings_advanced"> <div className="mx_UserSettings_advanced">
{_t('Access Token:')} { _t('Access Token:') }
<span className="mx_UserSettings_advanced_spoiler" <span className="mx_UserSettings_advanced_spoiler"
onClick={this._showSpoiler} onClick={this._showSpoiler}
data-spoiler={ MatrixClientPeg.get().getAccessToken() }> data-spoiler={MatrixClientPeg.get().getAccessToken()}>
&lt;{ _t("click to reveal") }&gt; &lt;{ _t("click to reveal") }&gt;
</span> </span>
</div> </div>
@ -1398,23 +1398,23 @@ module.exports = React.createClass({
{ _t("Identity Server is") } { MatrixClientPeg.get().getIdentityServerUrl() } { _t("Identity Server is") } { MatrixClientPeg.get().getIdentityServerUrl() }
</div> </div>
<div className="mx_UserSettings_advanced"> <div className="mx_UserSettings_advanced">
{_t('matrix-react-sdk version:')} {(REACT_SDK_VERSION !== '<local>') { _t('matrix-react-sdk version:') } { (REACT_SDK_VERSION !== '<local>')
? gHVersionLabel('matrix-org/matrix-react-sdk', REACT_SDK_VERSION) ? gHVersionLabel('matrix-org/matrix-react-sdk', REACT_SDK_VERSION)
: REACT_SDK_VERSION : REACT_SDK_VERSION
}<br/> }<br />
{_t('riot-web version:')} {(this.state.vectorVersion !== undefined) { _t('riot-web version:') } { (this.state.vectorVersion !== undefined)
? gHVersionLabel('vector-im/riot-web', this.state.vectorVersion) ? gHVersionLabel('vector-im/riot-web', this.state.vectorVersion)
: 'unknown' : 'unknown'
}<br/> }<br />
{ _t("olm version:") } {olmVersionString}<br/> { _t("olm version:") } { olmVersionString }<br />
</div> </div>
</div> </div>
{this._renderCheckUpdate()} { this._renderCheckUpdate() }
{this._renderClearCache()} { this._renderClearCache() }
{this._renderDeactivateAccount()} { this._renderDeactivateAccount() }
</GeminiScrollbar> </GeminiScrollbar>
</div> </div>

View file

@ -13,11 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
var React = require('react'); import React from "react";
var ContentRepo = require("matrix-js-sdk").ContentRepo; import {ContentRepo} from "matrix-js-sdk";
var MatrixClientPeg = require('../../../MatrixClientPeg'); import MatrixClientPeg from "../../../MatrixClientPeg";
var Avatar = require('../../../Avatar'); import sdk from "../../../index";
var sdk = require("../../../index");
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'RoomAvatar', displayName: 'RoomAvatar',
@ -30,7 +29,7 @@ module.exports = React.createClass({
oobData: React.PropTypes.object, oobData: React.PropTypes.object,
width: React.PropTypes.number, width: React.PropTypes.number,
height: React.PropTypes.number, height: React.PropTypes.number,
resizeMethod: React.PropTypes.string resizeMethod: React.PropTypes.string,
}, },
getDefaultProps: function() { getDefaultProps: function() {
@ -44,13 +43,13 @@ module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
urls: this.getImageUrls(this.props) urls: this.getImageUrls(this.props),
}; };
}, },
componentWillReceiveProps: function(newProps) { componentWillReceiveProps: function(newProps) {
this.setState({ this.setState({
urls: this.getImageUrls(newProps) urls: this.getImageUrls(newProps),
}); });
}, },
@ -61,11 +60,10 @@ module.exports = React.createClass({
props.oobData.avatarUrl, props.oobData.avatarUrl,
Math.floor(props.width * window.devicePixelRatio), Math.floor(props.width * window.devicePixelRatio),
Math.floor(props.height * window.devicePixelRatio), Math.floor(props.height * window.devicePixelRatio),
props.resizeMethod props.resizeMethod,
), // highest priority ), // highest priority
this.getRoomAvatarUrl(props), this.getRoomAvatarUrl(props),
this.getOneToOneAvatar(props), this.getOneToOneAvatar(props), // lowest priority
this.getFallbackAvatar(props) // lowest priority
].filter(function(url) { ].filter(function(url) {
return (url != null && url != ""); return (url != null && url != "");
}); });
@ -79,17 +77,17 @@ module.exports = React.createClass({
Math.floor(props.width * window.devicePixelRatio), Math.floor(props.width * window.devicePixelRatio),
Math.floor(props.height * window.devicePixelRatio), Math.floor(props.height * window.devicePixelRatio),
props.resizeMethod, props.resizeMethod,
false false,
); );
}, },
getOneToOneAvatar: function(props) { getOneToOneAvatar: function(props) {
if (!props.room) return null; if (!props.room) return null;
var mlist = props.room.currentState.members; const mlist = props.room.currentState.members;
var userIds = []; const userIds = [];
// for .. in optimisation to return early if there are >2 keys // for .. in optimisation to return early if there are >2 keys
for (var uid in mlist) { for (const uid in mlist) {
if (mlist.hasOwnProperty(uid)) { if (mlist.hasOwnProperty(uid)) {
userIds.push(uid); userIds.push(uid);
} }
@ -99,7 +97,7 @@ module.exports = React.createClass({
} }
if (userIds.length == 2) { if (userIds.length == 2) {
var theOtherGuy = null; let theOtherGuy = null;
if (mlist[userIds[0]].userId == MatrixClientPeg.get().credentials.userId) { if (mlist[userIds[0]].userId == MatrixClientPeg.get().credentials.userId) {
theOtherGuy = mlist[userIds[1]]; theOtherGuy = mlist[userIds[1]];
} else { } else {
@ -110,7 +108,7 @@ module.exports = React.createClass({
Math.floor(props.width * window.devicePixelRatio), Math.floor(props.width * window.devicePixelRatio),
Math.floor(props.height * window.devicePixelRatio), Math.floor(props.height * window.devicePixelRatio),
props.resizeMethod, props.resizeMethod,
false false,
); );
} else if (userIds.length == 1) { } else if (userIds.length == 1) {
return mlist[userIds[0]].getAvatarUrl( return mlist[userIds[0]].getAvatarUrl(
@ -118,37 +116,24 @@ module.exports = React.createClass({
Math.floor(props.width * window.devicePixelRatio), Math.floor(props.width * window.devicePixelRatio),
Math.floor(props.height * window.devicePixelRatio), Math.floor(props.height * window.devicePixelRatio),
props.resizeMethod, props.resizeMethod,
false false,
); );
} else { } else {
return null; return null;
} }
}, },
getFallbackAvatar: function(props) {
let roomId = null;
if (props.oobData && props.oobData.roomId) {
roomId = this.props.oobData.roomId;
} else if (props.room) {
roomId = props.room.roomId;
} else {
return null;
}
return Avatar.defaultAvatarUrlForString(roomId);
},
render: function() { render: function() {
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
var {room, oobData, ...otherProps} = this.props; const {room, oobData, ...otherProps} = this.props;
var roomName = room ? room.name : oobData.name; const roomName = room ? room.name : oobData.name;
return ( return (
<BaseAvatar {...otherProps} name={roomName} <BaseAvatar {...otherProps} name={roomName}
idName={room ? room.roomId : null} idName={room ? room.roomId : null}
urls={this.state.urls} /> urls={this.state.urls} />
); );
} },
}); });

View file

@ -41,7 +41,11 @@ module.exports = React.createClass({
validAddressTypes: PropTypes.arrayOf(PropTypes.oneOf(addressTypes)), validAddressTypes: PropTypes.arrayOf(PropTypes.oneOf(addressTypes)),
onFinished: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,
groupId: PropTypes.string, groupId: PropTypes.string,
// The type of entity to search for. Default: 'user'.
pickerType: PropTypes.oneOf(['user', 'room']), pickerType: PropTypes.oneOf(['user', 'room']),
// Whether the current user should be included in the addresses returned. Only
// applicable when pickerType is `user`. Default: false.
includeSelf: PropTypes.bool,
}, },
getDefaultProps: function() { getDefaultProps: function() {
@ -50,6 +54,7 @@ module.exports = React.createClass({
focus: true, focus: true,
validAddressTypes: addressTypes, validAddressTypes: addressTypes,
pickerType: 'user', pickerType: 'user',
includeSelf: false,
}; };
}, },
@ -358,7 +363,7 @@ module.exports = React.createClass({
results.forEach((result) => { results.forEach((result) => {
if (result.room_id) { if (result.room_id) {
queryList.push({ queryList.push({
addressType: 'mx', addressType: 'mx-room-id',
address: result.room_id, address: result.room_id,
displayName: result.name, displayName: result.name,
avatarMxc: result.avatar_url, avatarMxc: result.avatar_url,
@ -366,14 +371,16 @@ module.exports = React.createClass({
}); });
return; return;
} }
if (result.user_id === MatrixClientPeg.get().credentials.userId) { if (!this.props.includeSelf &&
result.user_id === MatrixClientPeg.get().credentials.userId
) {
return; return;
} }
// Return objects, structure of which is defined // Return objects, structure of which is defined
// by UserAddressType // by UserAddressType
queryList.push({ queryList.push({
addressType: 'mx', addressType: 'mx-user-id',
address: result.user_id, address: result.user_id,
displayName: result.display_name, displayName: result.display_name,
avatarMxc: result.avatar_url, avatarMxc: result.avatar_url,
@ -412,16 +419,23 @@ module.exports = React.createClass({
address: addressText, address: addressText,
isKnown: false, isKnown: false,
}; };
if (addrType == null) { if (!this.props.validAddressTypes.includes(addrType)) {
this.setState({ error: true }); this.setState({ error: true });
return null; return null;
} else if (addrType == 'mx') { } else if (addrType == 'mx-user-id') {
const user = MatrixClientPeg.get().getUser(addrObj.address); const user = MatrixClientPeg.get().getUser(addrObj.address);
if (user) { if (user) {
addrObj.displayName = user.displayName; addrObj.displayName = user.displayName;
addrObj.avatarMxc = user.avatarUrl; addrObj.avatarMxc = user.avatarUrl;
addrObj.isKnown = true; addrObj.isKnown = true;
} }
} else if (addrType == 'mx-room-id') {
const room = MatrixClientPeg.get().getRoom(addrObj.address);
if (room) {
addrObj.displayName = room.name;
addrObj.avatarMxc = room.avatarUrl;
addrObj.isKnown = true;
}
} }
const userList = this.state.userList.slice(); const userList = this.state.userList.slice();
@ -481,7 +495,7 @@ module.exports = React.createClass({
const AddressTile = sdk.getComponent("elements.AddressTile"); const AddressTile = sdk.getComponent("elements.AddressTile");
for (let i = 0; i < this.state.userList.length; i++) { for (let i = 0; i < this.state.userList.length; i++) {
query.push( query.push(
<AddressTile key={i} address={this.state.userList[i]} canDismiss={true} onDismissed={ this.onDismissed(i) } />, <AddressTile key={i} address={this.state.userList[i]} canDismiss={true} onDismissed={this.onDismissed(i)} />,
); );
} }
} }
@ -503,23 +517,36 @@ module.exports = React.createClass({
let error; let error;
let addressSelector; let addressSelector;
if (this.state.error) { if (this.state.error) {
let tryUsing = '';
const validTypeDescriptions = this.props.validAddressTypes.map((t) => {
return {
'mx-user-id': _t("Matrix ID"),
'mx-room-id': _t("Matrix Room ID"),
'email': _t("email address"),
}[t];
});
tryUsing = _t("Try using one of the following valid address types: %(validTypesList)s.", {
validTypesList: validTypeDescriptions.join(", "),
});
error = <div className="mx_ChatInviteDialog_error"> error = <div className="mx_ChatInviteDialog_error">
{_t("You have entered an invalid contact. Try using their Matrix ID or email address.")} { _t("You have entered an invalid address.") }
<br />
{ tryUsing }
</div>; </div>;
} else if (this.state.searchError) { } else if (this.state.searchError) {
error = <div className="mx_ChatInviteDialog_error">{this.state.searchError}</div>; error = <div className="mx_ChatInviteDialog_error">{ this.state.searchError }</div>;
} else if ( } else if (
this.state.query.length > 0 && this.state.query.length > 0 &&
this.state.queryList.length === 0 && this.state.queryList.length === 0 &&
!this.state.busy !this.state.busy
) { ) {
error = <div className="mx_ChatInviteDialog_error">{_t("No results")}</div>; error = <div className="mx_ChatInviteDialog_error">{ _t("No results") }</div>;
} else { } else {
addressSelector = ( addressSelector = (
<AddressSelector ref={(ref) => {this.addressSelector = ref;}} <AddressSelector ref={(ref) => {this.addressSelector = ref;}}
addressList={ this.state.queryList } addressList={this.state.queryList}
onSelected={ this.onSelected } onSelected={this.onSelected}
truncateAt={ TRUNCATE_QUERY_LIST } truncateAt={TRUNCATE_QUERY_LIST}
/> />
); );
} }
@ -527,7 +554,7 @@ module.exports = React.createClass({
return ( return (
<div className="mx_ChatInviteDialog" onKeyDown={this.onKeyDown}> <div className="mx_ChatInviteDialog" onKeyDown={this.onKeyDown}>
<div className="mx_Dialog_title"> <div className="mx_Dialog_title">
{this.props.title} { this.props.title }
</div> </div>
<AccessibleButton className="mx_ChatInviteDialog_cancel" <AccessibleButton className="mx_ChatInviteDialog_cancel"
onClick={this.onCancel} > onClick={this.onCancel} >
@ -543,7 +570,7 @@ module.exports = React.createClass({
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button className="mx_Dialog_primary" onClick={this.onButtonClick}> <button className="mx_Dialog_primary" onClick={this.onButtonClick}>
{this.props.button} { this.props.button }
</button> </button>
</div> </div>
</div> </div>

View file

@ -52,20 +52,20 @@ export default React.createClass({
return ( return (
<BaseDialog className="mx_ConfirmUserActionDialog" onFinished={this.props.onFinished} <BaseDialog className="mx_ConfirmUserActionDialog" onFinished={this.props.onFinished}
onEnterPressed={ this.onOk } onEnterPressed={this.onOk}
title={title} title={title}
> >
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
{_t("Are you sure you wish to remove (delete) this event? " + { _t("Are you sure you wish to remove (delete) this event? " +
"Note that if you delete a room name or topic change, it could undo the change.")} "Note that if you delete a room name or topic change, it could undo the change.") }
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button className={confirmButtonClass} onClick={this.onOk}> <button className={confirmButtonClass} onClick={this.onOk}>
{_t("Remove")} { _t("Remove") }
</button> </button>
<button onClick={this.onCancel}> <button onClick={this.onCancel}>
{_t("Cancel")} { _t("Cancel") }
</button> </button>
</div> </div>
</BaseDialog> </BaseDialog>

View file

@ -88,7 +88,7 @@ export default React.createClass({
<form onSubmit={this.onOk}> <form onSubmit={this.onOk}>
<input className="mx_ConfirmUserActionDialog_reasonField" <input className="mx_ConfirmUserActionDialog_reasonField"
ref={this._collectReasonField} ref={this._collectReasonField}
placeholder={ _t("Reason") } placeholder={_t("Reason")}
autoFocus={true} autoFocus={true}
/> />
</form> </form>
@ -112,22 +112,22 @@ export default React.createClass({
return ( return (
<BaseDialog className="mx_ConfirmUserActionDialog" onFinished={this.props.onFinished} <BaseDialog className="mx_ConfirmUserActionDialog" onFinished={this.props.onFinished}
onEnterPressed={ this.onOk } onEnterPressed={this.onOk}
title={title} title={title}
> >
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<div className="mx_ConfirmUserActionDialog_avatar"> <div className="mx_ConfirmUserActionDialog_avatar">
{avatar} { avatar }
</div> </div>
<div className="mx_ConfirmUserActionDialog_name">{name}</div> <div className="mx_ConfirmUserActionDialog_name">{ name }</div>
<div className="mx_ConfirmUserActionDialog_userId">{userId}</div> <div className="mx_ConfirmUserActionDialog_userId">{ userId }</div>
</div> </div>
{reasonBox} { reasonBox }
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button className={confirmButtonClass} <button className={confirmButtonClass}
onClick={this.onOk} autoFocus={!this.props.askReason} onClick={this.onOk} autoFocus={!this.props.askReason}
> >
{this.props.action} { this.props.action }
</button> </button>
<button onClick={this.onCancel}> <button onClick={this.onCancel}>

View file

@ -142,8 +142,8 @@ export default React.createClass({
// rather than displaying what the server gives us, but synapse doesn't give // rather than displaying what the server gives us, but synapse doesn't give
// any yet. // any yet.
createErrorNode = <div className="error"> createErrorNode = <div className="error">
<div>{_t('Room creation failed')}</div> <div>{ _t('Room creation failed') }</div>
<div>{this.state.createError.message}</div> <div>{ this.state.createError.message }</div>
</div>; </div>;
} }
@ -156,7 +156,7 @@ export default React.createClass({
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<div className="mx_CreateGroupDialog_inputRow"> <div className="mx_CreateGroupDialog_inputRow">
<div className="mx_CreateGroupDialog_label"> <div className="mx_CreateGroupDialog_label">
<label htmlFor="groupname">{_t('Group Name')}</label> <label htmlFor="groupname">{ _t('Group Name') }</label>
</div> </div>
<div> <div>
<input id="groupname" className="mx_CreateGroupDialog_input" <input id="groupname" className="mx_CreateGroupDialog_input"
@ -169,7 +169,7 @@ export default React.createClass({
</div> </div>
<div className="mx_CreateGroupDialog_inputRow"> <div className="mx_CreateGroupDialog_inputRow">
<div className="mx_CreateGroupDialog_label"> <div className="mx_CreateGroupDialog_label">
<label htmlFor="groupid">{_t('Group ID')}</label> <label htmlFor="groupid">{ _t('Group ID') }</label>
</div> </div>
<div> <div>
<input id="groupid" className="mx_CreateGroupDialog_input" <input id="groupid" className="mx_CreateGroupDialog_input"
@ -182,9 +182,9 @@ export default React.createClass({
</div> </div>
</div> </div>
<div className="error"> <div className="error">
{this.state.groupIdError} { this.state.groupIdError }
</div> </div>
{createErrorNode} { createErrorNode }
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button onClick={this._onCancel}> <button onClick={this._onCancel}>

View file

@ -28,25 +28,25 @@ export default function DeviceVerifyDialog(props) {
const body = ( const body = (
<div> <div>
<p> <p>
{_t("To verify that this device can be trusted, please contact its " + { _t("To verify that this device can be trusted, please contact its " +
"owner using some other means (e.g. in person or a phone call) " + "owner using some other means (e.g. in person or a phone call) " +
"and ask them whether the key they see in their User Settings " + "and ask them whether the key they see in their User Settings " +
"for this device matches the key below:")} "for this device matches the key below:") }
</p> </p>
<div className="mx_UserSettings_cryptoSection"> <div className="mx_UserSettings_cryptoSection">
<ul> <ul>
<li><label>{_t("Device name")}:</label> <span>{ props.device.getDisplayName() }</span></li> <li><label>{ _t("Device name") }:</label> <span>{ props.device.getDisplayName() }</span></li>
<li><label>{_t("Device ID")}:</label> <span><code>{ props.device.deviceId}</code></span></li> <li><label>{ _t("Device ID") }:</label> <span><code>{ props.device.deviceId }</code></span></li>
<li><label>{_t("Device key")}:</label> <span><code><b>{ key }</b></code></span></li> <li><label>{ _t("Device key") }:</label> <span><code><b>{ key }</b></code></span></li>
</ul> </ul>
</div> </div>
<p> <p>
{_t("If it matches, press the verify button below. " + { _t("If it matches, press the verify button below. " +
"If it doesn't, then someone else is intercepting this device " + "If it doesn't, then someone else is intercepting this device " +
"and you probably want to press the blacklist button instead.")} "and you probably want to press the blacklist button instead.") }
</p> </p>
<p> <p>
{_t("In future this verification process will be more sophisticated.")} { _t("In future this verification process will be more sophisticated.") }
</p> </p>
</div> </div>
); );

View file

@ -63,11 +63,11 @@ export default React.createClass({
<BaseDialog className="mx_ErrorDialog" onFinished={this.props.onFinished} <BaseDialog className="mx_ErrorDialog" onFinished={this.props.onFinished}
title={this.props.title || _t('Error')}> title={this.props.title || _t('Error')}>
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
{this.props.description || _t('An error has occurred.')} { this.props.description || _t('An error has occurred.') }
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button ref="button" className="mx_Dialog_primary" onClick={this.props.onFinished}> <button ref="button" className="mx_Dialog_primary" onClick={this.props.onFinished}>
{this.props.button || _t('OK')} { this.props.button || _t('OK') }
</button> </button>
</div> </div>
</BaseDialog> </BaseDialog>

View file

@ -126,17 +126,17 @@ export default React.createClass({
return ( return (
<div> <div>
<p>{text}</p> <p>{ text }</p>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button onClick={this._onVerifyClicked}> <button onClick={this._onVerifyClicked}>
{_t('Start verification')} { _t('Start verification') }
</button> </button>
<button onClick={this._onShareClicked}> <button onClick={this._onShareClicked}>
{_t('Share without verifying')} { _t('Share without verifying') }
</button> </button>
<button onClick={this._onIgnoreClicked}> <button onClick={this._onIgnoreClicked}>
{_t('Ignore request')} { _t('Ignore request') }
</button> </button>
</div> </div>
</div> </div>
@ -154,7 +154,7 @@ export default React.createClass({
} else { } else {
content = ( content = (
<div> <div>
<p>{_t('Loading device info...')}</p> <p>{ _t('Loading device info...') }</p>
<Spinner /> <Spinner />
</div> </div>
); );
@ -165,7 +165,7 @@ export default React.createClass({
onFinished={this.props.onFinished} onFinished={this.props.onFinished}
title={_t('Encryption key request')} title={_t('Encryption key request')}
> >
{content} { content }
</BaseDialog> </BaseDialog>
); );
}, },

View file

@ -55,7 +55,7 @@ export default React.createClass({
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const cancelButton = this.props.hasCancelButton ? ( const cancelButton = this.props.hasCancelButton ? (
<button onClick={this.onCancel}> <button onClick={this.onCancel}>
{_t("Cancel")} { _t("Cancel") }
</button> </button>
) : null; ) : null;
const buttonClasses = classnames({ const buttonClasses = classnames({
@ -64,18 +64,18 @@ export default React.createClass({
}); });
return ( return (
<BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished} <BaseDialog className="mx_QuestionDialog" onFinished={this.props.onFinished}
onEnterPressed={ this.onOk } onEnterPressed={this.onOk}
title={this.props.title} title={this.props.title}
> >
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
{this.props.description} { this.props.description }
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button className={buttonClasses} onClick={this.onOk} autoFocus={this.props.focus}> <button className={buttonClasses} onClick={this.onOk} autoFocus={this.props.focus}>
{this.props.button || _t('OK')} { this.props.button || _t('OK') }
</button> </button>
{this.props.extraButtons} { this.props.extraButtons }
{cancelButton} { cancelButton }
</div> </div>
</BaseDialog> </BaseDialog>
); );

View file

@ -45,10 +45,10 @@ export default React.createClass({
if (SdkConfig.get().bug_report_endpoint_url) { if (SdkConfig.get().bug_report_endpoint_url) {
bugreport = ( bugreport = (
<p> <p>
{_tJsx( { _tJsx(
"Otherwise, <a>click here</a> to send a bug report.", "Otherwise, <a>click here</a> to send a bug report.",
/<a>(.*?)<\/a>/, (sub) => <a onClick={this._sendBugReport} key="bugreport" href='#'>{sub}</a>, /<a>(.*?)<\/a>/, (sub) => <a onClick={this._sendBugReport} key="bugreport" href='#'>{ sub }</a>,
)} ) }
</p> </p>
); );
} }
@ -57,19 +57,19 @@ export default React.createClass({
<BaseDialog className="mx_ErrorDialog" onFinished={this.props.onFinished} <BaseDialog className="mx_ErrorDialog" onFinished={this.props.onFinished}
title={_t('Unable to restore session')}> title={_t('Unable to restore session')}>
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<p>{_t("We encountered an error trying to restore your previous session. If " + <p>{ _t("We encountered an error trying to restore your previous session. If " +
"you continue, you will need to log in again, and encrypted chat " + "you continue, you will need to log in again, and encrypted chat " +
"history will be unreadable.")}</p> "history will be unreadable.") }</p>
<p>{_t("If you have previously used a more recent version of Riot, your session " + <p>{ _t("If you have previously used a more recent version of Riot, your session " +
"may be incompatible with this version. Close this window and return " + "may be incompatible with this version. Close this window and return " +
"to the more recent version.")}</p> "to the more recent version.") }</p>
{bugreport} { bugreport }
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button className="mx_Dialog_primary" onClick={this._continueClicked}> <button className="mx_Dialog_primary" onClick={this._continueClicked}>
{_t("Continue anyway")} { _t("Continue anyway") }
</button> </button>
</div> </div>
</BaseDialog> </BaseDialog>

View file

@ -130,10 +130,10 @@ export default React.createClass({
const emailInput = this.state.emailBusy ? <Spinner /> : <EditableText const emailInput = this.state.emailBusy ? <Spinner /> : <EditableText
className="mx_SetEmailDialog_email_input" className="mx_SetEmailDialog_email_input"
placeholder={ _t("Email address") } placeholder={_t("Email address")}
placeholderClassName="mx_SetEmailDialog_email_input_placeholder" placeholderClassName="mx_SetEmailDialog_email_input_placeholder"
blurToCancel={ false } blurToCancel={false}
onValueChanged={ this.onEmailAddressChanged } />; onValueChanged={this.onEmailAddressChanged} />;
return ( return (
<BaseDialog className="mx_SetEmailDialog" <BaseDialog className="mx_SetEmailDialog"

View file

@ -226,7 +226,7 @@ export default React.createClass({
let usernameIndicator = null; let usernameIndicator = null;
let usernameBusyIndicator = null; let usernameBusyIndicator = null;
if (this.state.usernameBusy) { if (this.state.usernameBusy) {
usernameBusyIndicator = <Spinner w="24" h="24"/>; usernameBusyIndicator = <Spinner w="24" h="24" />;
} else { } else {
const usernameAvailable = this.state.username && const usernameAvailable = this.state.username &&
this.state.usernameCheckSupport && !this.state.usernameError; this.state.usernameCheckSupport && !this.state.usernameError;
@ -275,17 +275,17 @@ export default React.createClass({
/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/,
], ],
[ [
(sub) => <span>{this.props.homeserverUrl}</span>, (sub) => <span>{ this.props.homeserverUrl }</span>,
(sub) => <a href="#" onClick={this.props.onDifferentServerClicked}>{sub}</a>, (sub) => <a href="#" onClick={this.props.onDifferentServerClicked}>{ sub }</a>,
], ],
)} ) }
</p> </p>
<p> <p>
{ _tJsx( { _tJsx(
'If you already have a Matrix account you can <a>log in</a> instead.', 'If you already have a Matrix account you can <a>log in</a> instead.',
/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/,
[(sub) => <a href="#" onClick={this.props.onLoginClick}>{sub}</a>], [(sub) => <a href="#" onClick={this.props.onLoginClick}>{ sub }</a>],
)} ) }
</p> </p>
{ auth } { auth }
{ authErrorIndicator } { authErrorIndicator }

View file

@ -65,10 +65,10 @@ export default React.createClass({
> >
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<div className="mx_TextInputDialog_label"> <div className="mx_TextInputDialog_label">
<label htmlFor="textinput"> {this.props.description} </label> <label htmlFor="textinput"> { this.props.description } </label>
</div> </div>
<div> <div>
<input id="textinput" ref="textinput" className="mx_TextInputDialog_input" defaultValue={this.props.value} autoFocus={this.props.focus} size="64" onKeyDown={this.onKeyDown}/> <input id="textinput" ref="textinput" className="mx_TextInputDialog_input" defaultValue={this.props.value} autoFocus={this.props.focus} size="64" onKeyDown={this.onKeyDown} />
</div> </div>
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
@ -76,7 +76,7 @@ export default React.createClass({
{ _t("Cancel") } { _t("Cancel") }
</button> </button>
<button className="mx_Dialog_primary" onClick={this.onOk}> <button className="mx_Dialog_primary" onClick={this.onOk}>
{this.props.button} { this.props.button }
</button> </button>
</div> </div>
</BaseDialog> </BaseDialog>

View file

@ -45,11 +45,12 @@ export default React.createClass({
const address = this.props.address; const address = this.props.address;
const name = address.displayName || address.address; const name = address.displayName || address.address;
let imgUrls = []; const imgUrls = [];
const isMatrixAddress = ['mx-user-id', 'mx-room-id'].includes(address.addressType);
if (address.addressType === "mx" && address.avatarMxc) { if (isMatrixAddress && address.avatarMxc) {
imgUrls.push(MatrixClientPeg.get().mxcUrlToHttp( imgUrls.push(MatrixClientPeg.get().mxcUrlToHttp(
address.avatarMxc, 25, 25, 'crop' address.avatarMxc, 25, 25, 'crop',
)); ));
} else if (address.addressType === 'email') { } else if (address.addressType === 'email') {
imgUrls.push('img/icon-email-user.svg'); imgUrls.push('img/icon-email-user.svg');
@ -77,7 +78,7 @@ export default React.createClass({
let info; let info;
let error = false; let error = false;
if (address.addressType === "mx" && address.isKnown) { if (isMatrixAddress && address.isKnown) {
const idClasses = classNames({ const idClasses = classNames({
"mx_AddressTile_id": true, "mx_AddressTile_id": true,
"mx_AddressTile_justified": this.props.justified, "mx_AddressTile_justified": this.props.justified,
@ -89,7 +90,7 @@ export default React.createClass({
<div className={idClasses}>{ address.address }</div> <div className={idClasses}>{ address.address }</div>
</div> </div>
); );
} else if (address.addressType === "mx") { } else if (isMatrixAddress) {
const unknownMxClasses = classNames({ const unknownMxClasses = classNames({
"mx_AddressTile_unknownMx": true, "mx_AddressTile_unknownMx": true,
"mx_AddressTile_justified": this.props.justified, "mx_AddressTile_justified": this.props.justified,

View file

@ -50,16 +50,16 @@ export default class AppPermission extends React.Component {
let e2eWarningText; let e2eWarningText;
if (this.props.isRoomEncrypted) { if (this.props.isRoomEncrypted) {
e2eWarningText = e2eWarningText =
<span className='mx_AppPermissionWarningTextLabel'>{_t('NOTE: Apps are not end-to-end encrypted')}</span>; <span className='mx_AppPermissionWarningTextLabel'>{ _t('NOTE: Apps are not end-to-end encrypted') }</span>;
} }
return ( return (
<div className='mx_AppPermissionWarning'> <div className='mx_AppPermissionWarning'>
<div className='mx_AppPermissionWarningImage'> <div className='mx_AppPermissionWarningImage'>
<img src='img/warning.svg' alt={_t('Warning!')}/> <img src='img/warning.svg' alt={_t('Warning!')} />
</div> </div>
<div className='mx_AppPermissionWarningText'> <div className='mx_AppPermissionWarningText'>
<span className='mx_AppPermissionWarningTextLabel'>{_t('Do you want to load widget from URL:')}</span> <span className='mx_AppPermissionWarningTextURL'>{this.state.curlBase}</span> <span className='mx_AppPermissionWarningTextLabel'>{ _t('Do you want to load widget from URL:') }</span> <span className='mx_AppPermissionWarningTextURL'>{ this.state.curlBase }</span>
{e2eWarningText} { e2eWarningText }
</div> </div>
<input <input
className='mx_AppPermissionButton' className='mx_AppPermissionButton'

View file

@ -261,7 +261,7 @@ export default React.createClass({
if (this.state.loading) { if (this.state.loading) {
appTileBody = ( appTileBody = (
<div className='mx_AppTileBody mx_AppLoading'> <div className='mx_AppTileBody mx_AppLoading'>
<MessageSpinner msg='Loading...'/> <MessageSpinner msg='Loading...' />
</div> </div>
); );
} else if (this.state.hasPermissionToLoad == true) { } else if (this.state.hasPermissionToLoad == true) {
@ -312,19 +312,19 @@ export default React.createClass({
return ( return (
<div className={this.props.fullWidth ? "mx_AppTileFullWidth" : "mx_AppTile"} id={this.props.id}> <div className={this.props.fullWidth ? "mx_AppTileFullWidth" : "mx_AppTile"} id={this.props.id}>
<div ref="menu_bar" className="mx_AppTileMenuBar" onClick={this.onClickMenuBar}> <div ref="menu_bar" className="mx_AppTileMenuBar" onClick={this.onClickMenuBar}>
{this.formatAppTileName()} { this.formatAppTileName() }
<span className="mx_AppTileMenuBarWidgets"> <span className="mx_AppTileMenuBarWidgets">
{/* Edit widget */} { /* Edit widget */ }
{showEditButton && <img { showEditButton && <img
src="img/edit.svg" src="img/edit.svg"
className="mx_filterFlipColor mx_AppTileMenuBarWidget mx_AppTileMenuBarWidgetPadding" className="mx_filterFlipColor mx_AppTileMenuBarWidget mx_AppTileMenuBarWidgetPadding"
width="8" height="8" width="8" height="8"
alt={_t('Edit')} alt={_t('Edit')}
title={_t('Edit')} title={_t('Edit')}
onClick={this._onEditClick} onClick={this._onEditClick}
/>} /> }
{/* Delete widget */} { /* Delete widget */ }
<img src={deleteIcon} <img src={deleteIcon}
className={deleteClasses} className={deleteClasses}
width="8" height="8" width="8" height="8"
@ -334,7 +334,7 @@ export default React.createClass({
/> />
</span> </span>
</div> </div>
{appTileBody} { appTileBody }
</div> </div>
); );
}, },

View file

@ -6,10 +6,10 @@ const AppWarning = (props) => {
return ( return (
<div className='mx_AppPermissionWarning'> <div className='mx_AppPermissionWarning'>
<div className='mx_AppPermissionWarningImage'> <div className='mx_AppPermissionWarningImage'>
<img src='img/warning.svg' alt={_t('Warning!')}/> <img src='img/warning.svg' alt={_t('Warning!')} />
</div> </div>
<div className='mx_AppPermissionWarningText'> <div className='mx_AppPermissionWarningText'>
<span className='mx_AppPermissionWarningTextLabel'>{props.errorMsg}</span> <span className='mx_AppPermissionWarningTextLabel'>{ props.errorMsg }</span>
</div> </div>
</div> </div>
); );

View file

@ -157,7 +157,12 @@ class FlairAvatar extends React.Component {
render() { render() {
const httpUrl = this.context.matrixClient.mxcUrlToHttp( const httpUrl = this.context.matrixClient.mxcUrlToHttp(
this.props.groupProfile.avatarUrl, 14, 14, 'scale', false); this.props.groupProfile.avatarUrl, 14, 14, 'scale', false);
return <img src={httpUrl} width="14px" height="14px" onClick={this.onClick}/>; return <img
src={httpUrl}
width="14px"
height="14px"
onClick={this.onClick}
title={this.props.groupProfile.groupId} />;
} }
} }
@ -186,7 +191,7 @@ export default class Flair extends React.Component {
componentWillMount() { componentWillMount() {
this._unmounted = false; this._unmounted = false;
if (UserSettingsStore.isFeatureEnabled('feature_flair') && groupSupport) { if (UserSettingsStore.isFeatureEnabled('feature_groups') && groupSupport) {
this._generateAvatars(); this._generateAvatars();
} }
} }
@ -233,11 +238,11 @@ export default class Flair extends React.Component {
return <div />; return <div />;
} }
const avatars = this.state.profiles.map((profile, index) => { const avatars = this.state.profiles.map((profile, index) => {
return <FlairAvatar key={index} groupProfile={profile}/>; return <FlairAvatar key={index} groupProfile={profile} />;
}); });
return ( return (
<span className="mx_Flair" style={{"marginLeft": "5px", "verticalAlign": "-3px"}}> <span className="mx_Flair" style={{"marginLeft": "5px", "verticalAlign": "-3px"}}>
{avatars} { avatars }
</span> </span>
); );
} }

View file

@ -0,0 +1,38 @@
/*
Copyright 2017 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.
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 sdk from '../../../index';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
const GroupsButton = function(props) {
const ActionButton = sdk.getComponent('elements.ActionButton');
return (
<ActionButton action="view_my_groups"
label={_t("Groups")}
iconPath="img/icons-groups.svg"
size={props.size}
tooltip={props.tooltip}
/>
);
};
GroupsButton.propTypes = {
size: PropTypes.string,
tooltip: PropTypes.bool,
};
export default GroupsButton;

View file

@ -80,7 +80,7 @@ export default class ManageIntegsButton extends React.Component {
}); });
if (this.state.scalarError && !this.scalarClient.hasCredentials()) { if (this.state.scalarError && !this.scalarClient.hasCredentials()) {
integrationsWarningTriangle = <img src="img/warning.svg" title={_t('Integrations Error')} width="17"/>; integrationsWarningTriangle = <img src="img/warning.svg" title={_t('Integrations Error')} width="17" />;
// Popup shown when hovering over integrationsButton_error (via CSS) // Popup shown when hovering over integrationsButton_error (via CSS)
integrationsErrorPopup = ( integrationsErrorPopup = (
<span className="mx_RoomSettings_integrationsButton_errorPopup"> <span className="mx_RoomSettings_integrationsButton_errorPopup">
@ -90,8 +90,8 @@ export default class ManageIntegsButton extends React.Component {
} }
integrationsButton = ( integrationsButton = (
<AccessibleButton className={integrationsButtonClasses} onClick={this.onManageIntegrations} title={ _t('Manage Integrations') }> <AccessibleButton className={integrationsButtonClasses} onClick={this.onManageIntegrations} title={_t('Manage Integrations')}>
<TintableSvg src="img/icons-apps.svg" width="35" height="35"/> <TintableSvg src="img/icons-apps.svg" width="35" height="35" />
{ integrationsWarningTriangle } { integrationsWarningTriangle }
{ integrationsErrorPopup } { integrationsErrorPopup }
</AccessibleButton> </AccessibleButton>

View file

@ -26,8 +26,8 @@ module.exports = React.createClass({
const msg = this.props.msg || "Loading..."; const msg = this.props.msg || "Loading...";
return ( return (
<div className="mx_Spinner"> <div className="mx_Spinner">
<div className="mx_Spinner_Msg">{msg}</div>&nbsp; <div className="mx_Spinner_Msg">{ msg }</div>&nbsp;
<img src="img/spinner.gif" width={w} height={h} className={imgClass}/> <img src="img/spinner.gif" width={w} height={h} className={imgClass} />
</div> </div>
); );
}, },

View file

@ -167,7 +167,7 @@ const Pill = React.createClass({
userId = member.userId; userId = member.userId;
linkText = member.rawDisplayName.replace(' (IRC)', ''); // FIXME when groups are done linkText = member.rawDisplayName.replace(' (IRC)', ''); // FIXME when groups are done
if (this.props.shouldShowPillAvatar) { if (this.props.shouldShowPillAvatar) {
avatar = <MemberAvatar member={member} width={16} height={16}/>; avatar = <MemberAvatar member={member} width={16} height={16} />;
} }
pillClass = 'mx_UserPill'; pillClass = 'mx_UserPill';
href = null; href = null;
@ -180,7 +180,7 @@ const Pill = React.createClass({
if (room) { if (room) {
linkText = (room ? getDisplayAliasForRoom(room) : null) || resource; linkText = (room ? getDisplayAliasForRoom(room) : null) || resource;
if (this.props.shouldShowPillAvatar) { if (this.props.shouldShowPillAvatar) {
avatar = <RoomAvatar room={room} width={16} height={16}/>; avatar = <RoomAvatar room={room} width={16} height={16} />;
} }
pillClass = 'mx_RoomPill'; pillClass = 'mx_RoomPill';
} }
@ -195,12 +195,12 @@ const Pill = React.createClass({
if (this.state.pillType) { if (this.state.pillType) {
return this.props.inMessage ? return this.props.inMessage ?
<a className={classes} href={href} onClick={onClick} title={resource} data-offset-key={this.props.offsetKey}> <a className={classes} href={href} onClick={onClick} title={resource} data-offset-key={this.props.offsetKey}>
{avatar} { avatar }
{linkText} { linkText }
</a> : </a> :
<span className={classes} title={resource} data-offset-key={this.props.offsetKey}> <span className={classes} title={resource} data-offset-key={this.props.offsetKey}>
{avatar} { avatar }
{linkText} { linkText }
</span>; </span>;
} else { } else {
// Deliberately render nothing if the URL isn't recognised // Deliberately render nothing if the URL isn't recognised

View file

@ -46,7 +46,7 @@ module.exports = React.createClass({
truncateAt: 2, truncateAt: 2,
createOverflowElement: function(overflowCount, totalCount) { createOverflowElement: function(overflowCount, totalCount) {
return ( return (
<div>{_t("And %(count)s more...", {count: overflowCount})}</div> <div>{ _t("And %(count)s more...", {count: overflowCount}) }</div>
); );
}, },
}; };
@ -93,8 +93,8 @@ module.exports = React.createClass({
return ( return (
<div className={this.props.className}> <div className={this.props.className}>
{childNodes} { childNodes }
{overflowNode} { overflowNode }
</div> </div>
); );
}, },

View file

@ -50,7 +50,7 @@ export default React.createClass({
className="mx_GroupInviteTile_name" className="mx_GroupInviteTile_name"
dir="auto" dir="auto"
> >
{this.props.group.name} { this.props.group.name }
</EmojiText>; </EmojiText>;
const badge = <div className="mx_GroupInviteTile_badge">!</div>; const badge = <div className="mx_GroupInviteTile_badge">!</div>;
@ -58,11 +58,11 @@ export default React.createClass({
return ( return (
<AccessibleButton className="mx_GroupInviteTile" onClick={this.onClick}> <AccessibleButton className="mx_GroupInviteTile" onClick={this.onClick}>
<div className="mx_GroupInviteTile_avatarContainer"> <div className="mx_GroupInviteTile_avatarContainer">
{av} { av }
</div> </div>
<div className="mx_GroupInviteTile_nameContainer"> <div className="mx_GroupInviteTile_nameContainer">
{label} { label }
{badge} { badge }
</div> </div>
</AccessibleButton> </AccessibleButton>
); );

View file

@ -128,7 +128,7 @@ module.exports = withMatrixClient(React.createClass({
kickButton = ( kickButton = (
<AccessibleButton className="mx_MemberInfo_field" <AccessibleButton className="mx_MemberInfo_field"
onClick={this._onKick}> onClick={this._onKick}>
{_t('Remove from group')} { _t('Remove from group') }
</AccessibleButton> </AccessibleButton>
); );
@ -143,11 +143,11 @@ module.exports = withMatrixClient(React.createClass({
if (kickButton || adminButton) { if (kickButton || adminButton) {
adminTools = adminTools =
<div className="mx_MemberInfo_adminTools"> <div className="mx_MemberInfo_adminTools">
<h3>{_t("Admin Tools")}</h3> <h3>{ _t("Admin Tools") }</h3>
<div className="mx_MemberInfo_buttons"> <div className="mx_MemberInfo_buttons">
{kickButton} { kickButton }
{adminButton} { adminButton }
</div> </div>
</div>; </div>;
} }
@ -173,13 +173,13 @@ module.exports = withMatrixClient(React.createClass({
<div className="mx_MemberInfo"> <div className="mx_MemberInfo">
<GeminiScrollbar autoshow={true}> <GeminiScrollbar autoshow={true}>
<AccessibleButton className="mx_MemberInfo_cancel"onClick={this._onCancel}> <AccessibleButton className="mx_MemberInfo_cancel"onClick={this._onCancel}>
<img src="img/cancel.svg" width="18" height="18"/> <img src="img/cancel.svg" width="18" height="18" />
</AccessibleButton> </AccessibleButton>
<div className="mx_MemberInfo_avatar"> <div className="mx_MemberInfo_avatar">
{avatar} { avatar }
</div> </div>
<EmojiText element="h2">{groupMemberName}</EmojiText> <EmojiText element="h2">{ groupMemberName }</EmojiText>
<div className="mx_MemberInfo_profile"> <div className="mx_MemberInfo_profile">
<div className="mx_MemberInfo_profileField"> <div className="mx_MemberInfo_profileField">

View file

@ -124,7 +124,9 @@ export default withMatrixClient(React.createClass({
render: function() { render: function() {
if (this.state.fetching) { if (this.state.fetching) {
const Spinner = sdk.getComponent("elements.Spinner"); const Spinner = sdk.getComponent("elements.Spinner");
return <Spinner />; return (<div className="mx_MemberList">
<Spinner />
</div>);
} else if (this.state.members === null) { } else if (this.state.members === null) {
return null; return null;
} }
@ -133,7 +135,7 @@ export default withMatrixClient(React.createClass({
<form autoComplete="off"> <form autoComplete="off">
<input className="mx_GroupMemberList_query" id="mx_GroupMemberList_query" type="text" <input className="mx_GroupMemberList_query" id="mx_GroupMemberList_query" type="text"
onChange={this.onSearchQueryChanged} value={this.state.searchQuery} onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
placeholder={ _t('Filter group members') } /> placeholder={_t('Filter group members')} />
</form> </form>
); );
@ -144,7 +146,7 @@ export default withMatrixClient(React.createClass({
<GeminiScrollbar autoshow={true} className="mx_MemberList_joined mx_MemberList_outerWrapper"> <GeminiScrollbar autoshow={true} className="mx_MemberList_joined mx_MemberList_outerWrapper">
<TruncatedList className="mx_MemberList_wrapper" truncateAt={this.state.truncateAt} <TruncatedList className="mx_MemberList_wrapper" truncateAt={this.state.truncateAt}
createOverflowElement={this._createOverflowTile}> createOverflowElement={this._createOverflowTile}>
{this.makeGroupMemberTiles(this.state.searchQuery)} { this.makeGroupMemberTiles(this.state.searchQuery) }
</TruncatedList> </TruncatedList>
</GeminiScrollbar> </GeminiScrollbar>
</div> </div>

View file

@ -123,7 +123,7 @@ export default React.createClass({
<form autoComplete="off"> <form autoComplete="off">
<input className="mx_GroupRoomList_query" id="mx_GroupRoomList_query" type="text" <input className="mx_GroupRoomList_query" id="mx_GroupRoomList_query" type="text"
onChange={this.onSearchQueryChanged} value={this.state.searchQuery} onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
placeholder={ _t('Filter group rooms') } /> placeholder={_t('Filter group rooms')} />
</form> </form>
); );
@ -134,7 +134,7 @@ export default React.createClass({
<GeminiScrollbar autoshow={true} className="mx_GroupRoomList_joined mx_GroupRoomList_outerWrapper"> <GeminiScrollbar autoshow={true} className="mx_GroupRoomList_joined mx_GroupRoomList_outerWrapper">
<TruncatedList className="mx_GroupRoomList_wrapper" truncateAt={this.state.truncateAt} <TruncatedList className="mx_GroupRoomList_wrapper" truncateAt={this.state.truncateAt}
createOverflowElement={this._createOverflowTile}> createOverflowElement={this._createOverflowTile}>
{this.makeGroupRoomTiles(this.state.searchQuery)} { this.makeGroupRoomTiles(this.state.searchQuery) }
</TruncatedList> </TruncatedList>
</GeminiScrollbar> </GeminiScrollbar>
</div> </div>

View file

@ -71,10 +71,10 @@ const GroupRoomTile = React.createClass({
return ( return (
<AccessibleButton className="mx_GroupRoomTile" onClick={this.onClick}> <AccessibleButton className="mx_GroupRoomTile" onClick={this.onClick}>
<div className="mx_GroupRoomTile_avatar"> <div className="mx_GroupRoomTile_avatar">
{av} { av }
</div> </div>
<div className="mx_GroupRoomTile_name"> <div className="mx_GroupRoomTile_name">
{name} { name }
</div> </div>
</AccessibleButton> </AccessibleButton>
); );

View file

@ -25,7 +25,7 @@ module.exports = React.createClass({
render: function() { render: function() {
return ( return (
<div className="mx_Login_links"> <div className="mx_Login_links">
<a href="https://matrix.org">{_t("powered by Matrix")}</a> <a href="https://matrix.org">{ _t("powered by Matrix") }</a>
</div> </div>
); );
}, },

View file

@ -32,9 +32,9 @@ export default function SenderProfile(props) {
return ( return (
<div className="mx_SenderProfile" dir="auto" onClick={props.onClick}> <div className="mx_SenderProfile" dir="auto" onClick={props.onClick}>
<EmojiText className="mx_SenderProfile_name">{name || ''}</EmojiText> <EmojiText className="mx_SenderProfile_name">{ name || '' }</EmojiText>
{props.enableFlair ? <Flair userId={mxEvent.getSender()} /> : null} { props.enableFlair ? <Flair userId={mxEvent.getSender()} /> : null }
{props.aux ? <EmojiText className="mx_SenderProfile_aux"> {props.aux}</EmojiText> : null} { props.aux ? <EmojiText className="mx_SenderProfile_aux"> { props.aux }</EmojiText> : null }
</div> </div>
); );
} }

View file

@ -31,7 +31,7 @@ module.exports = React.createClass({
const text = this.props.mxEvent.getContent().body; const text = this.props.mxEvent.getContent().body;
return ( return (
<span className="mx_UnknownBody" title={tooltip}> <span className="mx_UnknownBody" title={tooltip}>
{text} { text }
</span> </span>
); );
}, },

View file

@ -231,16 +231,16 @@ module.exports = React.createClass({
"mx_AddWidget_button" "mx_AddWidget_button"
} }
title={_t('Add a widget')}> title={_t('Add a widget')}>
[+] {_t('Add a widget')} [+] { _t('Add a widget') }
</div>; </div>;
} }
return ( return (
<div className="mx_AppsDrawer"> <div className="mx_AppsDrawer">
<div id="apps" className="mx_AppsContainer"> <div id="apps" className="mx_AppsContainer">
{apps} { apps }
</div> </div>
{this._canUserModify() && addWidget} { this._canUserModify() && addWidget }
</div> </div>
); );
}, },

View file

@ -61,7 +61,7 @@ module.exports = React.createClass({
render: function() { render: function() {
return ( return (
<div className="mx_ForwardMessage"> <div className="mx_ForwardMessage">
<h1>{_t('Please select the destination room for this message')}</h1> <h1>{ _t('Please select the destination room for this message') }</h1>
</div> </div>
); );
}, },

View file

@ -372,7 +372,7 @@ module.exports = React.createClass({
}, },
_getChildrenInvited: function(start, end) { _getChildrenInvited: function(start, end) {
return this._makeMemberTiles(this.state.filteredInvitedMembers.slice(start, end)); return this._makeMemberTiles(this.state.filteredInvitedMembers.slice(start, end), 'invite');
}, },
_getChildCountInvited: function() { _getChildCountInvited: function() {

View file

@ -186,18 +186,18 @@ module.exports = React.createClass({
saveButton = ( saveButton = (
<AccessibleButton className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}> <AccessibleButton className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>
{_t("Save")} { _t("Save") }
</AccessibleButton> </AccessibleButton>
); );
} }
if (this.props.onCancelClick) { if (this.props.onCancelClick) {
cancelButton = <CancelButton onClick={this.props.onCancelClick}/>; cancelButton = <CancelButton onClick={this.props.onCancelClick} />;
} }
if (this.props.saving) { if (this.props.saving) {
const Spinner = sdk.getComponent("elements.Spinner"); const Spinner = sdk.getComponent("elements.Spinner");
spinner = <div className="mx_RoomHeader_spinner"><Spinner/></div>; spinner = <div className="mx_RoomHeader_spinner"><Spinner /></div>;
} }
if (canSetRoomName) { if (canSetRoomName) {
@ -254,7 +254,7 @@ module.exports = React.createClass({
} }
if (topic) { if (topic) {
topicElement = topicElement =
<div className="mx_RoomHeader_topic" ref="topic" title={ topic } dir="auto">{ topic }</div>; <div className="mx_RoomHeader_topic" ref="topic" title={topic} dir="auto">{ topic }</div>;
} }
} }
@ -262,16 +262,16 @@ module.exports = React.createClass({
if (canSetRoomAvatar) { if (canSetRoomAvatar) {
roomAvatar = ( roomAvatar = (
<div className="mx_RoomHeader_avatarPicker"> <div className="mx_RoomHeader_avatarPicker">
<div onClick={ this.onAvatarPickerClick }> <div onClick={this.onAvatarPickerClick}>
<ChangeAvatar ref="changeAvatar" room={this.props.room} showUploadSection={false} width={48} height={48} /> <ChangeAvatar ref="changeAvatar" room={this.props.room} showUploadSection={false} width={48} height={48} />
</div> </div>
<div className="mx_RoomHeader_avatarPicker_edit"> <div className="mx_RoomHeader_avatarPicker_edit">
<label htmlFor="avatarInput" ref="file_label"> <label htmlFor="avatarInput" ref="file_label">
<img src="img/camera.svg" <img src="img/camera.svg"
alt={ _t("Upload avatar") } title={ _t("Upload avatar") } alt={_t("Upload avatar")} title={_t("Upload avatar")}
width="17" height="15" /> width="17" height="15" />
</label> </label>
<input id="avatarInput" type="file" onChange={ this.onAvatarSelected }/> <input id="avatarInput" type="file" onChange={this.onAvatarSelected} />
</div> </div>
</div> </div>
); );
@ -286,7 +286,7 @@ module.exports = React.createClass({
if (this.props.onSettingsClick) { if (this.props.onSettingsClick) {
settingsButton = settingsButton =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSettingsClick} title={_t("Settings")}> <AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSettingsClick} title={_t("Settings")}>
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16"/> <TintableSvg src="img/icons-settings-room.svg" width="16" height="16" />
</AccessibleButton>; </AccessibleButton>;
} }
@ -301,24 +301,24 @@ module.exports = React.createClass({
let forgetButton; let forgetButton;
if (this.props.onForgetClick) { if (this.props.onForgetClick) {
forgetButton = forgetButton =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onForgetClick} title={ _t("Forget room") }> <AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onForgetClick} title={_t("Forget room")}>
<TintableSvg src="img/leave.svg" width="26" height="20"/> <TintableSvg src="img/leave.svg" width="26" height="20" />
</AccessibleButton>; </AccessibleButton>;
} }
let searchButton; let searchButton;
if (this.props.onSearchClick && this.props.inRoom) { if (this.props.onSearchClick && this.props.inRoom) {
searchButton = searchButton =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSearchClick} title={ _t("Search") }> <AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSearchClick} title={_t("Search")}>
<TintableSvg src="img/icons-search.svg" width="35" height="35"/> <TintableSvg src="img/icons-search.svg" width="35" height="35" />
</AccessibleButton>; </AccessibleButton>;
} }
let rightPanelButtons; let rightPanelButtons;
if (this.props.collapsedRhs) { if (this.props.collapsedRhs) {
rightPanelButtons = rightPanelButtons =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.onShowRhsClick} title={ _t('Show panel') }> <AccessibleButton className="mx_RoomHeader_button" onClick={this.onShowRhsClick} title={_t('Show panel')}>
<TintableSvg src="img/maximise.svg" width="10" height="16"/> <TintableSvg src="img/maximise.svg" width="10" height="16" />
</AccessibleButton>; </AccessibleButton>;
} }
@ -342,7 +342,7 @@ module.exports = React.createClass({
} }
return ( return (
<div className={ "mx_RoomHeader " + (this.props.editing ? "mx_RoomHeader_editing" : "") }> <div className={"mx_RoomHeader " + (this.props.editing ? "mx_RoomHeader_editing" : "")}>
<div className="mx_RoomHeader_wrapper"> <div className="mx_RoomHeader_wrapper">
<div className="mx_RoomHeader_leftRow"> <div className="mx_RoomHeader_leftRow">
<div className="mx_RoomHeader_avatar"> <div className="mx_RoomHeader_avatar">
@ -353,10 +353,10 @@ module.exports = React.createClass({
{ topicElement } { topicElement }
</div> </div>
</div> </div>
{spinner} { spinner }
{saveButton} { saveButton }
{cancelButton} { cancelButton }
{rightRow} { rightRow }
</div> </div>
</div> </div>
); );

View file

@ -26,7 +26,7 @@ export function CancelButton(props) {
return ( return (
<AccessibleButton className='mx_RoomHeader_cancelButton' onClick={onClick}> <AccessibleButton className='mx_RoomHeader_cancelButton' onClick={onClick}>
<img src="img/cancel.svg" className='mx_filterFlipColor' <img src="img/cancel.svg" className='mx_filterFlipColor'
width="18" height="18" alt={_t("Cancel")}/> width="18" height="18" alt={_t("Cancel")} />
</AccessibleButton> </AccessibleButton>
); );
} }

View file

@ -129,17 +129,17 @@ module.exports = React.createClass({
if (this.state.call && this.state.call.type === "voice" && this.props.showVoice) { if (this.state.call && this.state.call.type === "voice" && this.props.showVoice) {
const callRoom = MatrixClientPeg.get().getRoom(this.state.call.roomId); const callRoom = MatrixClientPeg.get().getRoom(this.state.call.roomId);
voice = ( voice = (
<div className="mx_CallView_voice" onClick={ this.props.onClick }> <div className="mx_CallView_voice" onClick={this.props.onClick}>
{_t("Active call (%(roomName)s)", {roomName: callRoom.name})} { _t("Active call (%(roomName)s)", {roomName: callRoom.name}) }
</div> </div>
); );
} }
return ( return (
<div> <div>
<VideoView ref="video" onClick={ this.props.onClick } <VideoView ref="video" onClick={this.props.onClick}
onResize={ this.props.onResize } onResize={this.props.onResize}
maxHeight={ this.props.maxVideoHeight } maxHeight={this.props.maxVideoHeight}
/> />
{ voice } { voice }
</div> </div>

View file

@ -62,17 +62,17 @@ module.exports = React.createClass({
<div className="mx_IncomingCallBox" id="incomingCallBox"> <div className="mx_IncomingCallBox" id="incomingCallBox">
<img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" /> <img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" />
<div className="mx_IncomingCallBox_title"> <div className="mx_IncomingCallBox_title">
{incomingCallText} { incomingCallText }
</div> </div>
<div className="mx_IncomingCallBox_buttons"> <div className="mx_IncomingCallBox_buttons">
<div className="mx_IncomingCallBox_buttons_cell"> <div className="mx_IncomingCallBox_buttons_cell">
<div className="mx_IncomingCallBox_buttons_decline" onClick={this.onRejectClick}> <div className="mx_IncomingCallBox_buttons_decline" onClick={this.onRejectClick}>
{_t("Decline")} { _t("Decline") }
</div> </div>
</div> </div>
<div className="mx_IncomingCallBox_buttons_cell"> <div className="mx_IncomingCallBox_buttons_cell">
<div className="mx_IncomingCallBox_buttons_accept" onClick={this.onAnswerClick}> <div className="mx_IncomingCallBox_buttons_accept" onClick={this.onAnswerClick}>
{_t("Accept")} { _t("Accept") }
</div> </div>
</div> </div>
</div> </div>

View file

@ -110,13 +110,13 @@ module.exports = React.createClass({
const maxVideoHeight = fullscreenElement ? null : this.props.maxHeight; const maxVideoHeight = fullscreenElement ? null : this.props.maxHeight;
return ( return (
<div className="mx_VideoView" ref={this.setContainer} onClick={ this.props.onClick }> <div className="mx_VideoView" ref={this.setContainer} onClick={this.props.onClick}>
<div className="mx_VideoView_remoteVideoFeed"> <div className="mx_VideoView_remoteVideoFeed">
<VideoFeed ref="remote" onResize={this.props.onResize} <VideoFeed ref="remote" onResize={this.props.onResize}
maxHeight={maxVideoHeight} /> maxHeight={maxVideoHeight} />
</div> </div>
<div className="mx_VideoView_localVideoFeed"> <div className="mx_VideoView_localVideoFeed">
<VideoFeed ref="local"/> <VideoFeed ref="local" />
</div> </div>
</div> </div>
); );

View file

@ -734,7 +734,6 @@
"WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WARNUNG: SCHLÜSSEL-VERIFIZIERUNG FEHLGESCHLAGEN! Der Signatur-Schlüssel für %(userId)s und das Gerät %(deviceId)s ist \"%(fprint)s\", welcher nicht mit dem bereitgestellten Schlüssel \"%(fingerprint)s\" übereinstimmt. Dies kann bedeuten, dass deine Kommunikation abgehört wird!", "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WARNUNG: SCHLÜSSEL-VERIFIZIERUNG FEHLGESCHLAGEN! Der Signatur-Schlüssel für %(userId)s und das Gerät %(deviceId)s ist \"%(fprint)s\", welcher nicht mit dem bereitgestellten Schlüssel \"%(fingerprint)s\" übereinstimmt. Dies kann bedeuten, dass deine Kommunikation abgehört wird!",
"You have <a>disabled</a> URL previews by default.": "Du hast die URL-Vorschau standardmäßig <a>deaktiviert</a>.", "You have <a>disabled</a> URL previews by default.": "Du hast die URL-Vorschau standardmäßig <a>deaktiviert</a>.",
"You have <a>enabled</a> URL previews by default.": "Du hast die URL-Vorschau standardmäßig <a>aktiviert</a>.", "You have <a>enabled</a> URL previews by default.": "Du hast die URL-Vorschau standardmäßig <a>aktiviert</a>.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Du hast einen ungültigen Kontakt eingegeben. Versuche es mit der Matrix-Kennung oder der E-Mail-Adresse des Kontakts.",
"$senderDisplayName changed the room avatar to <img/>": "$senderDisplayName hat das Raum-Bild geändert zu <img/>", "$senderDisplayName changed the room avatar to <img/>": "$senderDisplayName hat das Raum-Bild geändert zu <img/>",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s hat das Raum-Bild für %(roomName)s geändert", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s hat das Raum-Bild für %(roomName)s geändert",
"Hide removed messages": "Gelöschte Nachrichten verbergen", "Hide removed messages": "Gelöschte Nachrichten verbergen",

View file

@ -685,7 +685,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Έχετε αποσυνδεθεί από όλες τις συσκευές και δεν θα λαμβάνετε πλέον ειδοποιήσεις push. Για να ενεργοποιήσετε τις ειδοποιήσεις, συνδεθείτε ξανά σε κάθε συσκευή", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Έχετε αποσυνδεθεί από όλες τις συσκευές και δεν θα λαμβάνετε πλέον ειδοποιήσεις push. Για να ενεργοποιήσετε τις ειδοποιήσεις, συνδεθείτε ξανά σε κάθε συσκευή",
"You have <a>disabled</a> URL previews by default.": "Έχετε <a>απενεργοποιημένη</a> από προεπιλογή την προεπισκόπηση συνδέσμων.", "You have <a>disabled</a> URL previews by default.": "Έχετε <a>απενεργοποιημένη</a> από προεπιλογή την προεπισκόπηση συνδέσμων.",
"You have <a>enabled</a> URL previews by default.": "Έχετε <a>ενεργοποιημένη</a> από προεπιλογή την προεπισκόπηση συνδέσμων.", "You have <a>enabled</a> URL previews by default.": "Έχετε <a>ενεργοποιημένη</a> από προεπιλογή την προεπισκόπηση συνδέσμων.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Έχετε πληκτρολογήσει μια άκυρη επαφή. Χρησιμοποιήστε το Matrix ID ή την ηλεκτρονική διεύθυνση αλληλογραφίας τους.",
"You may wish to login with a different account, or add this email to this account.": "Μπορεί να θέλετε να συνδεθείτε με διαφορετικό λογαριασμό, ή να προσθέσετε αυτή τη διεύθυνση ηλεκτρονικής αλληλογραφίας σε αυτόν τον λογαριασμό.", "You may wish to login with a different account, or add this email to this account.": "Μπορεί να θέλετε να συνδεθείτε με διαφορετικό λογαριασμό, ή να προσθέσετε αυτή τη διεύθυνση ηλεκτρονικής αλληλογραφίας σε αυτόν τον λογαριασμό.",
"You need to be able to invite users to do that.": "Για να το κάνετε αυτό πρέπει να έχετε τη δυνατότητα να προσκαλέσετε χρήστες.", "You need to be able to invite users to do that.": "Για να το κάνετε αυτό πρέπει να έχετε τη δυνατότητα να προσκαλέσετε χρήστες.",
"You seem to be uploading files, are you sure you want to quit?": "Φαίνεται ότι αποστέλετε αρχεία, είστε βέβαιοι ότι θέλετε να αποχωρήσετε;", "You seem to be uploading files, are you sure you want to quit?": "Φαίνεται ότι αποστέλετε αρχεία, είστε βέβαιοι ότι θέλετε να αποχωρήσετε;",

View file

@ -554,7 +554,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device",
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.", "You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.", "You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "You have entered an invalid contact. Try using their Matrix ID or email address.",
"You have no visible notifications": "You have no visible notifications", "You have no visible notifications": "You have no visible notifications",
"You may wish to login with a different account, or add this email to this account.": "You may wish to login with a different account, or add this email to this account.", "You may wish to login with a different account, or add this email to this account.": "You may wish to login with a different account, or add this email to this account.",
"you must be a": "you must be a", "you must be a": "you must be a",
@ -894,5 +893,10 @@
"Unpublish": "Unpublish", "Unpublish": "Unpublish",
"This group is published on your profile": "This group is published on your profile", "This group is published on your profile": "This group is published on your profile",
"Publish": "Publish", "Publish": "Publish",
"This group is not published on your profile": "This group is not published on your profile" "This group is not published on your profile": "This group is not published on your profile",
"Matrix ID": "Matrix ID",
"Matrix Room ID": "Matrix Room ID",
"email address": "email address",
"Try using one of the following valid address types: %(validTypesList)s.": "Try using one of the following valid address types: %(validTypesList)s.",
"You have entered an invalid address.": "You have entered an invalid address."
} }

View file

@ -478,7 +478,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device",
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.", "You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.", "You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "You have entered an invalid contact. Try using their Matrix ID or email address.",
"You have no visible notifications": "You have no visible notifications", "You have no visible notifications": "You have no visible notifications",
"you must be a": "you must be a", "you must be a": "you must be a",
"You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.",

View file

@ -621,7 +621,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Ha sido desconectado de todos los dispositivos y no continuara recibiendo notificaciones. Para volver a habilitar las notificaciones, vuelva a conectarse en cada dispositivo", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Ha sido desconectado de todos los dispositivos y no continuara recibiendo notificaciones. Para volver a habilitar las notificaciones, vuelva a conectarse en cada dispositivo",
"You have <a>disabled</a> URL previews by default.": "Ha <a>deshabilitado</a> la vista previa de URL por defecto.", "You have <a>disabled</a> URL previews by default.": "Ha <a>deshabilitado</a> la vista previa de URL por defecto.",
"You have <a>enabled</a> URL previews by default.": "Ha <a>habilitado</a> vista previa de URL por defecto.", "You have <a>enabled</a> URL previews by default.": "Ha <a>habilitado</a> vista previa de URL por defecto.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Ha ingresado un contacto no valido. Intente usando la ID Matrix o e-mail del contacto.",
"You have no visible notifications": "No tiene notificaciones visibles", "You have no visible notifications": "No tiene notificaciones visibles",
"You may wish to login with a different account, or add this email to this account.": "Puede ingresar con una cuenta diferente, o agregar este e-mail a esta cuenta.", "You may wish to login with a different account, or add this email to this account.": "Puede ingresar con una cuenta diferente, o agregar este e-mail a esta cuenta.",
"you must be a": "usted debe ser un", "you must be a": "usted debe ser un",

View file

@ -555,7 +555,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Saioa amaitu duzu eta ez dituzu jakinarazpenak jasoko. Jakinarazpenak jaso nahi badituzu hasi saioa berriro gailu bakoitzean", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Saioa amaitu duzu eta ez dituzu jakinarazpenak jasoko. Jakinarazpenak jaso nahi badituzu hasi saioa berriro gailu bakoitzean",
"You have <a>disabled</a> URL previews by default.": "Lehenetsita URLak aurreikustea <a>desgaitu</a> duzu.", "You have <a>disabled</a> URL previews by default.": "Lehenetsita URLak aurreikustea <a>desgaitu</a> duzu.",
"You have <a>enabled</a> URL previews by default.": "Lehenetsita URLak aurreikustea <a>gaitu</a> duzu.", "You have <a>enabled</a> URL previews by default.": "Lehenetsita URLak aurreikustea <a>gaitu</a> duzu.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Kontaktu baliogabea sartu duzu. Saiatu bere Matrix ID-a edo e-mail helbidea erabiltzen.",
"You have no visible notifications": "Ez daukazu jakinarazpen ikusgairik", "You have no visible notifications": "Ez daukazu jakinarazpen ikusgairik",
"You may wish to login with a different account, or add this email to this account.": "Agian beste kontu batekin hasi nahi duzu saioa, edo e-mail hau kontu honetara gehitu.", "You may wish to login with a different account, or add this email to this account.": "Agian beste kontu batekin hasi nahi duzu saioa, edo e-mail hau kontu honetara gehitu.",
"you must be a": "hau izan behar duzu:", "you must be a": "hau izan behar duzu:",

View file

@ -679,7 +679,6 @@
"Tagged as: ": "Étiquetter comme : ", "Tagged as: ": "Étiquetter comme : ",
"You have <a>disabled</a> URL previews by default.": "Vous avez <a>désactivé</a> les aperçus dURL par défaut.", "You have <a>disabled</a> URL previews by default.": "Vous avez <a>désactivé</a> les aperçus dURL par défaut.",
"You have <a>enabled</a> URL previews by default.": "Vous avez <a>activé</a> les aperçus dURL par défaut.", "You have <a>enabled</a> URL previews by default.": "Vous avez <a>activé</a> les aperçus dURL par défaut.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Vous avez entré un contact invalide. Essayez dutiliser leur identifiant Matrix ou leur adresse email.",
"Hide removed messages": "Cacher les messages supprimés", "Hide removed messages": "Cacher les messages supprimés",
"Add": "Ajouter", "Add": "Ajouter",
"%(count)s new messages|one": "%(count)s nouveau message", "%(count)s new messages|one": "%(count)s nouveau message",

View file

@ -529,7 +529,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Kijelentkeztél minden eszközről így nem fogsz \"push\" értesítéseket kapni. Az értesítések engedélyezéséhez jelentkezz vissza mindegyik eszközön", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Kijelentkeztél minden eszközről így nem fogsz \"push\" értesítéseket kapni. Az értesítések engedélyezéséhez jelentkezz vissza mindegyik eszközön",
"You have <a>disabled</a> URL previews by default.": "Az URL előnézet alapból <a>tiltva</a> van.", "You have <a>disabled</a> URL previews by default.": "Az URL előnézet alapból <a>tiltva</a> van.",
"You have <a>enabled</a> URL previews by default.": "Az URL előnézet alapból <a>engedélyezve</a> van.", "You have <a>enabled</a> URL previews by default.": "Az URL előnézet alapból <a>engedélyezve</a> van.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Érvénytelen kapcsolatot adtál meg. Próbáld meg a Matrix azonosítóját vagy e-mail címét használni.",
"You have no visible notifications": "Nincsenek látható értesítéseid", "You have no visible notifications": "Nincsenek látható értesítéseid",
"You may wish to login with a different account, or add this email to this account.": "Lehet, hogy más fiókba szeretnél belépni vagy ezt az e-mail címet szeretnéd ehhez a fiókhoz kötni.", "You may wish to login with a different account, or add this email to this account.": "Lehet, hogy más fiókba szeretnél belépni vagy ezt az e-mail címet szeretnéd ehhez a fiókhoz kötni.",
"you must be a": "szükséges szerep:", "you must be a": "szükséges szerep:",

View file

@ -535,7 +535,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "모든 장치에서 로그아웃되었고 더 이상 알림을 받지 않으실 거에요. 다시 알림을 받으시려면, 각 장치에 로그인해주세요", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "모든 장치에서 로그아웃되었고 더 이상 알림을 받지 않으실 거에요. 다시 알림을 받으시려면, 각 장치에 로그인해주세요",
"You have <a>disabled</a> URL previews by default.": "URL 미리보기 <a>쓰지 않기</a>를 기본으로 하셨어요.", "You have <a>disabled</a> URL previews by default.": "URL 미리보기 <a>쓰지 않기</a>를 기본으로 하셨어요.",
"You have <a>enabled</a> URL previews by default.": "URL 미리보기 <a>쓰기</a>를 기본으로 하셨어요.", "You have <a>enabled</a> URL previews by default.": "URL 미리보기 <a>쓰기</a>를 기본으로 하셨어요.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "잘못된 연락처를 입력하셨어요. 매트릭스 ID나 이메일 주소를 써보세요.",
"You have no visible notifications": "보여드릴 알림이 없어요", "You have no visible notifications": "보여드릴 알림이 없어요",
"You may wish to login with a different account, or add this email to this account.": "다른 계정으로 로그인하거나, 이 이메일을 이 계정에 추가할 수도 있어요.", "You may wish to login with a different account, or add this email to this account.": "다른 계정으로 로그인하거나, 이 이메일을 이 계정에 추가할 수도 있어요.",
"you must be a": "해야해요", "you must be a": "해야해요",

View file

@ -593,7 +593,6 @@
"You cannot place VoIP calls in this browser.": "Tu nevari veikt VoIP zvanus šajā pārlūkā.", "You cannot place VoIP calls in this browser.": "Tu nevari veikt VoIP zvanus šajā pārlūkā.",
"You do not have permission to post to this room": "Tev nav vajadzīgās atļaujas pievienot ziņas šajā istabā", "You do not have permission to post to this room": "Tev nav vajadzīgās atļaujas pievienot ziņas šajā istabā",
"You have <a>disabled</a> URL previews by default.": "URL priekšskatījums pēc noklusējuma Tev ir <a>atspējots</a>.", "You have <a>disabled</a> URL previews by default.": "URL priekšskatījums pēc noklusējuma Tev ir <a>atspējots</a>.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Tu ievadīji nepareizu kontaktu. Mēģini izmantot viņa Matrix ID vai epasta adresi.",
"You may wish to login with a different account, or add this email to this account.": "Tu varētu, iespējams, vēlēties pierakstīties no cita konta vai piesaistīt šo epastu šim kontam.", "You may wish to login with a different account, or add this email to this account.": "Tu varētu, iespējams, vēlēties pierakstīties no cita konta vai piesaistīt šo epastu šim kontam.",
"you must be a": "Tev ir jābūt", "you must be a": "Tev ir jābūt",
"You must <a>register</a> to use this functionality": "Lai izmantotu šo funkcionalitāti, Tev ir <a>jāreģistrējas</a>", "You must <a>register</a> to use this functionality": "Lai izmantotu šo funkcionalitāti, Tev ir <a>jāreģistrējas</a>",

View file

@ -560,7 +560,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Je bent op alle apparaten uitgelegd en je zal niet langer notificaties ontvangen. Om notificaties weer aan te zetten, log op elk apparaat opnieuw in", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Je bent op alle apparaten uitgelegd en je zal niet langer notificaties ontvangen. Om notificaties weer aan te zetten, log op elk apparaat opnieuw in",
"You have <a>disabled</a> URL previews by default.": "Je hebt URL-voorvertoningen standaard <a>uitgezet</a>.", "You have <a>disabled</a> URL previews by default.": "Je hebt URL-voorvertoningen standaard <a>uitgezet</a>.",
"You have <a>enabled</a> URL previews by default.": "Je hebt URL-voorvertoningen standaard <a>aangezet</a>.", "You have <a>enabled</a> URL previews by default.": "Je hebt URL-voorvertoningen standaard <a>aangezet</a>.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Je hebt een ongeldig contact ingevoerd. Probeer zijn of haar Matrix-ID of e-mailadres te gebruiken.",
"You have no visible notifications": "Je hebt geen zichtbare notificaties", "You have no visible notifications": "Je hebt geen zichtbare notificaties",
"You may wish to login with a different account, or add this email to this account.": "Je wilt misschien met een ander account inloggen of deze e-mail aan je account toevoegen.", "You may wish to login with a different account, or add this email to this account.": "Je wilt misschien met een ander account inloggen of deze e-mail aan je account toevoegen.",
"you must be a": "wat je moet zijn is een", "you must be a": "wat je moet zijn is een",

View file

@ -603,7 +603,6 @@
"You have been kicked from %(roomName)s by %(userName)s.": "Zostałeś usunięty z %(roomName)s przez %(userName)s.", "You have been kicked from %(roomName)s by %(userName)s.": "Zostałeś usunięty z %(roomName)s przez %(userName)s.",
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Wylogowałeś się ze wszystkich urządzeń i nie będziesz już otrzymywał powiadomień push. Aby ponownie aktywować powiadomienia zaloguj się ponownie na każdym urządzeniu", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Wylogowałeś się ze wszystkich urządzeń i nie będziesz już otrzymywał powiadomień push. Aby ponownie aktywować powiadomienia zaloguj się ponownie na każdym urządzeniu",
"You have <a>disabled</a> URL previews by default.": "Masz domyślnie <a>wyłączone</a> podglądy linków.", "You have <a>disabled</a> URL previews by default.": "Masz domyślnie <a>wyłączone</a> podglądy linków.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Wpisałeś niewłaściwy kontakt. Spróbuj używając Matrix ID lub adresu e-mail.",
"You have no visible notifications": "Nie masz widocznych powiadomień", "You have no visible notifications": "Nie masz widocznych powiadomień",
"You may wish to login with a different account, or add this email to this account.": "Możesz chcieć zalogować się z innego konta lub dodać e-mail do tego konta.", "You may wish to login with a different account, or add this email to this account.": "Możesz chcieć zalogować się z innego konta lub dodać e-mail do tego konta.",
"you must be a": "musisz być", "you must be a": "musisz być",

View file

@ -733,7 +733,6 @@
"Tagged as: ": "Marcado como: ", "Tagged as: ": "Marcado como: ",
"You have <a>disabled</a> URL previews by default.": "Você <a>desabilitou</a> pré-visualizações de links por padrão.", "You have <a>disabled</a> URL previews by default.": "Você <a>desabilitou</a> pré-visualizações de links por padrão.",
"You have <a>enabled</a> URL previews by default.": "Você <a>habilitou</a> pré-visualizações de links por padrão.", "You have <a>enabled</a> URL previews by default.": "Você <a>habilitou</a> pré-visualizações de links por padrão.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Você inseriu um contato inválido. Tente usar o ID Matrix ou endereço de e-mail da pessoa que está buscando.",
"You have been banned from %(roomName)s by %(userName)s.": "Você foi expulso(a) da sala %(roomName)s por %(userName)s.", "You have been banned from %(roomName)s by %(userName)s.": "Você foi expulso(a) da sala %(roomName)s por %(userName)s.",
"Send anyway": "Enviar de qualquer maneira", "Send anyway": "Enviar de qualquer maneira",
"This room": "Esta sala", "This room": "Esta sala",

View file

@ -730,7 +730,6 @@
"Tagged as: ": "Marcado como: ", "Tagged as: ": "Marcado como: ",
"You have <a>disabled</a> URL previews by default.": "Você <a>desabilitou</a> pré-visualizações de links por padrão.", "You have <a>disabled</a> URL previews by default.": "Você <a>desabilitou</a> pré-visualizações de links por padrão.",
"You have <a>enabled</a> URL previews by default.": "Você <a>habilitou</a> pré-visualizações de links por padrão.", "You have <a>enabled</a> URL previews by default.": "Você <a>habilitou</a> pré-visualizações de links por padrão.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Você inseriu um contato inválido. Tente usar o ID Matrix ou endereço de e-mail da pessoa que está buscando.",
"Hide removed messages": "Ocultar mensagens removidas", "Hide removed messages": "Ocultar mensagens removidas",
"Add": "Adicionar", "Add": "Adicionar",
"%(count)s new messages|one": "%(count)s nova mensagem", "%(count)s new messages|one": "%(count)s nova mensagem",

View file

@ -618,7 +618,6 @@
"WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "ВНИМАНИЕ: ОШИБКА ПРОВЕРКИ КЛЮЧЕЙ! Ключ подписи пользователя %(userId)s на устройстве %(deviceId)s — \"%(fprint)s\", и он не соответствует предоставленному ключу \"%(fingerprint)s\". Это может означать, что ваше общение перехватывается!", "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "ВНИМАНИЕ: ОШИБКА ПРОВЕРКИ КЛЮЧЕЙ! Ключ подписи пользователя %(userId)s на устройстве %(deviceId)s — \"%(fprint)s\", и он не соответствует предоставленному ключу \"%(fingerprint)s\". Это может означать, что ваше общение перехватывается!",
"You have <a>disabled</a> URL previews by default.": "Предварительный просмотр ссылок <a>отключен</a> по-умолчанию.", "You have <a>disabled</a> URL previews by default.": "Предварительный просмотр ссылок <a>отключен</a> по-умолчанию.",
"You have <a>enabled</a> URL previews by default.": "Предварительный просмотр ссылок <a>включен</a> по-умолчанию.", "You have <a>enabled</a> URL previews by default.": "Предварительный просмотр ссылок <a>включен</a> по-умолчанию.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Вы ввели недопустимый контакт. Попробуйте использовать Matrix ID или адрес электронной почты.",
"You need to enter a user name.": "Необходимо ввести имя пользователя.", "You need to enter a user name.": "Необходимо ввести имя пользователя.",
"You seem to be in a call, are you sure you want to quit?": "Звонок не завершен, вы уверены, что хотите выйти?", "You seem to be in a call, are you sure you want to quit?": "Звонок не завершен, вы уверены, что хотите выйти?",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Вы не сможете отменить это изменение, так как этот пользователь получит уровень доступа, аналогичный вашему.", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Вы не сможете отменить это изменение, так как этот пользователь получит уровень доступа, аналогичный вашему.",

View file

@ -516,7 +516,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Tüm cihazlardan çıkış yaptınız ve artık bildirimler almayacaksınız . Bildirimleri yeniden etkinleştirmek için , her cihazda tekrar giriş yapın", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Tüm cihazlardan çıkış yaptınız ve artık bildirimler almayacaksınız . Bildirimleri yeniden etkinleştirmek için , her cihazda tekrar giriş yapın",
"You have <a>disabled</a> URL previews by default.": "URL önizlemelerini varsayılan olarak <a> devre dışı </a> bıraktınız.", "You have <a>disabled</a> URL previews by default.": "URL önizlemelerini varsayılan olarak <a> devre dışı </a> bıraktınız.",
"You have <a>enabled</a> URL previews by default.": "URL önizlemelerini varsayılan olarak <a> etkinleştirdiniz </a> .", "You have <a>enabled</a> URL previews by default.": "URL önizlemelerini varsayılan olarak <a> etkinleştirdiniz </a> .",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "Geçersiz bir kişi girdiniz . Matrix ID veya e-posta adresini kullanarak tekrar deneyin.",
"You have no visible notifications": "Hiçbir görünür bildiriminiz yok", "You have no visible notifications": "Hiçbir görünür bildiriminiz yok",
"You may wish to login with a different account, or add this email to this account.": "Farklı bir hesap ile giriş yapmak veya bu e-postayı bu hesaba eklemek istemiş olabilirsiniz.", "You may wish to login with a different account, or add this email to this account.": "Farklı bir hesap ile giriş yapmak veya bu e-postayı bu hesaba eklemek istemiş olabilirsiniz.",
"you must be a": "olabilirsiniz", "you must be a": "olabilirsiniz",

View file

@ -630,7 +630,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "你已经登出了所有的设备并不再接收推送通知。要重新启用通知,请再在每个设备上登录", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "你已经登出了所有的设备并不再接收推送通知。要重新启用通知,请再在每个设备上登录",
"You have <a>disabled</a> URL previews by default.": "你已经默认 <a>禁用</a> URL 预览。", "You have <a>disabled</a> URL previews by default.": "你已经默认 <a>禁用</a> URL 预览。",
"You have <a>enabled</a> URL previews by default.": "你已经默认 <a>启用</a> URL 预览。", "You have <a>enabled</a> URL previews by default.": "你已经默认 <a>启用</a> URL 预览。",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "你输入了一个非法的联系人。尝试使用他们的 Matrix ID 或者电子邮件地址。",
"Your home server does not support device management.": "你的 home server 不支持设备管理。", "Your home server does not support device management.": "你的 home server 不支持设备管理。",
"Set a display name:": "设置一个昵称:", "Set a display name:": "设置一个昵称:",
"This server does not support authentication with a phone number.": "这个服务器不支持用电话号码认证。", "This server does not support authentication with a phone number.": "这个服务器不支持用电话号码认证。",

View file

@ -574,7 +574,6 @@
"You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "您已在所有裝置上登出,並且不會再收到推送通知。要重新啟用通知,再次於每個裝置上登入", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "您已在所有裝置上登出,並且不會再收到推送通知。要重新啟用通知,再次於每個裝置上登入",
"You have <a>disabled</a> URL previews by default.": "您已預設<a>停用</a> URL 預覽。", "You have <a>disabled</a> URL previews by default.": "您已預設<a>停用</a> URL 預覽。",
"You have <a>enabled</a> URL previews by default.": "您已預設<a>啟用</a> URL 預覽。", "You have <a>enabled</a> URL previews by default.": "您已預設<a>啟用</a> URL 預覽。",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "您輸入了無效的聯絡人。嘗試使用他們的 Matrix ID 或電子郵件地址。",
"You have no visible notifications": "您沒有可見的通知", "You have no visible notifications": "您沒有可見的通知",
"You may wish to login with a different account, or add this email to this account.": "您可能會想要以不同的帳號登入,或是把這個電子郵件加入到此帳號中。", "You may wish to login with a different account, or add this email to this account.": "您可能會想要以不同的帳號登入,或是把這個電子郵件加入到此帳號中。",
"you must be a": "您一定是", "you must be a": "您一定是",