Merge branch 'develop' into wmwragg/chat-message-presentation
This commit is contained in:
commit
48a2567b82
12 changed files with 228 additions and 61 deletions
|
@ -273,8 +273,11 @@ function _onAction(payload) {
|
||||||
break;
|
break;
|
||||||
case 'incoming_call':
|
case 'incoming_call':
|
||||||
if (module.exports.getAnyActiveCall()) {
|
if (module.exports.getAnyActiveCall()) {
|
||||||
payload.call.hangup("busy");
|
// ignore multiple incoming calls. in future, we may want a line-1/line-2 setup.
|
||||||
return; // don't allow >1 call to be received, hangup newer one.
|
// we avoid rejecting with "busy" in case the user wants to answer it on a different device.
|
||||||
|
// in future we could signal a "local busy" as a warning to the caller.
|
||||||
|
// see https://github.com/vector-im/vector-web/issues/1964
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the runtime env doesn't do VoIP, stop here.
|
// if the runtime env doesn't do VoIP, stop here.
|
||||||
|
|
|
@ -69,7 +69,7 @@ var sanitizeHtmlParams = {
|
||||||
allowedAttributes: {
|
allowedAttributes: {
|
||||||
// custom ones first:
|
// custom ones first:
|
||||||
font: [ 'color' ], // custom to matrix
|
font: [ 'color' ], // custom to matrix
|
||||||
a: [ 'href', 'name', 'target' ], // remote target: custom to matrix
|
a: [ 'href', 'name', 'target', 'rel' ], // remote target: custom to matrix
|
||||||
// We don't currently allow img itself by default, but this
|
// We don't currently allow img itself by default, but this
|
||||||
// would make sense if we did
|
// would make sense if we did
|
||||||
img: [ 'src' ],
|
img: [ 'src' ],
|
||||||
|
@ -92,6 +92,7 @@ var sanitizeHtmlParams = {
|
||||||
else {
|
else {
|
||||||
attribs.target = '_blank';
|
attribs.target = '_blank';
|
||||||
}
|
}
|
||||||
|
attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
|
||||||
return { tagName: tagName, attribs : attribs };
|
return { tagName: tagName, attribs : attribs };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
164
src/RoomNotifs.js
Normal file
164
src/RoomNotifs.js
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import MatrixClientPeg from './MatrixClientPeg';
|
||||||
|
import PushProcessor from 'matrix-js-sdk/lib/pushprocessor';
|
||||||
|
import q from 'q';
|
||||||
|
|
||||||
|
export const ALL_MESSAGES_LOUD = 'all_messages_loud';
|
||||||
|
export const ALL_MESSAGES = 'all_messages';
|
||||||
|
export const MENTIONS_ONLY = 'mentions_only';
|
||||||
|
export const MUTE = 'mute';
|
||||||
|
|
||||||
|
export function getRoomNotifsState(roomId) {
|
||||||
|
if (MatrixClientPeg.get().isGuest()) return RoomNotifs.ALL_MESSAGES;
|
||||||
|
|
||||||
|
// look through the override rules for a rule affecting this room:
|
||||||
|
// if one exists, it will take precedence.
|
||||||
|
const muteRule = findOverrideMuteRule(roomId);
|
||||||
|
if (muteRule) {
|
||||||
|
return MUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for everything else, look at the room rule.
|
||||||
|
const roomRule = MatrixClientPeg.get().getRoomPushRule('global', roomId);
|
||||||
|
|
||||||
|
// XXX: We have to assume the default is to notify for all messages
|
||||||
|
// (in particular this will be 'wrong' for one to one rooms because
|
||||||
|
// they will notify loudly for all messages)
|
||||||
|
if (!roomRule || !roomRule.enabled) return ALL_MESSAGES;
|
||||||
|
|
||||||
|
// a mute at the room level will still allow mentions
|
||||||
|
// to notify
|
||||||
|
if (isMuteRule(roomRule)) return MENTIONS_ONLY;
|
||||||
|
|
||||||
|
const actionsObject = PushProcessor.actionListToActionsObject(roomRule.actions);
|
||||||
|
if (actionsObject.tweaks.sound) return ALL_MESSAGES_LOUD;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setRoomNotifsState(roomId, newState) {
|
||||||
|
if (newState == MUTE) {
|
||||||
|
return setRoomNotifsStateMuted(roomId);
|
||||||
|
} else {
|
||||||
|
return setRoomNotifsStateUnmuted(roomId, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRoomNotifsStateMuted(roomId) {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
// delete the room rule
|
||||||
|
const roomRule = cli.getRoomPushRule('global', roomId);
|
||||||
|
if (roomRule) {
|
||||||
|
promises.push(cli.deletePushRule('global', 'room', roomRule.rule_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add/replace an override rule to squelch everything in this room
|
||||||
|
// NB. We use the room ID as the name of this rule too, although this
|
||||||
|
// is an override rule, not a room rule: it still pertains to this room
|
||||||
|
// though, so using the room ID as the rule ID is logical and prevents
|
||||||
|
// duplicate copies of the rule.
|
||||||
|
promises.push(cli.addPushRule('global', 'override', roomId, {
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
kind: 'event_match',
|
||||||
|
key: 'room_id',
|
||||||
|
pattern: roomId,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
'dont_notify',
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
return q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRoomNotifsStateUnmuted(roomId, newState) {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
const overrideMuteRule = findOverrideMuteRule(roomId);
|
||||||
|
if (overrideMuteRule) {
|
||||||
|
promises.push(cli.deletePushRule('global', 'override', overrideMuteRule.rule_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newState == 'all_messages') {
|
||||||
|
const roomRule = cli.getRoomPushRule('global', roomId);
|
||||||
|
if (roomRule) {
|
||||||
|
promises.push(cli.deletePushRule('global', 'room', roomRule.rule_id));
|
||||||
|
}
|
||||||
|
} else if (newState == 'mentions_only') {
|
||||||
|
promises.push(cli.addPushRule('global', 'room', roomId, {
|
||||||
|
actions: [
|
||||||
|
'dont_notify',
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
// https://matrix.org/jira/browse/SPEC-400
|
||||||
|
promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true));
|
||||||
|
} else if ('all_messages_loud') {
|
||||||
|
promises.push(cli.addPushRule('global', 'room', roomId, {
|
||||||
|
actions: [
|
||||||
|
'notify',
|
||||||
|
{
|
||||||
|
set_tweak: 'sound',
|
||||||
|
value: 'default',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
// https://matrix.org/jira/browse/SPEC-400
|
||||||
|
promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOverrideMuteRule(roomId) {
|
||||||
|
for (const rule of MatrixClientPeg.get().pushRules['global'].override) {
|
||||||
|
if (isRuleForRoom(roomId, rule)) {
|
||||||
|
if (isMuteRule(rule) && rule.enabled) {
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRuleForRoom(roomId, rule) {
|
||||||
|
if (rule.conditions.length !== 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const cond = rule.conditions[0];
|
||||||
|
if (
|
||||||
|
cond.kind == 'event_match' &&
|
||||||
|
cond.key == 'room_id' &&
|
||||||
|
cond.pattern == roomId
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMuteRule(rule) {
|
||||||
|
return (
|
||||||
|
rule.actions.length == 1 &&
|
||||||
|
rule.actions[0] == 'dont_notify'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -34,8 +34,10 @@ class ScalarAuthClient {
|
||||||
defer.reject(err);
|
defer.reject(err);
|
||||||
} else if (response.statusCode / 100 !== 2) {
|
} else if (response.statusCode / 100 !== 2) {
|
||||||
defer.reject({statusCode: response.statusCode});
|
defer.reject({statusCode: response.statusCode});
|
||||||
|
} else if (!body || !body.scalar_token) {
|
||||||
|
defer.reject(new Error("Missing scalar_token in response"));
|
||||||
} else {
|
} else {
|
||||||
defer.resolve(body.access_token);
|
defer.resolve(body.scalar_token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ CommandEntry.fromCommands = function(commandArray) {
|
||||||
|
|
||||||
class MemberEntry extends Entry {
|
class MemberEntry extends Entry {
|
||||||
constructor(member) {
|
constructor(member) {
|
||||||
super(member.name || member.userId);
|
super((member.name || member.userId).replace(' (IRC)', ''));
|
||||||
this.member = member;
|
this.member = member;
|
||||||
this.kind = 'member';
|
this.kind = 'member';
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ module.exports = React.createClass({
|
||||||
return (
|
return (
|
||||||
<span className="mx_MFileBody">
|
<span className="mx_MFileBody">
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
<a href={cli.mxcUrlToHttp(content.url)} target="_blank" rel="noopener">
|
||||||
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
||||||
Download {text}
|
Download {text}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -134,7 +134,7 @@ module.exports = React.createClass({
|
||||||
onMouseLeave={this.onImageLeave} />
|
onMouseLeave={this.onImageLeave} />
|
||||||
</a>
|
</a>
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
<a href={cli.mxcUrlToHttp(content.url)} target="_blank" rel="noopener">
|
||||||
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
||||||
Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" })
|
Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" })
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -123,7 +123,7 @@ module.exports = React.createClass({
|
||||||
<div className="mx_LinkPreviewWidget" >
|
<div className="mx_LinkPreviewWidget" >
|
||||||
{ img }
|
{ img }
|
||||||
<div className="mx_LinkPreviewWidget_caption">
|
<div className="mx_LinkPreviewWidget_caption">
|
||||||
<div className="mx_LinkPreviewWidget_title"><a href={ this.props.link } target="_blank">{ p["og:title"] }</a></div>
|
<div className="mx_LinkPreviewWidget_title"><a href={ this.props.link } target="_blank" rel="noopener">{ p["og:title"] }</a></div>
|
||||||
<div className="mx_LinkPreviewWidget_siteName">{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }</div>
|
<div className="mx_LinkPreviewWidget_siteName">{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }</div>
|
||||||
<div className="mx_LinkPreviewWidget_description" ref="description">
|
<div className="mx_LinkPreviewWidget_description" ref="description">
|
||||||
{ p["og:description"] }
|
{ p["og:description"] }
|
||||||
|
|
|
@ -67,6 +67,11 @@ module.exports = React.createClass({
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this._cancelDeviceList = null;
|
this._cancelDeviceList = null;
|
||||||
|
|
||||||
|
// only display the devices list if our client supports E2E *and* the
|
||||||
|
// feature is enabled in the user settings
|
||||||
|
this._enableDevices = MatrixClientPeg.get().isCryptoEnabled() &&
|
||||||
|
UserSettingsStore.isFeatureEnabled("e2e_encryption");
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
existingOneToOneRoomId: this.getExistingOneToOneRoomId()
|
existingOneToOneRoomId: this.getExistingOneToOneRoomId()
|
||||||
});
|
});
|
||||||
|
@ -147,6 +152,10 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeviceVerificationChanged: function(userId, device) {
|
onDeviceVerificationChanged: function(userId, device) {
|
||||||
|
if (!this._enableDevices) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (userId == this.props.member.userId) {
|
if (userId == this.props.member.userId) {
|
||||||
// no need to re-download the whole thing; just update our copy of
|
// no need to re-download the whole thing; just update our copy of
|
||||||
// the list.
|
// the list.
|
||||||
|
@ -170,6 +179,10 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_downloadDeviceList: function(member) {
|
_downloadDeviceList: function(member) {
|
||||||
|
if (!this._enableDevices) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var cancelled = false;
|
var cancelled = false;
|
||||||
this._cancelDeviceList = function() { cancelled = true; }
|
this._cancelDeviceList = function() { cancelled = true; }
|
||||||
|
|
||||||
|
@ -532,7 +545,7 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_renderDevices: function() {
|
_renderDevices: function() {
|
||||||
if (!UserSettingsStore.isFeatureEnabled("e2e_encryption")) {
|
if (!this._enableDevices) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,16 +47,6 @@ module.exports = React.createClass({
|
||||||
tags[tagName] = ['yep'];
|
tags[tagName] = ['yep'];
|
||||||
});
|
});
|
||||||
|
|
||||||
var areNotifsMuted = false;
|
|
||||||
if (!MatrixClientPeg.get().isGuest()) {
|
|
||||||
var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId);
|
|
||||||
if (roomPushRule) {
|
|
||||||
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
|
|
||||||
areNotifsMuted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: this._yankValueFromEvent("m.room.name", "name"),
|
name: this._yankValueFromEvent("m.room.name", "name"),
|
||||||
topic: this._yankValueFromEvent("m.room.topic", "topic"),
|
topic: this._yankValueFromEvent("m.room.topic", "topic"),
|
||||||
|
@ -66,7 +56,6 @@ module.exports = React.createClass({
|
||||||
power_levels_changed: false,
|
power_levels_changed: false,
|
||||||
tags_changed: false,
|
tags_changed: false,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
areNotifsMuted: areNotifsMuted,
|
|
||||||
// isRoomPublished is loaded async in componentWillMount so when the component
|
// isRoomPublished is loaded async in componentWillMount so when the component
|
||||||
// inits, the saved value will always be undefined, however getInitialState()
|
// inits, the saved value will always be undefined, however getInitialState()
|
||||||
// is also called from the saving code so we must return the correct value here
|
// is also called from the saving code so we must return the correct value here
|
||||||
|
@ -188,12 +177,6 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.state.areNotifsMuted !== originalState.areNotifsMuted) {
|
|
||||||
promises.push(MatrixClientPeg.get().setRoomMutePushRule(
|
|
||||||
"global", roomId, this.state.areNotifsMuted
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// power levels
|
// power levels
|
||||||
var powerLevels = this._getPowerLevels();
|
var powerLevels = this._getPowerLevels();
|
||||||
if (powerLevels) {
|
if (powerLevels) {
|
||||||
|
@ -647,12 +630,6 @@ module.exports = React.createClass({
|
||||||
{ tagsSection }
|
{ tagsSection }
|
||||||
|
|
||||||
<div className="mx_RoomSettings_toggles">
|
<div className="mx_RoomSettings_toggles">
|
||||||
<label>
|
|
||||||
<input type="checkbox" disabled={ cli.isGuest() }
|
|
||||||
onChange={this._onToggle.bind(this, "areNotifsMuted", true, false)}
|
|
||||||
defaultChecked={this.state.areNotifsMuted}/>
|
|
||||||
'Mention only' notifications for this room
|
|
||||||
</label>
|
|
||||||
<div className="mx_RoomSettings_settings">
|
<div className="mx_RoomSettings_settings">
|
||||||
<h3>Who can access this room?</h3>
|
<h3>Who can access this room?</h3>
|
||||||
{ inviteGuestWarning }
|
{ inviteGuestWarning }
|
||||||
|
|
|
@ -22,6 +22,7 @@ var dis = require("../../../dispatcher");
|
||||||
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
var ContextualMenu = require('../../structures/ContextualMenu');
|
var ContextualMenu = require('../../structures/ContextualMenu');
|
||||||
|
var RoomNotifs = require('../../../RoomNotifs');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'RoomTile',
|
displayName: 'RoomTile',
|
||||||
|
@ -43,43 +44,41 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
var areNotifsMuted = false;
|
|
||||||
var cli = MatrixClientPeg.get();
|
|
||||||
if (!cli.isGuest()) {
|
|
||||||
var roomPushRule = cli.getRoomPushRule("global", this.props.room.roomId);
|
|
||||||
if (roomPushRule) {
|
|
||||||
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
|
|
||||||
areNotifsMuted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return({
|
return({
|
||||||
hover : false,
|
hover : false,
|
||||||
badgeHover : false,
|
badgeHover : false,
|
||||||
notificationTagMenu: false,
|
notificationTagMenu: false,
|
||||||
roomTagMenu: false,
|
roomTagMenu: false,
|
||||||
areNotifsMuted: areNotifsMuted,
|
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onAction: function(payload) {
|
_shouldShowNotifBadge: function() {
|
||||||
switch (payload.action) {
|
const showBadgeInStates = [RoomNotifs.ALL_MESSAGES, RoomNotifs.ALL_MESSAGES_LOUD];
|
||||||
case 'notification_change':
|
return showBadgeInStates.indexOf(this.state.notifState) > -1;
|
||||||
// Is the notification about this room?
|
},
|
||||||
if (payload.roomId === this.props.room.roomId) {
|
|
||||||
this.setState( { areNotifsMuted : payload.areNotifsMuted });
|
_shouldShowMentionBadge: function() {
|
||||||
}
|
return this.state.notifState != RoomNotifs.MUTE;
|
||||||
break;
|
},
|
||||||
|
|
||||||
|
onAccountData: function(accountDataEvent) {
|
||||||
|
if (accountDataEvent.getType() == 'm.push_rules') {
|
||||||
|
this.setState({
|
||||||
|
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentWillMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
dis.unregister(this.dispatcherRef);
|
var cli = MatrixClientPeg.get();
|
||||||
|
if (cli) {
|
||||||
|
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick: function() {
|
onClick: function() {
|
||||||
|
@ -179,15 +178,19 @@ module.exports = React.createClass({
|
||||||
var notificationCount = this.props.room.getUnreadNotificationCount();
|
var notificationCount = this.props.room.getUnreadNotificationCount();
|
||||||
// var highlightCount = this.props.room.getUnreadNotificationCount("highlight");
|
// var highlightCount = this.props.room.getUnreadNotificationCount("highlight");
|
||||||
|
|
||||||
|
const notifBadges = notificationCount > 0 && this._shouldShowNotifBadge();
|
||||||
|
const mentionBadges = this.props.highlight && this._shouldShowMentionBadge();
|
||||||
|
const badges = notifBadges || mentionBadges;
|
||||||
|
|
||||||
var classes = classNames({
|
var classes = classNames({
|
||||||
'mx_RoomTile': true,
|
'mx_RoomTile': true,
|
||||||
'mx_RoomTile_selected': this.props.selected,
|
'mx_RoomTile_selected': this.props.selected,
|
||||||
'mx_RoomTile_unread': this.props.unread,
|
'mx_RoomTile_unread': this.props.unread,
|
||||||
'mx_RoomTile_unreadNotify': notificationCount > 0 && !this.state.areNotifsMuted,
|
'mx_RoomTile_unreadNotify': notifBadges,
|
||||||
'mx_RoomTile_highlight': this.props.highlight,
|
'mx_RoomTile_highlight': mentionBadges,
|
||||||
'mx_RoomTile_invited': (me && me.membership == 'invite'),
|
'mx_RoomTile_invited': (me && me.membership == 'invite'),
|
||||||
'mx_RoomTile_notificationTagMenu': this.state.notificationTagMenu,
|
'mx_RoomTile_notificationTagMenu': this.state.notificationTagMenu,
|
||||||
'mx_RoomTile_noBadges': !(this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted))
|
'mx_RoomTile_noBadges': !badges,
|
||||||
});
|
});
|
||||||
|
|
||||||
var avatarClasses = classNames({
|
var avatarClasses = classNames({
|
||||||
|
@ -214,7 +217,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
if (this.state.badgeHover || this.state.notificationTagMenu) {
|
if (this.state.badgeHover || this.state.notificationTagMenu) {
|
||||||
badgeContent = "\u00B7\u00B7\u00B7";
|
badgeContent = "\u00B7\u00B7\u00B7";
|
||||||
} else if (this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted)) {
|
} else if (badges) {
|
||||||
var limitedCount = (notificationCount > 99) ? '99+' : notificationCount;
|
var limitedCount = (notificationCount > 99) ? '99+' : notificationCount;
|
||||||
badgeContent = notificationCount ? limitedCount : '!';
|
badgeContent = notificationCount ? limitedCount : '!';
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,7 +233,7 @@ module.exports = React.createClass({
|
||||||
var nameClasses = classNames({
|
var nameClasses = classNames({
|
||||||
'mx_RoomTile_name': true,
|
'mx_RoomTile_name': true,
|
||||||
'mx_RoomTile_invite': this.props.isInvite,
|
'mx_RoomTile_invite': this.props.isInvite,
|
||||||
'mx_RoomTile_badgeShown': this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted) || this.state.badgeHover || this.state.notificationTagMenu,
|
'mx_RoomTile_badgeShown': badges || this.state.badgeHover || this.state.notificationTagMenu,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.props.selected) {
|
if (this.props.selected) {
|
||||||
|
|
|
@ -137,6 +137,10 @@ matrixLinkify.options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
linkAttributes: {
|
||||||
|
rel: 'noopener',
|
||||||
|
},
|
||||||
|
|
||||||
target: function(href, type) {
|
target: function(href, type) {
|
||||||
if (type === 'url') {
|
if (type === 'url') {
|
||||||
if (href.match(matrixLinkify.VECTOR_URL_PATTERN)) {
|
if (href.match(matrixLinkify.VECTOR_URL_PATTERN)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue