Merge branch 'develop' of github.com:vector-im/riot-web into t3chguy/devtools-118247

pull/5718/head
Michael Telatynski 2018-01-25 20:59:31 +00:00
commit 04bca93e0d
No known key found for this signature in database
GPG Key ID: 3F879DA5AD802A5E
84 changed files with 670 additions and 465 deletions

View File

@ -1,3 +1,5 @@
<!-- Please report security issues by email to security@matrix.org -->
<!-- This is a bug report template. By following the instructions below and
filling out the sections with your information, you will help the us to get all
the necessary data to fix your issue.

View File

@ -3,7 +3,10 @@ dist: trusty
# we don't need sudo, so can run in a container, which makes startup much
# quicker.
sudo: false
#
# unfortunately we do temporarily require sudo as a workaround for
# https://github.com/travis-ci/travis-ci/issues/8836
sudo: required
language: node_js
node_js:

View File

@ -13,3 +13,6 @@ include:
* Michael Telatynski (https://github.com/t3chguy)
Improved consistency of inverted elements in dark theme across browsers
* Alexandr Korsak (https://github.com/oivoodoo)
Improved multiple file uploading

View File

@ -1,3 +1,17 @@
Changes in [0.13.4](https://github.com/vector-im/riot-web/releases/tag/v0.13.4) (2018-01-03)
============================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.3...v0.13.4)
* Change config of riot.im electron build to fix some widgets not working. This only affects
electron builds using the riot.im config - for all other builds, this is identical to
v0.13.3.
Changes in [0.13.3](https://github.com/vector-im/riot-web/releases/tag/v0.13.3) (2017-12-04)
============================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.2...v0.13.3)
* Bump js-sdk, react-sdk version to pull in fix for [setting room publicity in a group](https://github.com/matrix-org/matrix-js-sdk/commit/aa3201ebb0fff5af2fb733080aa65ed1f7213de6).
Changes in [0.13.2](https://github.com/vector-im/riot-web/releases/tag/v0.13.2) (2017-11-28)
============================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.1...v0.13.2)

View File

@ -128,8 +128,13 @@ You can configure the app by copying `config.sample.json` to
1. `cross_origin_renderer_url`: URL to a static HTML page hosting code to help display
encrypted file attachments. This MUST be hosted on a completely separate domain to
anything else since it is used to isolate the privileges of file attachments to this
domain. Default: `usercontent.riot.im`. This needs to contain v1.html from
domain. Default: `https://usercontent.riot.im/v1.html`. This needs to contain v1.html from
https://github.com/matrix-org/usercontent/blob/master/v1.html
1. `piwik`: an object containing the following properties:
1. `url`: The URL of the Piwik instance to use for collecting Analytics
1. `whitelistedHSUrls`: a list of HS URLs to not redact from the Analytics
1. `whitelistedISUrls`: a list of IS URLs to not redact from the Analytics
1. `siteId`: The Piwik Site ID to use when sending Analytics to the Piwik server configured above
Running as a Desktop app
========================
@ -314,31 +319,51 @@ For a developer guide, see the [translating dev doc](docs/translating-dev.md).
Triaging issues
===============
Issues will be triaged by the core team using the following primary set of tags:
Issues will be triaged by the core team using the below set of tags.
priority:
Tags are meant to be used in combination - e.g.:
* P1 critical bug == really urgent stuff that should be next in the bugfixing todo list
* "release blocker" == stuff which is blocking us from cutting the next release.
* P1 feature type:voip == what VoIP features should we be working on next?
* P1: top priority; typically blocks releases
priority: **compulsory**
* P1: top priority - i.e. pool of stuff which we should be working on next
* P2: still need to fix, but lower than P1
* P3: non-urgent
* P4: intereseting idea - bluesky some day
* P4: interesting idea - bluesky some day
* P5: recorded for posterity/to avoid duplicates. No intention to resolves right now.
bug or feature:
bug or feature: **compulsory**
* bug
* feature
bug severity:
bug severity: **compulsory, if bug**
* cosmetic - feature works functionally but UI/UX is broken
* critical - whole app doesn't work
* major - entire feature doesn't work
* minor - partially broken feature (but still usable)
* cosmetic - feature works functionally but UI/UX is broken
additional categories:
types
* type:* - refers to a particular part of the app; used to filter bugs
on a given topic - e.g. VOIP, signup, timeline, etc.
additional categories (self-explanatory):
* release blocker
* ui/ux (think of this as cosmetic)
* network (specific to network conditions)
* platform (platform specific)
* platform specific
* accessibility
* maintenance
* performance
* i18n
* blocked - whether this issue currently can't be progressed due to outside factors
community engagement
* easy
* hacktoberfest
* bounty? - proposal to be included in a bounty programme
* bounty - included in Status Open Bounty

View File

@ -24,6 +24,8 @@
"welcomeUserId": "@riot-bot:matrix.org",
"piwik": {
"url": "https://piwik.riot.im/",
"whitelistedHSUrls": ["https://matrix.org"],
"whitelistedISUrls": ["https://vector.im", "https://matrix.org"],
"siteId": 1
}
}

View File

@ -2,7 +2,7 @@
"name": "riot-web",
"productName": "Riot",
"main": "src/electron-main.js",
"version": "0.13.2",
"version": "0.13.4",
"description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.",
"dependencies": {

View File

@ -5,6 +5,10 @@
"brand": "Riot",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
"integrations_widgets_urls": [
"https://scalar-staging.riot.im/scalar/api",
"https://scalar.vector.im/api"
],
"bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"welcomeUserId": "@riot-bot:matrix.org",
"roomDirectory": {

View File

@ -2,9 +2,9 @@
"name": "riot-web",
"productName": "Riot",
"main": "electron_app/src/electron-main.js",
"version": "0.13.2",
"version": "0.13.4",
"description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.",
"author": "New Vector Ltd.",
"repository": {
"type": "git",
"url": "https://github.com/vector-im/riot-web"
@ -68,14 +68,13 @@
"gfm.css": "^1.1.1",
"highlight.js": "^9.0.0",
"linkifyjs": "^2.1.3",
"matrix-js-sdk": "0.9.1",
"matrix-react-sdk": "0.11.2",
"matrix-js-sdk": "0.9.2",
"matrix-react-sdk": "0.11.3",
"modernizr": "^3.1.0",
"pako": "^1.0.5",
"prop-types": "^15.5.10",
"react": "^15.6.0",
"react-dnd": "^2.1.4",
"react-dnd-html5-backend": "^2.1.2",
"react-beautiful-dnd": "^4.0.1",
"react-dom": "^15.6.0",
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
"sanitize-html": "^1.11.1",

View File

@ -16,7 +16,7 @@ const INCLUDE_LANGS = [
{'value': 'el', 'label': 'Ελληνικά'},
{'value': 'eo', 'label': 'Esperanto'},
{'value': 'es', 'label': 'Español'},
{'value': 'eu', 'label': 'Euskal'},
{'value': 'eu', 'label': 'Euskara'},
{'value': 'fi', 'label': 'Suomi'},
{'value': 'fr', 'label': 'Français'},
{'value': 'hu', 'label': 'Magyar'},

View File

@ -17,10 +17,8 @@ limitations under the License.
'use strict';
import React from 'react';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import classNames from 'classnames';
import KeyCode from 'matrix-react-sdk/lib/KeyCode';
import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
import sdk from 'matrix-react-sdk';
import dis from 'matrix-react-sdk/lib/dispatcher';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
@ -199,4 +197,4 @@ var LeftPanel = React.createClass({
}
});
module.exports = DragDropContext(HTML5Backend)(LeftPanel);
module.exports = LeftPanel;

View File

@ -24,7 +24,7 @@ import sdk from 'matrix-react-sdk';
import dis from 'matrix-react-sdk/lib/dispatcher';
import { MatrixClient } from 'matrix-js-sdk';
import Analytics from 'matrix-react-sdk/lib/Analytics';
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
import RateLimitedFunc from 'matrix-react-sdk/lib/ratelimitedfunc';
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
import { showGroupInviteDialog, showGroupAddRoomDialog } from 'matrix-react-sdk/lib/GroupAddressPicker';
import GroupStoreCache from 'matrix-react-sdk/lib/stores/GroupStoreCache';
@ -58,8 +58,8 @@ class HeaderButton extends React.Component {
<div className="mx_RightPanel_headerButton_badge">
{ this.props.badge ? this.props.badge : <span>&nbsp;</span> }
</div>
<TintableSvg src={this.props.iconSrc} width="25" height="25"/>
{ this.props.isHighlighted ? <div className="mx_RightPanel_headerButton_highlight"></div> : <div/> }
<TintableSvg src={this.props.iconSrc} width="25" height="25" />
{ this.props.isHighlighted ? <div className="mx_RightPanel_headerButton_highlight" /> : <div /> }
</AccessibleButton>;
}
@ -184,18 +184,17 @@ module.exports = React.createClass({
onRoomStateMember: function(ev, state, member) {
// redraw the badge on the membership list
if (this.state.phase == this.Phase.RoomMemberList && member.roomId === this.props.roomId) {
if (this.state.phase === this.Phase.RoomMemberList && member.roomId === this.props.roomId) {
this._delayedUpdate();
}
else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId &&
} else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId &&
member.userId === this.state.member.userId) {
// refresh the member info (e.g. new power level)
this._delayedUpdate();
}
},
_delayedUpdate: new rate_limited_func(function() {
this.forceUpdate();
_delayedUpdate: new RateLimitedFunc(function() {
this.forceUpdate(); // eslint-disable-line babel/no-invalid-this
}, 500),
onAction: function(payload) {
@ -266,22 +265,23 @@ module.exports = React.createClass({
let inviteGroup;
let membersBadge;
if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo)
let membersTitle = _t('Members');
if ((this.state.phase === this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo)
&& this.props.roomId
) {
const cli = this.context.matrixClient;
const room = cli.getRoom(this.props.roomId);
let userIsInRoom;
let isUserInRoom;
if (room) {
membersBadge = formatCount(room.getJoinedMembers().length);
userIsInRoom = room.hasMembershipState(
this.context.matrixClient.credentials.userId, 'join',
);
const numMembers = room.getJoinedMembers().length;
membersTitle = _t('%(count)s Members', { count: numMembers });
membersBadge = <div title={membersTitle}>{ formatCount(numMembers) }</div>;
isUserInRoom = room.hasMembershipState(this.context.matrixClient.credentials.userId, 'join');
}
if (userIsInRoom) {
if (isUserInRoom) {
inviteGroup =
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } >
<AccessibleButton className="mx_RightPanel_invite" onClick={this.onInviteButtonClick}>
<div className="mx_RightPanel_icon" >
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
</div>
@ -292,13 +292,13 @@ module.exports = React.createClass({
const isPhaseGroup = [
this.Phase.GroupMemberInfo,
this.Phase.GroupMemberList
this.Phase.GroupMemberList,
].includes(this.state.phase);
let headerButtons = [];
if (this.props.roomId) {
headerButtons = [
<HeaderButton key="_membersButton" title={_t('Members')} iconSrc="img/icons-people.svg"
<HeaderButton key="_membersButton" title={membersTitle} iconSrc="img/icons-people.svg"
isHighlighted={[this.Phase.RoomMemberList, this.Phase.RoomMemberInfo].includes(this.state.phase)}
clickPhase={this.Phase.RoomMemberList}
badge={membersBadge}
@ -336,54 +336,54 @@ module.exports = React.createClass({
// button on these 2 screens or you won't be able to re-expand the panel.
headerButtons.push(
<div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" key="_minimizeButton"
title={ _t("Hide panel") } aria-label={ _t("Hide panel") } onClick={ this.onCollapseClick }
title={_t("Hide panel")} aria-label={_t("Hide panel")} onClick={this.onCollapseClick}
>
<TintableSvg src="img/minimise.svg" width="10" height="16"/>
<TintableSvg src="img/minimise.svg" width="10" height="16" />
</div>,
);
}
let panel = <div />;
if (!this.props.collapsed) {
if (this.props.roomId && this.state.phase == this.Phase.RoomMemberList) {
if (this.props.roomId && this.state.phase === this.Phase.RoomMemberList) {
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />;
} else if (this.props.groupId && this.state.phase == this.Phase.GroupMemberList) {
} else if (this.props.groupId && this.state.phase === this.Phase.GroupMemberList) {
panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase === this.Phase.GroupRoomList) {
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase == this.Phase.RoomMemberInfo) {
} else if (this.state.phase === this.Phase.RoomMemberInfo) {
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
} else if (this.state.phase == this.Phase.GroupMemberInfo) {
} else if (this.state.phase === this.Phase.GroupMemberInfo) {
panel = <GroupMemberInfo
groupMember={this.state.member}
groupId={this.props.groupId}
key={this.state.member.user_id} />;
} else if (this.state.phase == this.Phase.GroupRoomInfo) {
} else if (this.state.phase === this.Phase.GroupRoomInfo) {
panel = <GroupRoomInfo
groupRoomId={this.state.groupRoomId}
groupId={this.props.groupId}
key={this.state.groupRoomId} />;
} else if (this.state.phase == this.Phase.NotificationPanel) {
} else if (this.state.phase === this.Phase.NotificationPanel) {
panel = <NotificationPanel />;
} else if (this.state.phase == this.Phase.FilePanel) {
} else if (this.state.phase === this.Phase.FilePanel) {
panel = <FilePanel roomId={this.props.roomId} />;
}
}
if (!panel) {
panel = <div className="mx_RightPanel_blank"></div>;
panel = <div className="mx_RightPanel_blank" />;
}
if (this.props.groupId && this.state.isUserPrivilegedInGroup) {
inviteGroup = isPhaseGroup ? (
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } >
<AccessibleButton className="mx_RightPanel_invite" onClick={this.onInviteButtonClick}>
<div className="mx_RightPanel_icon" >
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
</div>
<div className="mx_RightPanel_message">{ _t('Invite to this community') }</div>
</AccessibleButton>
) : (
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } >
<AccessibleButton className="mx_RightPanel_invite" onClick={this.onInviteButtonClick}>
<div className="mx_RightPanel_icon" >
<TintableSvg src="img/icons-room-add.svg" width="35" height="35" />
</div>
@ -392,19 +392,16 @@ module.exports = React.createClass({
);
}
let classes = classNames(
"mx_RightPanel", "mx_fadable",
{
"collapsed": this.props.collapsed,
"mx_fadable_faded": this.props.disabled,
}
);
const classes = classNames("mx_RightPanel", "mx_fadable", {
"collapsed": this.props.collapsed,
"mx_fadable_faded": this.props.disabled,
});
return (
<aside className={classes}>
<div className="mx_RightPanel_header">
<div className="mx_RightPanel_headerButtonGroup">
{headerButtons}
{ headerButtons }
</div>
</div>
{ panel }

View File

@ -20,8 +20,8 @@ limitations under the License.
var React = require('react');
var ReactDOM = require('react-dom');
var classNames = require('classnames');
var DropTarget = require('react-dnd').DropTarget;
var sdk = require('matrix-react-sdk');
import { Droppable } from 'react-beautiful-dnd';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
var dis = require('matrix-react-sdk/lib/dispatcher');
var Unread = require('matrix-react-sdk/lib/Unread');
@ -30,7 +30,8 @@ var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
import Modal from 'matrix-react-sdk/lib/Modal';
import KeyCode from 'matrix-react-sdk/lib/KeyCode';
import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
// turn this on for drop & drag console debugging galore
var debug = false;
@ -326,44 +327,45 @@ var RoomSubList = React.createClass({
});
},
calcManualOrderTagData: function(room) {
var index = this.state.sortedList.indexOf(room);
calcManualOrderTagData: function(index) {
// we sort rooms by the lexicographic ordering of the 'order' metadata on their tags.
// for convenience, we calculate this for now a floating point number between 0.0 and 1.0.
var orderA = 0.0; // by default we're next to the beginning of the list
let orderA = 0.0; // by default we're next to the beginning of the list
if (index > 0) {
var prevTag = this.state.sortedList[index - 1].tags[this.props.tagName];
const prevTag = this.state.sortedList[index - 1].tags[this.props.tagName];
if (!prevTag) {
console.error("Previous room in sublist is not tagged to be in this list. This should never happen.")
}
else if (prevTag.order === undefined) {
console.error("Previous room in sublist is not tagged to be in this list. This should never happen.");
} else if (prevTag.order === undefined) {
console.error("Previous room in sublist has no ordering metadata. This should never happen.");
}
else {
} else {
orderA = prevTag.order;
}
}
var orderB = 1.0; // by default we're next to the end of the list too
let orderB = 1.0; // by default we're next to the end of the list too
if (index < this.state.sortedList.length - 1) {
var nextTag = this.state.sortedList[index + 1].tags[this.props.tagName];
const nextTag = this.state.sortedList[index + 1].tags[this.props.tagName];
if (!nextTag) {
console.error("Next room in sublist is not tagged to be in this list. This should never happen.")
}
else if (nextTag.order === undefined) {
console.error("Next room in sublist is not tagged to be in this list. This should never happen.");
} else if (nextTag.order === undefined) {
console.error("Next room in sublist has no ordering metadata. This should never happen.");
}
else {
} else {
orderB = nextTag.order;
}
}
var order = (orderA + orderB) / 2.0;
const order = (orderA + orderB) / 2.0;
if (order === orderA || order === orderB) {
console.error("Cannot describe new list position. This should be incredibly unlikely.");
// TODO: renumber the list
this.state.sortedList.forEach((room, index) => {
MatrixClientPeg.get().setRoomTag(
room.roomId, this.props.tagName,
{order: index / this.state.sortedList.length},
);
});
return index / this.state.sortedList.length;
}
return order;
@ -372,12 +374,14 @@ var RoomSubList = React.createClass({
makeRoomTiles: function() {
var self = this;
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
return this.state.sortedList.map(function(room) {
return this.state.sortedList.map(function(room, index) {
// XXX: is it evil to pass in self as a prop to RoomTile?
return (
<DNDRoomTile
index={index} // For DND
room={ room }
roomSubList={ self }
tagName={self.props.tagName}
key={ room.roomId }
collapsed={ self.props.collapsed || false}
unread={ Unread.doesRoomHaveUnreadMessages(room) }
@ -563,12 +567,18 @@ var RoomSubList = React.createClass({
</TruncatedList>;
}
return connectDropTarget(
<div>
{ this._getHeaderJsx() }
{ subList }
</div>
);
const subListContent = <div>
{ this._getHeaderJsx() }
{ subList }
</div>;
return this.props.editable ? <Droppable droppableId={"room-sub-list-droppable_" + this.props.tagName}>
{ (provided, snapshot) => (
<div ref={provided.innerRef}>
{ subListContent }
</div>
) }
</Droppable> : subListContent;
}
else {
var Loader = sdk.getComponent("elements.Spinner");
@ -582,11 +592,4 @@ var RoomSubList = React.createClass({
}
});
// Export the wrapped version, inlining the 'collect' functions
// to more closely resemble the ES7
module.exports =
DropTarget('RoomTile', roomListTarget, function(connect) {
return {
connectDropTarget: connect.dropTarget(),
}
})(RoomSubList);
module.exports = RoomSubList;

View File

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import KeyCode from 'matrix-react-sdk/lib/KeyCode';
import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
import sdk from 'matrix-react-sdk';
import dis from 'matrix-react-sdk/lib/dispatcher';
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';

View File

@ -16,14 +16,17 @@ limitations under the License.
'use strict';
var React = require('react');
import React from 'react';
import PropTypes from 'prop-types';
import SyntaxHighlight from '../views/elements/SyntaxHighlight';
module.exports = React.createClass({
displayName: 'ViewSource',
propTypes: {
content: React.PropTypes.object.isRequired,
onFinished: React.PropTypes.func.isRequired,
content: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired,
},
componentDidMount: function() {
@ -45,9 +48,9 @@ module.exports = React.createClass({
render: function() {
return (
<div className="mx_ViewSource">
<pre>
{JSON.stringify(this.props.content, null, 2)}
</pre>
<SyntaxHighlight className="json">
{ JSON.stringify(this.props.content, null, 2) }
</SyntaxHighlight>
</div>
);
}

View File

@ -16,15 +16,16 @@ limitations under the License.
'use strict';
const React = require('react');
import React from 'react';
const MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
const dis = require('matrix-react-sdk/lib/dispatcher');
const sdk = require('matrix-react-sdk');
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import dis from 'matrix-react-sdk/lib/dispatcher';
import sdk from 'matrix-react-sdk';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
const Modal = require('matrix-react-sdk/lib/Modal');
const Resend = require("matrix-react-sdk/lib/Resend");
import Modal from 'matrix-react-sdk/lib/Modal';
import Resend from "matrix-react-sdk/lib/Resend";
import SettingsStore from "matrix-react-sdk/lib/settings/SettingsStore";
import {makeEventPermalink} from 'matrix-react-sdk/lib/matrix-to';
module.exports = React.createClass({
displayName: 'MessageContextMenu',
@ -107,15 +108,14 @@ module.exports = React.createClass({
onFinished: (proceed) => {
if (!proceed) return;
MatrixClientPeg.get().redactEvent(
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()
).catch(function(e) {
const cli = MatrixClientPeg.get();
cli.redactEvent(this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()).catch(function(e) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// display error message stating you couldn't delete this.
const code = e.errcode || e.statusCode;
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
title: _t('Error'),
description: _t('You cannot delete this message. (%(code)s)', {code: code})
description: _t('You cannot delete this message. (%(code)s)', {code}),
});
}).done();
},
@ -138,12 +138,12 @@ module.exports = React.createClass({
onPinClick: function() {
MatrixClientPeg.get().getStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', '')
.catch(e => {
.catch((e) => {
// Intercept the Event Not Found error and fall through the promise chain with no event.
if (e.errcode === "M_NOT_FOUND") return null;
throw e;
})
.then(event => {
.then((event) => {
const eventIds = (event ? event.pinned : []) || [];
if (!eventIds.includes(this.props.mxEvent.getId())) {
// Not pinned - add
@ -153,7 +153,8 @@ module.exports = React.createClass({
eventIds.splice(eventIds.indexOf(this.props.mxEvent.getId()), 1);
}
MatrixClientPeg.get().sendStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', {pinned: eventIds}, '');
const cli = MatrixClientPeg.get();
cli.sendStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', {pinned: eventIds}, '');
});
this.closeMenu();
},
@ -177,6 +178,14 @@ module.exports = React.createClass({
this.closeMenu();
},
onReplyClick: function() {
dis.dispatch({
action: 'quote_event',
event: this.props.mxEvent,
});
this.closeMenu();
},
render: function() {
const eventStatus = this.props.mxEvent.status;
let resendButton;
@ -184,12 +193,11 @@ module.exports = React.createClass({
let cancelButton;
let forwardButton;
let pinButton;
let viewSourceButton;
let viewClearSourceButton;
let unhidePreviewButton;
let permalinkButton;
let externalURLButton;
let quoteButton;
let replyButton;
if (eventStatus === 'not_sent') {
resendButton = (
@ -224,17 +232,25 @@ module.exports = React.createClass({
</div>
);
if (SettingsStore.isFeatureEnabled("feature_rich_quoting")) {
replyButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onReplyClick}>
{ _t('Reply') }
</div>
);
}
if (this.state.canPin) {
pinButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onPinClick}>
{this._isPinned() ? _t('Unpin Message') : _t('Pin Message')}
{ this._isPinned() ? _t('Unpin Message') : _t('Pin Message') }
</div>
);
}
}
}
viewSourceButton = (
const viewSourceButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}>
{ _t('View Source') }
</div>
@ -259,10 +275,10 @@ module.exports = React.createClass({
}
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
permalinkButton = (
const permalinkButton = (
<div className="mx_MessageContextMenu_field">
<a href={ "https://matrix.to/#/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() }
target="_blank" rel="noopener" onClick={ this.closeMenu }>{ _t('Permalink') }</a>
<a href={makeEventPermalink(this.props.mxEvent.getRoomId(), this.props.mxEvent.getId())}
target="_blank" rel="noopener" onClick={this.closeMenu}>{ _t('Permalink') }</a>
</div>
);
@ -275,29 +291,30 @@ module.exports = React.createClass({
}
// Bridges can provide a 'external_url' to link back to the source.
if( typeof(this.props.mxEvent.event.content.external_url) === "string") {
externalURLButton = (
<div className="mx_MessageContextMenu_field">
<a href={ this.props.mxEvent.event.content.external_url }
rel="noopener" target="_blank" onClick={ this.closeMenu }>{ _t('Source URL') }</a>
</div>
);
if (typeof(this.props.mxEvent.event.content.external_url) === "string") {
externalURLButton = (
<div className="mx_MessageContextMenu_field">
<a href={this.props.mxEvent.event.content.external_url}
rel="noopener" target="_blank" onClick={this.closeMenu}>{ _t('Source URL') }</a>
</div>
);
}
return (
<div>
{resendButton}
{redactButton}
{cancelButton}
{forwardButton}
{pinButton}
{viewSourceButton}
{viewClearSourceButton}
{unhidePreviewButton}
{permalinkButton}
{quoteButton}
{externalURLButton}
{ resendButton }
{ redactButton }
{ cancelButton }
{ forwardButton }
{ pinButton }
{ viewSourceButton }
{ viewClearSourceButton }
{ unhidePreviewButton }
{ permalinkButton }
{ quoteButton }
{ replyButton }
{ externalURLButton }
</div>
);
},

View File

@ -275,7 +275,7 @@ module.exports = React.createClass({
<div className={ alertMeClasses } onClick={this._onClickAlertMe} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
{ _t('All messages (loud)') }
{ _t('All messages (noisy)') }
</div>
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />

View File

@ -17,6 +17,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import sdk from 'matrix-react-sdk';
import SyntaxHighlight from '../elements/SyntaxHighlight';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
@ -60,7 +61,7 @@ class GenericEditor extends DevtoolsComponent {
<label htmlFor={id}>{ label }</label>
</div>
<div className="mx_DevTools_inputCell">
<input id={id} onChange={this._onChange} value={this.state[id]} size="32" />
<input id={id} className="mx_TextInputDialog_input" onChange={this._onChange} value={this.state[id]} size="32" />
</div>
</div>;
}
@ -363,7 +364,9 @@ class RoomStateExplorer extends DevtoolsComponent {
return <div className="mx_ViewSource">
<div className="mx_Dialog_content">
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre>
<SyntaxHighlight className="json">
{ JSON.stringify(this.state.event.event, null, 2) }
</SyntaxHighlight>
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.onBack}>{ _t('Back') }</button>
@ -492,7 +495,9 @@ class AccountDataExplorer extends DevtoolsComponent {
return <div className="mx_ViewSource">
<div className="mx_Dialog_content">
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre>
<SyntaxHighlight className="json">
{ JSON.stringify(this.state.event.event, null, 2) }
</SyntaxHighlight>
</div>
<div className="mx_Dialog_buttons">
<button onClick={this.onBack}>{ _t('Back') }</button>

View File

@ -20,7 +20,7 @@ var React = require('react');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var DateUtils = require('matrix-react-sdk/lib/DateUtils');
import {formatDate} from 'matrix-react-sdk/lib/DateUtils';
var filesize = require('filesize');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
const Modal = require('matrix-react-sdk/lib/Modal');
@ -159,7 +159,7 @@ module.exports = React.createClass({
}
eventMeta = (<div className="mx_ImageView_metadata">
{ _t('Uploaded on %(date)s by %(user)s', {date: DateUtils.formatDate(new Date(this.props.mxEvent.getTs())), user: sender}) }
{ _t('Uploaded on %(date)s by %(user)s', {date: formatDate(new Date(this.props.mxEvent.getTs())), user: sender}) }
</div>);
}

View File

@ -0,0 +1,53 @@
/*
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import {highlightBlock} from 'highlight.js';
export default class SyntaxHighlight extends React.Component {
static propTypes = {
className: PropTypes.string,
children: PropTypes.node,
};
constructor(props, context) {
super(props, context);
this._ref = this._ref.bind(this);
}
// componentDidUpdate used here for reusability
// componentWillReceiveProps fires too early to call highlightBlock on.
componentDidUpdate() {
if (this._el) highlightBlock(this._el);
}
// call componentDidUpdate because _ref is fired on initial render
// which does not fire componentDidUpdate
_ref(el) {
this._el = el;
this.componentDidUpdate();
}
render() {
const { className, children } = this.props;
return <pre className={`${className} mx_SyntaxHighlight`} ref={this._ref}>
<code>{ children }</code>
</pre>;
}
}

View File

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,8 +16,9 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import DateUtils from 'matrix-react-sdk/lib/DateUtils';
import {formatFullDateNoTime} from 'matrix-react-sdk/lib/DateUtils';
function getdaysArray() {
return [
@ -30,30 +32,30 @@ function getdaysArray() {
];
}
module.exports = React.createClass({
displayName: 'DateSeparator',
render: function() {
var date = new Date(this.props.ts);
var today = new Date();
var yesterday = new Date();
var days = getdaysArray();
yesterday.setDate(today.getDate() - 1);
var label;
if (date.toDateString() === today.toDateString()) {
label = _t('Today');
}
else if (date.toDateString() === yesterday.toDateString()) {
label = _t('Yesterday');
}
else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
label = days[date.getDay()];
}
else {
label = DateUtils.formatFullDate(date, this.props.showTwelveHour);
}
export default class DateSeparator extends React.Component {
static propTypes = {
ts: PropTypes.number.isRequired,
};
return (
<h2 className="mx_DateSeparator">{ label }</h2>
);
getLabel() {
const date = new Date(this.props.ts);
const today = new Date();
const yesterday = new Date();
const days = getdaysArray();
yesterday.setDate(today.getDate() - 1);
if (date.toDateString() === today.toDateString()) {
return _t('Today');
} else if (date.toDateString() === yesterday.toDateString()) {
return _t('Yesterday');
} else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
return days[date.getDay()];
} else {
return formatFullDateNoTime(date);
}
}
});
render() {
return <h2 className="mx_DateSeparator">{ this.getLabel() }</h2>;
}
}

View File

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,24 +15,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
import React from 'react';
import DateUtils from 'matrix-react-sdk/lib/DateUtils';
import PropTypes from 'prop-types';
import {formatFullDate, formatTime} from 'matrix-react-sdk/lib/DateUtils';
module.exports = React.createClass({
displayName: 'MessageTimestamp',
export default class MessageTimestamp extends React.Component {
static propTypes = {
ts: PropTypes.number.isRequired,
showTwelveHour: PropTypes.bool,
};
propTypes: {
showTwelveHour: React.PropTypes.bool,
},
render: function() {
render() {
const date = new Date(this.props.ts);
return (
<span className="mx_MessageTimestamp" title={ DateUtils.formatFullDate(date, this.props.showTwelveHour) }>
{ DateUtils.formatTime(date, this.props.showTwelveHour) }
<span className="mx_MessageTimestamp" title={formatFullDate(date, this.props.showTwelveHour)}>
{ formatTime(date, this.props.showTwelveHour) }
</span>
);
},
});
}
}

View File

@ -14,227 +14,51 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
import React from 'react';
import {DragSource} from 'react-dnd';
import {DropTarget} from 'react-dnd';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import sdk from 'matrix-react-sdk';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import { Draggable } from 'react-beautiful-dnd';
import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile';
import * as Rooms from 'matrix-react-sdk/lib/Rooms';
import Modal from 'matrix-react-sdk/lib/Modal';
/**
* Defines a new Component, DNDRoomTile that wraps RoomTile, making it draggable.
* Requires extra props:
* roomSubList: React.PropTypes.object.isRequired,
* refreshSubList: React.PropTypes.func.isRequired,
*/
import classNames from 'classnames';
/**
* Specifies the drag source contract.
* Only `beginDrag` function is required.
*/
var roomTileSource = {
canDrag: function(props, monitor) {
return props.roomSubList.props.editable;
},
beginDrag: function (props) {
// Return the data describing the dragged item
var item = {
room: props.room,
originalList: props.roomSubList,
originalIndex: props.roomSubList.findRoomTile(props.room).index,
targetList: props.roomSubList, // at first target is same as original
// lastTargetRoom: null,
// lastYOffset: null,
// lastYDelta: null,
};
if (props.roomSubList.debug) console.log("roomTile beginDrag for " + item.room.roomId);
// doing this 'correctly' with state causes react-dnd to break seemingly due to the state transitions
props.room._dragging = true;
return item;
},
endDrag: function (props, monitor, component) {
var item = monitor.getItem();
if (props.roomSubList.debug) console.log("roomTile endDrag for " + item.room.roomId + " with didDrop=" + monitor.didDrop());
props.room._dragging = false;
if (monitor.didDrop()) {
if (props.roomSubList.debug) console.log("force updating component " + item.targetList.props.label);
item.targetList.forceUpdate(); // as we're not using state
}
const prevTag = item.originalList.props.tagName;
const newTag = item.targetList.props.tagName;
if (monitor.didDrop() && item.targetList.props.editable) {
// Evil hack to get DMs behaving
if ((prevTag === undefined && newTag === 'im.vector.fake.direct') ||
(prevTag === 'im.vector.fake.direct' && newTag === undefined)
) {
Rooms.guessAndSetDMRoom(
item.room, newTag === 'im.vector.fake.direct',
).done(() => {
item.originalList.removeRoomTile(item.room);
}, (err) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to set direct chat tag " + err);
Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
title: _t('Failed to set direct chat tag'),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
return;
}
// More evilness: We will still be dealing with moving to favourites/low prio,
// but we avoid ever doing a request with 'im.vector.fake.direct`.
// if we moved lists, remove the old tag
if (prevTag && prevTag !== 'im.vector.fake.direct' &&
item.targetList !== item.originalList
) {
// commented out attempts to set a spinner on our target component as component is actually
// the original source component being dragged, not our target. To fix we just need to
// move all of this to endDrop in the target instead. FIXME later.
//component.state.set({ spinner: component.state.spinner ? component.state.spinner++ : 1 });
MatrixClientPeg.get().deleteRoomTag(item.room.roomId, prevTag).finally(function() {
//component.state.set({ spinner: component.state.spinner-- });
}).catch(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to remove tag " + prevTag + " from room: " + err);
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
title: _t('Failed to remove tag %(tagName)s from room', {tagName: prevTag}),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
}
var newOrder= {};
if (item.targetList.props.order === 'manual') {
newOrder['order'] = item.targetList.calcManualOrderTagData(item.room);
}
// if we moved lists or the ordering changed, add the new tag
if (newTag && newTag !== 'im.vector.fake.direct' &&
(item.targetList !== item.originalList || newOrder)
) {
MatrixClientPeg.get().setRoomTag(item.room.roomId, newTag, newOrder).catch(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to add tag " + newTag + " to room: " + err);
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
}
}
else {
// cancel the drop and reset our original position
if (props.roomSubList.debug) console.log("cancelling drop & drag");
props.roomSubList.moveRoomTile(item.room, item.originalIndex);
if (item.targetList && item.targetList !== item.originalList) {
item.targetList.removeRoomTile(item.room);
}
}
export default class DNDRoomTile extends React.Component {
constructor() {
super();
this.getClassName = this.getClassName.bind(this);
}
};
var roomTileTarget = {
canDrop: function() {
return false;
},
hover: function(props, monitor) {
var item = monitor.getItem();
//var off = monitor.getClientOffset();
// console.log("hovering on room " + props.room.roomId + ", isOver=" + monitor.isOver());
//console.log("item.targetList=" + item.targetList + ", roomSubList=" + props.roomSubList);
var switchedTarget = false;
if (item.targetList !== props.roomSubList) {
// we've switched target, so remove the tile from the previous target.
// n.b. the previous target might actually be the source list.
if (props.roomSubList.debug) console.log("switched target sublist");
switchedTarget = true;
item.targetList.removeRoomTile(item.room);
item.targetList = props.roomSubList;
}
if (!item.targetList.props.editable) return;
if (item.targetList.props.order === 'manual') {
if (item.room.roomId !== props.room.roomId && props.room !== item.lastTargetRoom) {
// find the offset of the target tile in the list.
var roomTile = props.roomSubList.findRoomTile(props.room);
// shuffle the list to add our tile to that position.
props.roomSubList.moveRoomTile(item.room, roomTile.index);
}
// stop us from flickering between our droptarget and the previous room.
// whenever the cursor changes direction we have to reset the flicker-damping.
/*
var yDelta = off.y - item.lastYOffset;
if ((yDelta > 0 && item.lastYDelta < 0) ||
(yDelta < 0 && item.lastYDelta > 0))
{
// the cursor changed direction - forget our previous room
item.lastTargetRoom = null;
}
else {
// track the last room we were hovering over so we can stop
// bouncing back and forth if the droptarget is narrower than
// the other list items. The other way to do this would be
// to reduce the size of the hittarget on the list items, but
// can't see an easy way to do that.
item.lastTargetRoom = props.room;
}
if (yDelta) item.lastYDelta = yDelta;
item.lastYOffset = off.y;
*/
}
else if (switchedTarget) {
if (!props.roomSubList.findRoomTile(item.room).room) {
// add to the list in the right place
props.roomSubList.moveRoomTile(item.room, 0);
}
// we have to sort the list whatever to recalculate it
props.roomSubList.sortList();
}
},
};
// Export the wrapped version, inlining the 'collect' functions
// to more closely resemble the ES7
module.exports =
DropTarget('RoomTile', roomTileTarget, function(connect, monitor) {
return {
// Call this function inside render()
// to let React DnD handle the drag events:
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
getClassName(isDragging) {
return classNames({
"mx_DNDRoomTile": true,
"mx_DNDRoomTile_dragging": isDragging,
});
}
})(
DragSource('RoomTile', roomTileSource, function(connect, monitor) {
return {
// Call this function inside render()
// to let React DnD handle the drag events:
connectDragSource: connect.dragSource(),
// You can ask the monitor about the current drag state:
isDragging: monitor.isDragging()
};
})(RoomTile));
render() {
const props = this.props;
return <div>
<Draggable
key={props.room.roomId}
draggableId={props.tagName + '_' + props.room.roomId}
index={props.index}
>
{ (provided, snapshot) => {
return (
<div>
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<div className={this.getClassName(snapshot.isDragging)}>
<RoomTile {...props} />
</div>
</div>
{ provided.placeholder }
</div>
);
} }
</Draggable>
</div>;
}
}

View File

@ -8,7 +8,7 @@
"All Rooms": "كل الغُرف",
"<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">متصفح سافاري</a> و <a href=\"http://opera.com\">متصفح أوبرا</a> يعملان أيضاً.",
"Add an email address above to configure email notifications": "أضف بريداً إلكترونياً أعلاه من أجل تعديل إعدادت تنبيهات البريد الإلكتروني",
"All messages (loud)": "كل الرسائل (صوت مرتفع)",
"All messages (noisy)": "كل الرسائل (صوت مرتفع)",
"All notifications are currently disabled for all targets.": "كل التنبيهات غير مفعلة حالياً للجميع.",
"An error occurred whilst saving your email notification preferences.": "حدث خطأ ما خلال حفظ إعدادات التنبيهات للبريد الإلكتروني.",
"Call invitation": "دعوة لمحادثة",

View File

@ -1,7 +1,7 @@
{
"Add an email address above to configure email notifications": "Дадайце адрас электроннай пошты вышэй, каб наладзіць апавяшчэнні",
"All messages": "Усе паведамленні",
"All messages (loud)": "Усе паведамленні (гучна)",
"All messages (noisy)": "Усе паведамленні (гучна)",
"All notifications are currently disabled for all targets.": "Усе апавяшчэнні ў цяперашні час адключаныя для ўсіх мэтаў.",
"An error occurred whilst saving your email notification preferences.": "Адбылася памылка падчас захавання налады апавяшчэнняў па электроннай пошце.",
"Cancel Sending": "Адмяніць адпраўку",

View File

@ -14,7 +14,7 @@
"Failed to remove tag %(tagName)s from room": "No s'ha pogut esborrar l'etiqueta %(tagName)s de la sala",
"Filter room names": "Filtra els noms de les sales",
"Couldn't load home page": "No s'ha pogut carregar la pàgina d'inici",
"All messages (loud)": "Tots els missatges (sorollós)",
"All messages (noisy)": "Tots els missatges (sorollós)",
"Mentions only": "Només mencions",
"Mute": "Silenciat",
"Direct Chat": "Xat directe",

View File

@ -42,7 +42,7 @@
"Messages sent by bot": "Zprávy poslané robotem",
"more": "více",
"Mute": "Ztlumit",
"All messages (loud)": "Všechny zprávy (hlasitě)",
"All messages (noisy)": "Všechny zprávy (hlasitě)",
"Couldn't load home page": "Nepodařilo se nahrát úvodní stránku",
"All notifications are currently disabled for all targets.": "Veškeré notifikace jsou aktuálně pro všechny cíle vypnuty.",
"Cancel Sending": "Zrušit odesílání",

View File

@ -62,7 +62,7 @@
"On": "An",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Du hast sie eventuell auf einem anderen Matrix-Client und nicht in Riot konfiguriert. Sie können in Riot nicht verändert werden, gelten aber trotzdem",
"All messages": "Alle Nachrichten",
"All messages (loud)": "Alle Nachrichten (laut)",
"All messages (noisy)": "Alle Nachrichten (laut)",
"Cancel Sending": "Senden abbrechen",
"Close": "Schließen",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Soll der Raum-Alias %(alias)s gelöscht und der %(name)s aus dem Verzeichnis entfernt werden?",

View File

@ -29,7 +29,7 @@
"Collecting app version information": "Συγκέντρωση πληροφοριών σχετικά με την έκδοση της εφαρμογής",
"customServer_text": "Μπορείτε να χρησιμοποιήσετε τις προσαρμοσμένες ρυθμίσεις για να εισέλθετε σε άλλους διακομιστές Matrix επιλέγοντας μια διαφορετική διεύθυνση για το διακομιστή.<br/> Αυτό σας επιτρέπει να χρησιμοποιήσετε την εφαρμογή Riot με έναν υπάρχοντα λογαριασμό σε διαφορετικό διακομιστή.<br/><br/>Επίσης μπορείτε να επιλέξετε ένα διαφορετικό διακομιστή ταυτότητας αλλά δεν θα έχετε τη δυνατότητα να προσκαλέσετε άλλους χρήστες ή να σας προσκαλέσουν μέσω μηνυμάτων ηλεκτρονικής αλληλογραφίας.",
"%(appName)s via %(browserName)s on %(osName)s": "%(appName)s μέσω %(browserName)s σε %(osName)s",
"All messages (loud)": "Όλα τα μηνύματα (δυνατά)",
"All messages (noisy)": "Όλα τα μηνύματα (δυνατά)",
"delete the alias.": "διέγραψε το ψευδώνυμο.",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Διαγραφή του ψευδώνυμου %(alias)s και αφαίρεση του %(name)s από το ευρετήριο;",
"Dismiss": "Απόρριψη",

View File

@ -137,7 +137,7 @@
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
"unknown error code": "unknown error code",
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
"All messages (loud)": "All messages (loud)",
"All messages (noisy)": "All messages (noisy)",
"All messages": "All messages",
"Mentions only": "Mentions only",
"Mute": "Mute",
@ -158,6 +158,8 @@
"Register": "Register",
"Invite to this room": "Invite to this room",
"Members": "Members",
"%(count)s Members|other": "%(count)s Members",
"%(count)s Members|one": "%(count)s Member",
"Files": "Files",
"Notifications": "Notifications",
"Rooms": "Rooms",
@ -217,5 +219,6 @@
"Contributing code to Matrix and Riot": "Contributing code to Matrix and Riot",
"Dev chat for the Riot/Web dev team": "Dev chat for the Riot/Web dev team",
"Dev chat for the Dendrite dev team": "Dev chat for the Dendrite dev team",
"Co-ordination for Riot/Web translators": "Co-ordination for Riot/Web translators"
"Co-ordination for Riot/Web translators": "Co-ordination for Riot/Web translators",
"Reply": "Reply"
}

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Add an email address above to configure email notifications",
"Advanced notification settings": "Advanced notification settings",
"All messages": "All messages",
"All messages (loud)": "All messages (loud)",
"All messages (noisy)": "All messages (noisy)",
"All Rooms": "All Rooms",
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
"An error occurred whilst saving your email notification preferences.": "An error occurred while saving your email notification preferences.",

View File

@ -1,7 +1,7 @@
{
"A new version of Riot is available.": "Nova versio de \"Riot\" haveblas.",
"All messages": "Ĉiuj mesaĝoj",
"All messages (loud)": "Ĉiuj mesaĝoj (lauta)",
"All messages (noisy)": "Ĉiuj mesaĝoj (lauta)",
"All Rooms": "Ĉiuj babilejoj",
"Cancel": "Nuligi",
"delete the alias.": "Forviŝi la kromnomon.",

View File

@ -135,7 +135,7 @@
"You have successfully set a password and an email address!": "¡Ha establecido exitosamente la contraseña y la dirección de email!",
"You have successfully set a password!": "¡Ha establecido exitosamente una contraseña!",
"%(appName)s via %(browserName)s on %(osName)s": "%(appName)s via %(browserName)s en %(osName)s",
"All messages (loud)": "Todos los mensajes (ruidoso)",
"All messages (noisy)": "Todos los mensajes (ruidoso)",
"All notifications are currently disabled for all targets.": "Las notificaciones estan desactivadas para todos los objetivos.",
"Collecting app version information": "Recolectando información de la versión de la aplicación",
"Collecting logs": "Recolectando registros",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Gehitu e-mail helbide bat goian e-mail bidezko jakinarazpenak konfiguratzeko",
"Advanced notification settings": "Jakinarazpen aurreratuen ezarpenak",
"All messages": "Mezu guztiak",
"All messages (loud)": "Mezu guztiak (ozen)",
"All messages (noisy)": "Mezu guztiak (ozen)",
"All Rooms": "Gela guztiak",
"All notifications are currently disabled for all targets.": "Une honetan jakinarazpen guztiak helburu guztietarako desgaituta daude.",
"An error occurred whilst saving your email notification preferences.": "Errore bat gertatu da zure e-mail bidezko jakinarazpenen hobespenak gordetzean.",

View File

@ -1,7 +1,7 @@
{
"A new version of Riot is available.": "نسخه‌ی جدید از رایوت موجود است.",
"All messages": "همه‌ی پیام‌ها",
"All messages (loud)": "همه‌ی پیام‌ها(بلند)",
"All messages (noisy)": "همه‌ی پیام‌ها(بلند)",
"All Rooms": "همه‌ی گپ‌ها",
"Cancel Sending": "فرستادن را لغو کن",
"Changelog": "تغییراتِ به‌وجودآمده",

View File

@ -4,7 +4,7 @@
"Add an email address above to configure email notifications": "Lisää sähköpostiosoite yllä saadaksesi ilmoituksia sähköpostiisi",
"Advanced notification settings": "Lisäasetukset ilmoituksille",
"All messages": "Kaikki viestit",
"All messages (loud)": "Kaikki viestit (äänekkäästi)",
"All messages (noisy)": "Kaikki viestit (äänekkäästi)",
"All Rooms": "Kaikki huoneet",
"All notifications are currently disabled for all targets.": "Kaikki ilmoitukset on kytketty pois kaikilta kohteilta.",
"An error occurred whilst saving your email notification preferences.": "Sähköposti-ilmoitusasetuksia tallettaessa tapahtui virhe.",

View File

@ -1,7 +1,7 @@
{
"Add an email address above to configure email notifications": "Ajouter une adresse e-mail pour la configuration des notifications par e-mail",
"All messages": "Tous les messages",
"All messages (loud)": "Tous les messages (fort)",
"All messages (noisy)": "Tous les messages (fort)",
"All notifications are currently disabled for all targets.": "Toutes les notifications sont désactivées pour tous les appareils.",
"An error occurred whilst saving your email notification preferences.": "Une erreur est survenue lors de la sauvegarde de vos préférences de notification par e-mail.",
"Cancel Sending": "Annuler l'envoi",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Engada un enderezo de correo electrónico para configurar as notificacións",
"Advanced notification settings": "Axustes avanzados de notificación",
"All messages": "Todas as mensaxes",
"All messages (loud)": "Todas as mensaxes (alto)",
"All messages (noisy)": "Todas as mensaxes (alto)",
"All Rooms": "Todas as Salas",
"All notifications are currently disabled for all targets.": "Todas as notificacións están deshabilitadas para todos os destinos.",
"An error occurred whilst saving your email notification preferences.": "Algo fallou mentras se gardaban as súas preferencias de notificaicón.",

View File

@ -3,7 +3,7 @@
"Add an email address above to configure email notifications": "הוסף כתובת דואר אלקטורני למעלה בכדי להגדיר התראות",
"Advanced notification settings": "הגדרות מתקדמות להתראות",
"All messages": "כל ההודעות",
"All messages (loud)": "כל ההודעות (צעקה)",
"All messages (noisy)": "כל ההודעות (צעקה)",
"All Rooms": "כל החדרים",
"All notifications are currently disabled for all targets.": "התראות מנוטרלות לכלל המערכת.",
"An error occurred whilst saving your email notification preferences.": "קרתה שגיאה בזמן שמירת הגדרות התראה באמצעות הדואר האלקטרוני.",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "E-mail értesítés beállításához írd be az e-mail címed",
"Advanced notification settings": "Haladó értesítési beállítások",
"All messages": "Minden üzenet",
"All messages (loud)": "Minden üzenet (hangos)",
"All messages (noisy)": "Minden üzenet (hangos)",
"All notifications are currently disabled for all targets.": "Minden céleszközön minden értesítés tiltva van.",
"An error occurred whilst saving your email notification preferences.": "Hiba történt az e-mail értesítés beállításánál.",
"Call invitation": "Hívás meghívó",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Tambahkan alamat email di atas untuk konfigurasi notifikasi email",
"Advanced notification settings": "Pengaturan notifikasi lanjutan",
"All messages": "Semua pesan",
"All messages (loud)": "Semua pesan (keras)",
"All messages (noisy)": "Semua pesan (keras)",
"All Rooms": "Semua Ruang",
"All notifications are currently disabled for all targets.": "Semua notifikasi saat ini dinonaktifkan untuk semua target.",
"An error occurred whilst saving your email notification preferences.": "Terjadi kesalahan saat menyimpan preferensi notifikasi email Anda.",

View File

@ -4,7 +4,7 @@
"Add an email address above to configure email notifications": "Aggiungi un indirizzo email sopra per configurare le notifiche via email",
"Advanced notification settings": "Impostazioni di notifica avanzate",
"All messages": "Tutti i messaggi",
"All messages (loud)": "Tutti i messaggi (rumoroso)",
"All messages (noisy)": "Tutti i messaggi (rumoroso)",
"All Rooms": "Tutte le stanze",
"An error occurred whilst saving your email notification preferences.": "Si è verificato un errore durante il salvataggio delle tue preferenze sulle notifiche email.",
"Call invitation": "Invito ad una chiamata",

View File

@ -1,6 +1,6 @@
{
"All messages": "全ての発言",
"All messages (loud)": "全ての発言(通知音あり)",
"All messages (noisy)": "全ての発言(通知音あり)",
"Cancel": "取消",
"Close": "閉じる",
"Direct Chat": "対話",

View File

@ -3,7 +3,7 @@
"Add an email address above to configure email notifications": "이메일 알림을 설정하기 위해 이메일 주소를 추가해주세요",
"Advanced notification settings": "고급 알림 설정",
"All messages": "모든 메시지",
"All messages (loud)": "모든 메시지 (크게)",
"All messages (noisy)": "모든 메시지 (크게)",
"All Rooms": "모든 방",
"All notifications are currently disabled for all targets.": "현재 모든 알림이 모든 상대에게서 꺼졌어요.",
"An error occurred whilst saving your email notification preferences.": "이메일 알림을 설정하다가 오류가 일어났어요.",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Pievieno augšā epasta adresi, lai konfigurētu epasta notifikāciju paziņojumus",
"Advanced notification settings": "Īpašie notifikāciju uzstādījumi",
"All messages": "Visas ziņas",
"All messages (loud)": "Visas ziņas (skaļi)",
"All messages (noisy)": "Visas ziņas (skaļi)",
"All Rooms": "Visas istabas",
"All notifications are currently disabled for all targets.": "Visi notifikāciju paziņojumi ir atspējoti visiem saņēmējiem.",
"An error occurred whilst saving your email notification preferences.": "Radās kļūda saglabājot tavus epasta notifikāciju ziņu uzstādījumus.",

View File

@ -1,7 +1,7 @@
{
"Add an email address above to configure email notifications": "ഇ മെയില്‍ അറിയിപ്പുകൾ ലഭിക്കാന്‍ മുകളില്‍ ഇ-മെയില്‍ വിലാസം നല്‍കൂ",
"All messages": "എല്ലാ സന്ദേശങ്ങളും",
"All messages (loud)": "എല്ലാ സന്ദേശങ്ങളും (ഉച്ചത്തിൽ)",
"All messages (noisy)": "എല്ലാ സന്ദേശങ്ങളും (ഉച്ചത്തിൽ)",
"%(appName)s via %(browserName)s on %(osName)s": "%(osName)sല് %(browserName)s വഴി %(appName)s",
"<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">സഫാരിയിലും</a>പിന്നെ <a href=\"http://opera.com\">ഓപ്പേറയിലും</a>പ്രവര്‍ത്തിക്കുന്നു.",
"A new version of Riot is available.": "റയട്ടിന്റെ ഒരു പുതിയ പതിപ്പ് ലഭ്യമാണ്.",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "Legg til en epost adresse for å sette opp epost varsling",
"Advanced notification settings": "Avanserte varslingsinnstillinger",
"All messages": "Alle meldinger",
"All messages (loud)": "Alle meldinger (høy)",
"All messages (noisy)": "Alle meldinger (høy)",
"All notifications are currently disabled for all targets.": "Alle varsler er deaktivert for alle mottakere.",
"An error occurred whilst saving your email notification preferences.": "En feil oppsto i forbindelse med lagring av epost varsel innstillinger.",
"Cancel Sending": "Avbryt sending",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "Voeg een e-mailadres toe om e-mailmeldingen te ontvangen",
"Advanced notification settings": "Geavanceerde meldingsinstellingen",
"All messages": "Alle berichten",
"All messages (loud)": "Alle berichten (luid)",
"All messages (noisy)": "Alle berichten (luid)",
"All notifications are currently disabled for all targets.": "Alle meldingen zijn momenteel uitgeschakeld voor alle doelen.",
"An error occurred whilst saving your email notification preferences.": "Er is een fout opgetreden tijdens het opslaan van uw e-mailmeldingsvoorkeuren.",
"Call invitation": "Oproep-uitnodiging",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Dodaj adres e-mail powyżej, aby skonfigurować powiadomienia e-mailowe",
"Advanced notification settings": "Zaawansowane ustawienia powiadomień",
"All messages": "Wszystkie wiadomości",
"All messages (loud)": "Wszystkie wiadomości (głośno)",
"All messages (noisy)": "Wszystkie wiadomości (głośno)",
"All Rooms": "Wszystkie pokoje",
"All notifications are currently disabled for all targets.": "Wszystkie powiadomienia są obecnie wyłączone dla wszystkich celów.",
"An error occurred whilst saving your email notification preferences.": "Podczas zapisywania ustawień powiadomień e-mail wystąpił błąd.",

View File

@ -1,7 +1,7 @@
{
"Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar as notificações por email",
"All messages": "Todas as mensagens",
"All messages (loud)": "Todas as mensagens (alto)",
"All messages (noisy)": "Todas as mensagens (alto)",
"An error occurred whilst saving your email notification preferences.": "Ocorreu um erro ao guardar as suas preferências de notificação por email.",
"Call invitation": "Convite para chamada",
"Cancel Sending": "Cancelar o envio",

View File

@ -1,7 +1,7 @@
{
"Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar suas notificações por email",
"All messages": "Todas as mensagens",
"All messages (loud)": "Todas as mensagens (alto)",
"All messages (noisy)": "Todas as mensagens (alto)",
"An error occurred whilst saving your email notification preferences.": "Um erro ocorreu enquanto o sistema estava salvando suas preferências de notificação por email.",
"Call invitation": "Convite para chamada",
"Cancel Sending": "Cancelar o envio",

View File

@ -63,7 +63,7 @@
"You are not receiving desktop notifications": "Вы не получаете уведомления на рабочем столе",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Возможно вы настроили их не в Riot, а в другом Matrix-клиенте. Настроить их в Riot не удастся, но они будут в нем применяться",
"All messages": "Все сообщения",
"All messages (loud)": "Все сообщения (со звуком)",
"All messages (noisy)": "Все сообщения (со звуком)",
"Cancel Sending": "Отменить отправку",
"Close": "Закрыть",
"Download this file": "Скачать этот файл",

View File

@ -135,7 +135,7 @@
"Failed to set Direct Message status of room": "Nepodarilo sa nastaviť stav miestnosti priama konverzácia",
"unknown error code": "neznámy kód chyby",
"Failed to forget room %(errCode)s": "Nepodarilo sa zabudnuť miestnosť %(errCode)s",
"All messages (loud)": "Všetky správy (hlučné)",
"All messages (noisy)": "Všetky správy (hlučné)",
"All messages": "Všetky správy",
"Mentions only": "Len zmienky",
"Mute": "Umlčať",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "Lägg till en epostadress här för att konfigurera epostaviseringar",
"Advanced notification settings": "Avancerade aviseringsinställingar",
"All messages": "Alla meddelanden",
"All messages (loud)": "Alla meddelanden (högljudd)",
"All messages (noisy)": "Alla meddelanden (högljudd)",
"All notifications are currently disabled for all targets.": "Alla aviseringar är för tillfället avstängda för alla mål.",
"An error occurred whilst saving your email notification preferences.": "Ett fel uppstod då epostaviseringsinställningarna sparades.",
"Call invitation": "Inbjudan till samtal",

View File

@ -4,7 +4,7 @@
"Add an email address above to configure email notifications": "மின்னஞ்சல் மூலம் அறிவிப்புகளை பெற உங்கள் மின்னஞ்சல் முகவரியை மேலே இணைக்கவும்",
"Advanced notification settings": "மேம்பட்ட அறிவிப்பிற்கான அமைப்புகள்",
"All messages": "அனைத்து செய்திகள்",
"All messages (loud)": "அனைத்து செய்திகள் (உரக்க)",
"All messages (noisy)": "அனைத்து செய்திகள் (உரக்க)",
"All Rooms": "அனைத்து அறைகள்",
"All notifications are currently disabled for all targets.": "அனைத்து இலக்குகளுக்கான அனைத்து அறிவுப்புகளும் தற்போது முடக்கி வைக்கப்பட்டுள்ளது.",
"An error occurred whilst saving your email notification preferences.": "உங்கள் மின்னஞ்சல் அறிவிப்பு விருப்பங்களை சேமிப்பதில் ஏதோ பிழை ஏற்பட்டுள்ளது.",

View File

@ -16,7 +16,7 @@
"Add an email address above to configure email notifications": "ఇమెయిల్ ప్రకటనలను రూపశిల్పం చేయడానికి ఎగువ ఇమెయిల్ చిరునామాను జోడించండి",
"Advanced notification settings": "ఆధునిక తాఖీదు అమరిక",
"All messages": "అన్ని సందేశాలు",
"All messages (loud)": "అన్ని సందేశాలు (గట్టిగ)",
"All messages (noisy)": "అన్ని సందేశాలు (గట్టిగ)",
"All Rooms": "అన్ని గదులు",
"Call invitation": "మాట్లాడడానికి ఆహ్వానం",
"Cancel Sending": "పంపడాన్ని ఆపేయండి",

View File

@ -81,7 +81,7 @@
"Riot is not supported on mobile web. Install the app?": "Riot ไม่รองรับเว็บบนอุปกรณ์พกพา ติดตั้งแอป?",
"Riot does not know how to join a room on this network": "Riot ไม่รู้วิธีเข้าร่วมห้องในเครือข่ายนี้",
"Direct Chat": "แชทโดยตรง",
"All messages (loud)": "ทุกข้อความ (เสียงดัง)",
"All messages (noisy)": "ทุกข้อความ (เสียงดัง)",
"Custom Server Options": "กำหนดเซิร์ฟเวอร์เอง",
"Directory": "ไดเรกทอรี",
"Enable audible notifications in web client": "เปิดใช้งานเสียงแจ้งเตือนบนเว็บไคลเอนต์",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "E-posta bildirimlerini yapılandırmak için yukarıya bir e-posta adresi ekleyin",
"Advanced notification settings": "Gelişmiş bildirim ayarları",
"All messages": "Tüm mesajlar",
"All messages (loud)": "Tüm mesajlar (uzun)",
"All messages (noisy)": "Tüm mesajlar (uzun)",
"All Rooms": "Tüm Odalar",
"All notifications are currently disabled for all targets.": "Tüm bildirimler şu anda tüm hedefler için devre dışı bırakılmıştır.",
"An error occurred whilst saving your email notification preferences.": "E-posta bildirim tercihlerinizi kaydetme işlemi sırasında bir hata oluştu.",

View File

@ -1,7 +1,7 @@
{
"A new version of Riot is available.": "Доступне оновлення для Riot.",
"All messages": "Усі повідомлення",
"All messages (loud)": "Усі повідомлення (гучно)",
"All messages (noisy)": "Усі повідомлення (гучно)",
"All Rooms": "Усі кімнати",
"All notifications are currently disabled for all targets.": "Сповіщення для усіх цілей на даний момент вимкнені.",
"An error occurred whilst saving your email notification preferences.": "Під час збереження налаштувань сповіщень е-поштою трапилася помилка.",

View File

@ -10,7 +10,7 @@
"Add an email address above to configure email notifications": "请在上方输入电子邮件地址以接收邮件通知",
"Advanced notification settings": "通知高级设置",
"All messages": "全部消息",
"All messages (loud)": "全部消息(高亮)",
"All messages (noisy)": "全部消息(高亮)",
"All Rooms": "全部聊天室",
"All notifications are currently disabled for all targets.": "当前所有目标的通知均已禁用。",
"An error occurred whilst saving your email notification preferences.": "保存邮件通知首选项设定时出现错误。",

View File

@ -8,7 +8,7 @@
"<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">Safari</a> 與 <a href=\"http://opera.com\">Opera</a> 也能使用。",
"Advanced notification settings": "進階通知設定",
"All messages": "所有訊息",
"All messages (loud)": "所有訊息(吵鬧)",
"All messages (noisy)": "所有訊息(吵鬧)",
"All Rooms": "所有的聊天室",
"Call invitation": "通話邀請",
"Cancel": "取消",

View File

@ -11,6 +11,7 @@
@import "./matrix-react-sdk/structures/_RoomStatusBar.scss";
@import "./matrix-react-sdk/structures/_RoomView.scss";
@import "./matrix-react-sdk/structures/_SearchBox.scss";
@import "./matrix-react-sdk/structures/_TagPanel.scss";
@import "./matrix-react-sdk/structures/_UploadBar.scss";
@import "./matrix-react-sdk/structures/_UserSettings.scss";
@import "./matrix-react-sdk/structures/login/_Login.scss";
@ -38,6 +39,7 @@
@import "./matrix-react-sdk/views/elements/_RichText.scss";
@import "./matrix-react-sdk/views/elements/_RoleButton.scss";
@import "./matrix-react-sdk/views/elements/_ToolTipButton.scss";
@import "./matrix-react-sdk/views/elements/_Quote.scss";
@import "./matrix-react-sdk/views/groups/_GroupPublicityToggle.scss";
@import "./matrix-react-sdk/views/groups/_GroupRoomList.scss";
@import "./matrix-react-sdk/views/groups/_GroupUserSettings.scss";
@ -69,6 +71,7 @@
@import "./matrix-react-sdk/views/rooms/_RoomTile.scss";
@import "./matrix-react-sdk/views/rooms/_SearchableEntityList.scss";
@import "./matrix-react-sdk/views/rooms/_TopUnreadMessagesBar.scss";
@import "./matrix-react-sdk/views/rooms/_QuotePreview.scss";
@import "./matrix-react-sdk/views/settings/_DevicesPanel.scss";
@import "./matrix-react-sdk/views/settings/_IntegrationsManager.scss";
@import "./matrix-react-sdk/views/voip/_CallView.scss";
@ -93,6 +96,7 @@
@import "./vector-web/views/elements/_ImageView.scss";
@import "./vector-web/views/elements/_InlineSpinner.scss";
@import "./vector-web/views/elements/_Spinner.scss";
@import "./vector-web/views/elements/_SyntaxHighlight.scss";
@import "./vector-web/views/globals/_MatrixToolbar.scss";
@import "./vector-web/views/messages/_DateSeparator.scss";
@import "./vector-web/views/messages/_MessageTimestamp.scss";

View File

@ -21,6 +21,8 @@ limitations under the License.
padding-top: 24px;
padding-bottom: 22px;
border-bottom: 1px solid $panel-divider-color;
display: flex;
}

View File

@ -0,0 +1,79 @@
/*
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.
*/
.mx_TagPanel {
width: 60px;
background-color: $tertiary-accent-color;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.mx_TagPanel .mx_TagPanel_tagTileContainer {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 65px;
flex-grow: 1;
}
.mx_TagPanel .mx_TagTile {
padding: 6px 3px;
opacity: 0.5;
}
.mx_TagPanel .mx_TagTile:focus,
.mx_TagPanel .mx_TagTile:hover,
.mx_TagPanel .mx_TagTile.mx_TagTile_selected {
opacity: 1;
}
.mx_TagPanel .mx_TagTile.mx_TagTile_selected {
/* To offset border of mx_TagTile_avatar */
padding: 3px 0px;
}
.mx_TagPanel .mx_TagTile.mx_TagTile_selected .mx_TagTile_avatar {
border: 3px solid $accent-color;
border-radius: 60px;
}
.mx_TagPanel .mx_TagTile.mx_AccessibleButton:focus {
filter: none;
}
.mx_TagTile_tooltip {
position: relative;
top: -30px;
left: 5px;
}
.mx_TagPanel_createGroupButton {
opacity: 0.5;
margin-bottom: 17px;
height: 25px;
}
.mx_TagPanel_createGroupButton:hover {
opacity: 1;
}
.mx_TagPanel_createGroupButton object {
pointer-events: none;
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_Quote .mx_DateSeparator {
font-size: 1em !important;
margin-bottom: 0;
padding-bottom: 1px;
bottom: -5px;
}
.mx_Quote_show {
cursor: pointer;
}

View File

@ -19,4 +19,5 @@ limitations under the License.
border: 1px solid $primary-hairline-color;
border-radius: 3px;
margin-right: 32px;
overflow: hidden;
}

View File

@ -85,6 +85,14 @@ limitations under the License.
flex-direction: row;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.mx_AppTileMenuBarTitle {
display: flex;
flex-direction: row;
align-items: center;
pointer-events: none;
}
.mx_AppTileMenuBarWidgets {
@ -93,6 +101,7 @@ limitations under the License.
flex-direction: row;
align-items: center;
}
.mx_AppTileMenuBarWidget {
// pointer-events: none;
cursor: pointer;

View File

@ -1,7 +1,7 @@
.mx_Autocomplete {
position: absolute;
bottom: 0;
z-index: 1000;
z-index: 1001;
width: 100%;
border: 1px solid $primary-hairline-color;
background: $primary-bg-color;
@ -90,3 +90,4 @@
.mx_Autocomplete_Completion_description {
color: gray;
}

View File

@ -96,6 +96,10 @@ limitations under the License.
line-height: 22px;
}
.mx_EventTile_quote {
margin-right: 10px;
}
.mx_EventTile_info .mx_EventTile_line {
padding-left: 83px;
}
@ -109,13 +113,13 @@ limitations under the License.
/* this is used for the tile for the event which is selected via the URL.
* TODO: ultimately we probably want some transition on here.
*/
.mx_EventTile_selected .mx_EventTile_line {
.mx_EventTile_selected > .mx_EventTile_line {
border-left: $accent-color 5px solid;
padding-left: 60px;
background-color: $event-selected-color;
}
.mx_EventTile:hover .mx_EventTile_line,
.mx_EventTile:hover .mx_EventTile_line:not(.mx_EventTile_quote),
.mx_EventTile.menu .mx_EventTile_line
{
background-color: $event-selected-color;
@ -209,7 +213,7 @@ limitations under the License.
visibility: visible;
}
.mx_EventTile_selected .mx_MessageTimestamp {
.mx_EventTile_selected > div > a > .mx_MessageTimestamp {
left: 3px;
width: auto;
}
@ -224,6 +228,10 @@ limitations under the License.
width: 19px;
height: 19px;
background-image: url($edit-button-url);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mx_EventTile:hover .mx_EventTile_editButton,

View File

@ -98,6 +98,9 @@ limitations under the License.
width: 100%;
flex: 1;
word-break: break-word;
max-height: 120px;
min-height: 21px;
overflow: auto;
}
.mx_MessageComposer_input .DraftEditor-root .DraftEditor-editorContainer {
@ -105,12 +108,6 @@ limitations under the License.
padding-top: 2px;
}
.mx_MessageComposer_input .public-DraftEditor-content {
max-height: 120px;
min-height: 21px;
overflow: auto;
}
.mx_MessageComposer_input blockquote {
color: $blockquote-fg-color;
margin: 0 0 16px;

View File

@ -0,0 +1,36 @@
.mx_QuotePreview {
position: absolute;
bottom: 0;
z-index: 1000;
width: 100%;
border: 1px solid $primary-hairline-color;
background: $primary-bg-color;
border-bottom: none;
border-radius: 4px 4px 0 0;
max-height: 50vh;
overflow: auto
}
.mx_QuotePreview_section {
border-bottom: 1px solid $primary-hairline-color;
}
.mx_QuotePreview_header {
margin: 12px;
color: $primary-fg-color;
font-weight: 400;
opacity: 0.4;
}
.mx_QuotePreview_title {
float: left;
}
.mx_QuotePreview_cancel {
float: right;
cursor: pointer;
}
.mx_QuotePreview_clear {
clear: both;
}

View File

@ -20,6 +20,8 @@ limitations under the License.
font-size: 13px;
display: block;
height: 34px;
background-color: $secondary-accent-color;
}
.mx_RoomTile_tooltip {
@ -155,6 +157,15 @@ limitations under the License.
background-color: $roomtile-selected-bg-color;
}
.mx_DNDRoomTile {
transform: none;
transition: transform 0.2s;
}
.mx_DNDRoomTile_dragging {
transform: scale(1.05, 1.05);
}
.mx_RoomTile:focus {
filter: none ! important;
background-color: $roomtile-focused-bg-color;

View File

@ -40,6 +40,7 @@ $preview-bar-bg-color: #f7f7f7;
// left-panel style muted accent color
$secondary-accent-color: #eaf5f0;
$tertiary-accent-color: #d3efe1;
// used by RoomDirectory permissions
$plinth-bg-color: $secondary-accent-color;
@ -48,7 +49,7 @@ $plinth-bg-color: $secondary-accent-color;
$droptarget-bg-color: rgba(255,255,255,0.5);
// used by AddressSelector
$selected-color: #eaf5f0;
$selected-color: $secondary-accent-color;
// selected for hoverover & selected event tiles
$event-selected-color: #f7f7f7;
@ -103,15 +104,16 @@ $roomtile-name-color: rgba(69, 69, 69, 0.8);
$roomtile-selected-bg-color: rgba(255, 255, 255, 0.8);
$roomtile-focused-bg-color: rgba(255, 255, 255, 0.9);
$roomsublist-background: #badece;
$roomsublist-label-fg-color: $h3-color;
$roomsublist-label-bg-color: #d3efe1;
$roomsublist-label-bg-color: $tertiary-accent-color;
$roomsublist-chevron-color: $accent-color;
$panel-divider-color: rgba(118, 207, 166, 0.2);
// ********************
$widget-menu-bar-bg-color: #d3efe1;
$widget-menu-bar-bg-color: $tertiary-accent-color;
// ********************

View File

@ -29,12 +29,13 @@ $preview-bar-bg-color: #333;
// left-panel style muted accent color
$secondary-accent-color: $primary-bg-color;
$tertiary-accent-color: #454545;
// stop the tinter trying to change the secondary accent color
// by overriding the key to something untintable
// XXX: this is a bit of a hack.
#mx_theme_secondaryAccentColor {
color: #c0ff33 ! important; // deliberately off by one
color: #c0ffee ! important;
}
#mx_theme_tertiaryAccentColor {
@ -99,18 +100,19 @@ $rte-code-bg-color: #000;
// ********************
$roomtile-name-color: rgba(186, 186, 186, 0.8);
$roomtile-selected-bg-color: rgba(255, 255, 255, 0.05);
$roomtile-selected-bg-color: #333;
$roomtile-focused-bg-color: rgba(255, 255, 255, 0.2);
$roomsublist-background: #222;
$roomsublist-label-fg-color: $h3-color;
$roomsublist-label-bg-color: #454545;
$roomsublist-label-bg-color: $tertiary-accent-color;
$roomsublist-chevron-color: $accent-color;
$panel-divider-color: rgba(118, 207, 166, 0.2);
// ********************
$widget-menu-bar-bg-color: #454545;
$widget-menu-bar-bg-color: $tertiary-accent-color;
// ********************

View File

@ -44,6 +44,7 @@ limitations under the License.
.mx_LeftPanel.collapsed .mx_BottomLeftMenu {
flex: 0 0 160px;
margin-bottom: 9px;
}
.mx_LeftPanel .mx_BottomLeftMenu {
@ -77,6 +78,7 @@ limitations under the License.
.mx_BottomLeftMenu_options .mx_RoleButton {
margin-left: 0px;
margin-right: 10px;
height: 30px;
}
.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings {

View File

@ -18,6 +18,8 @@ limitations under the License.
display: table;
table-layout: fixed;
width: 100%;
background-color: $roomsublist-background;
}
.mx_RoomSubList_labelContainer {
@ -33,14 +35,13 @@ limitations under the License.
font-weight: 600;
font-size: 12px;
width: 203px; /* padding + width = LHS Panel width */
height: 17px; /* padding + height = 29px, same as mx_RoomSubList_stickyContainer */
height: 19px; /* height + padding = 31px = mx_RoomSubList_label height */
padding-left: 16px; /* gutter */
padding-right: 16px; /* gutter */
padding-top: 6px;
padding-bottom: 6px;
cursor: pointer;
background-color: $roomsublist-label-bg-color;
border-top: solid 2px $secondary-accent-color;
background-color: $secondary-accent-color;
}
.mx_RoomSubList_label.mx_RoomSubList_fixed {
@ -156,6 +157,8 @@ limitations under the License.
position: relative;
cursor: pointer;
font-size: 13px;
background-color: $secondary-accent-color;
}
.collapsed .mx_RoomSubList_ellipsis {

View File

@ -0,0 +1,21 @@
/*
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
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.
*/
.mx_SyntaxHighlight {
/* inhibit hljs styling */
background: none !important;
color: $light-fg-color !important;
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="2048px" height="1792px" viewBox="0 0 2048 1792" enable-background="new 0 0 2048 1792" xml:space="preserve">
<path fill="#76CFA6" d="M1024,672c79.333,0,147.166,28.167,203.5,84.5c56.333,56.334,84.5,124.167,84.5,203.5
c0,79.334-28.167,147.167-84.5,203.5c-56.334,56.334-124.167,84.5-203.5,84.5c-79.334,0-147.167-28.166-203.5-84.5
C764.166,1107.167,736,1039.334,736,960c0-79.333,28.166-147.166,84.5-203.5C876.833,700.167,944.666,672,1024,672z M1728,256
c70.666,0,131,25,181,75s75,110.334,75,181v896c0,70.667-25,131-75,181s-110.334,75-181,75H320c-70.667,0-131-25-181-75
s-75-110.333-75-181V512c0-70.666,25-131,75-181s110.333-75,181-75h224l51-136c12.666-32.666,35.833-60.833,69.5-84.5
C698.166,11.834,732.666,0,768,0h512c35.333,0,69.833,11.834,103.5,35.5c33.666,23.667,56.833,51.834,69.5,84.5l51,136H1728z
M1024,1408c123.333,0,228.833-43.833,316.5-131.5c87.666-87.666,131.5-193.166,131.5-316.5c0-123.333-43.834-228.833-131.5-316.5
C1252.833,555.834,1147.333,512,1024,512c-123.334,0-228.834,43.834-316.5,131.5C619.833,731.167,576,836.667,576,960
c0,123.334,43.833,228.834,131.5,316.5C795.166,1364.167,900.666,1408,1024,1408z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1792px" height="1792px" viewBox="0 0 1792 1792" enable-background="new 0 0 1792 1792" xml:space="preserve">
<path fill="#76CFA6" d="M256,1408h1280V640H256V1408z M1792,288v1216c0,44-15.667,81.667-47,113s-69,47-113,47H160
c-44,0-81.667-15.667-113-47s-47-69-47-113V288c0-44,15.667-81.667,47-113s69-47,113-47h1472c44,0,81.667,15.667,113,47
S1792,244,1792,288z"/>
</svg>

After

Width:  |  Height:  |  Size: 745 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1792px" height="1792px" viewBox="0 0 1792 1792" enable-background="new 0 0 1792 1792" xml:space="preserve">
<path fill="#76CFA6" d="M1792,1312v192c0,44-15.667,81.667-47,113s-69,47-113,47H160c-44,0-81.667-15.667-113-47s-47-69-47-113v-192
c0-44,15.667-81.667,47-113s69-47,113-47h1472c44,0,81.667,15.667,113,47S1792,1268,1792,1312z"/>
</svg>

After

Width:  |  Height:  |  Size: 716 B

View File

@ -85,6 +85,7 @@ $preview-bar-bg-color: #f7f7f7;
// left-panel style muted accent color
$secondary-accent-color: #586C7B;
$tertiary-accent-color: #DBEBF6;
// stop the tinter trying to change the secondary accent color
// by overriding the key to something untintable
@ -159,6 +160,7 @@ $roomtile-name-color: #ffffff;
$roomtile-selected-bg-color: #465561;
$roomtile-focused-bg-color: #6d8597;
$roomsublist-background: #465561;
$roomsublist-label-fg-color: #ffffff;
$roomsublist-label-bg-color: $secondary-accent-color;
$roomsublist-chevron-color: #ffffff;
@ -236,7 +238,7 @@ $progressbar-color: #000;
.mx_RoomSubList_label {
font-size: 13px;
font-family: $header-font-family;
letter-spacing: 1px;
letter-spacing: 1px;
}
// FIXME: all these ! importants are horrid - we should instead go and define

View File

@ -387,6 +387,7 @@ async function loadLanguage() {
}
try {
await languageHandler.setLanguage(langs);
document.documentElement.setAttribute("lang", languageHandler.getCurrentLanguage());
} catch (e) {
console.error("Unable to set language", e);
}

View File

@ -16,6 +16,9 @@ limitations under the License.
/* joining.js: tests for the various paths when joining a room */
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
import Platform from '../../src/vector/platform';
require('skin-sdk');
var jssdk = require('matrix-js-sdk');
@ -85,6 +88,8 @@ describe('joining a room', function () {
localStorage.setItem("mx_access_token", ACCESS_TOKEN );
localStorage.setItem("mx_user_id", USER_ID);
PlatformPeg.set(new Platform());
var mc = (
<MatrixChat config={{}}
makeRegistrationUrl={()=>{throw new Error("unimplemented");}}

View File

@ -16,6 +16,9 @@ limitations under the License.
/* loading.js: test the myriad paths we have for loading the application */
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
import Platform from '../../src/vector/platform';
import 'skin-sdk';
import React from 'react';
@ -137,6 +140,8 @@ describe('loading:', function () {
default_is_url: DEFAULT_IS_URL,
}, opts.config || {});
PlatformPeg.set(new Platform());
var params = parseQs(windowLocation);
matrixChat = ReactDOM.render(
<MatrixChat