mirror of
https://github.com/SchildiChat/element-web.git
synced 2024-10-01 01:26:12 -04:00
Merge branch 'develop' of github.com:vector-im/riot-web into t3chguy/devtools-118247
This commit is contained in:
commit
04bca93e0d
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -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)
|
||||
|
45
README.md
45
README.md
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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": {
|
||||
|
@ -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": {
|
||||
|
11
package.json
11
package.json
@ -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",
|
||||
|
@ -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'},
|
||||
|
@ -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;
|
||||
|
@ -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> </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",
|
||||
{
|
||||
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 }
|
||||
|
@ -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>
|
||||
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;
|
||||
|
@ -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';
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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,11 +291,11 @@ 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") {
|
||||
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>
|
||||
<a href={this.props.mxEvent.event.content.external_url}
|
||||
rel="noopener" target="_blank" onClick={this.closeMenu}>{ _t('Source URL') }</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -287,17 +303,18 @@ module.exports = React.createClass({
|
||||
|
||||
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>
|
||||
);
|
||||
},
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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>);
|
||||
}
|
||||
|
||||
|
53
src/components/views/elements/SyntaxHighlight.js
Normal file
53
src/components/views/elements/SyntaxHighlight.js
Normal 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>;
|
||||
}
|
||||
}
|
@ -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();
|
||||
export default class DateSeparator extends React.Component {
|
||||
static propTypes = {
|
||||
ts: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
getLabel() {
|
||||
const date = new Date(this.props.ts);
|
||||
const today = new Date();
|
||||
const yesterday = new Date();
|
||||
const days = getdaysArray();
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
var label;
|
||||
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
label = _t('Today');
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return (
|
||||
<h2 className="mx_DateSeparator">{ label }</h2>
|
||||
);
|
||||
render() {
|
||||
return <h2 className="mx_DateSeparator">{ this.getLabel() }</h2>;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
export default class DNDRoomTile extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.getClassName = this.getClassName.bind(this);
|
||||
}
|
||||
|
||||
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')),
|
||||
});
|
||||
getClassName(isDragging) {
|
||||
return classNames({
|
||||
"mx_DNDRoomTile": true,
|
||||
"mx_DNDRoomTile_dragging": isDragging,
|
||||
});
|
||||
}
|
||||
|
||||
var newOrder= {};
|
||||
if (item.targetList.props.order === 'manual') {
|
||||
newOrder['order'] = item.targetList.calcManualOrderTagData(item.room);
|
||||
}
|
||||
render() {
|
||||
const props = this.props;
|
||||
|
||||
// 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')),
|
||||
});
|
||||
});
|
||||
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>;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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(),
|
||||
}
|
||||
})(
|
||||
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));
|
||||
}
|
||||
|
@ -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": "دعوة لمحادثة",
|
||||
|
@ -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": "Адмяніць адпраўку",
|
||||
|
@ -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",
|
||||
|
@ -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í",
|
||||
|
@ -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?",
|
||||
|
@ -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": "Απόρριψη",
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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.",
|
||||
|
@ -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.",
|
||||
|
@ -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",
|
||||
|
@ -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.",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"A new version of Riot is available.": "نسخهی جدید از رایوت موجود است.",
|
||||
"All messages": "همهی پیامها",
|
||||
"All messages (loud)": "همهی پیامها(بلند)",
|
||||
"All messages (noisy)": "همهی پیامها(بلند)",
|
||||
"All Rooms": "همهی گپها",
|
||||
"Cancel Sending": "فرستادن را لغو کن",
|
||||
"Changelog": "تغییراتِ بهوجودآمده",
|
||||
|
@ -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.",
|
||||
|
@ -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",
|
||||
|
@ -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.",
|
||||
|
@ -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.": "קרתה שגיאה בזמן שמירת הגדרות התראה באמצעות הדואר האלקטרוני.",
|
||||
|
@ -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ó",
|
||||
|
@ -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.",
|
||||
|
@ -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",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"All messages": "全ての発言",
|
||||
"All messages (loud)": "全ての発言(通知音あり)",
|
||||
"All messages (noisy)": "全ての発言(通知音あり)",
|
||||
"Cancel": "取消",
|
||||
"Close": "閉じる",
|
||||
"Direct Chat": "対話",
|
||||
|
@ -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.": "이메일 알림을 설정하다가 오류가 일어났어요.",
|
||||
|
@ -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.",
|
||||
|
@ -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.": "റയട്ടിന്റെ ഒരു പുതിയ പതിപ്പ് ലഭ്യമാണ്.",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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.",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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": "Скачать этот файл",
|
||||
|
@ -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ť",
|
||||
|
@ -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",
|
||||
|
@ -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.": "உங்கள் மின்னஞ்சல் அறிவிப்பு விருப்பங்களை சேமிப்பதில் ஏதோ பிழை ஏற்பட்டுள்ளது.",
|
||||
|
@ -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": "పంపడాన్ని ఆపేయండి",
|
||||
|
@ -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": "เปิดใช้งานเสียงแจ้งเตือนบนเว็บไคลเอนต์",
|
||||
|
@ -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.",
|
||||
|
@ -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.": "Під час збереження налаштувань сповіщень е-поштою трапилася помилка.",
|
||||
|
@ -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.": "保存邮件通知首选项设定时出现错误。",
|
||||
|
@ -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": "取消",
|
||||
|
@ -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";
|
||||
|
@ -21,6 +21,8 @@ limitations under the License.
|
||||
padding-top: 24px;
|
||||
padding-bottom: 22px;
|
||||
|
||||
border-bottom: 1px solid $panel-divider-color;
|
||||
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -19,4 +19,5 @@ limitations under the License.
|
||||
border: 1px solid $primary-hairline-color;
|
||||
border-radius: 3px;
|
||||
margin-right: 32px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
// ********************
|
||||
|
||||
|
@ -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;
|
||||
|
||||
// ********************
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
15
src/skins/vector/img/camera_green.svg
Normal file
15
src/skins/vector/img/camera_green.svg
Normal 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 |
9
src/skins/vector/img/maximize.svg
Normal file
9
src/skins/vector/img/maximize.svg
Normal 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 |
8
src/skins/vector/img/minimize.svg
Normal file
8
src/skins/vector/img/minimize.svg
Normal 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 |
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");}}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user