Merge pull request #2998 from matrix-org/jryans/clamp-reaction-senders

Limit reaction sender tooltip to 6 people
This commit is contained in:
J. Ryan Stinnett 2019-05-20 16:33:26 +01:00 committed by GitHub
commit db73e641ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 36 deletions

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -13,11 +14,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import sdk from '../../../index'; import sdk from '../../../index';
const MemberAvatar = require('../avatars/MemberAvatar.js'); import MemberAvatar from '../avatars/MemberAvatar';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'MemberEventListSummary', displayName: 'MemberEventListSummary',
@ -105,7 +108,7 @@ module.exports = React.createClass({
); );
}); });
const desc = this._renderCommaSeparatedList(descs); const desc = formatCommaSeparatedList(descs);
return _t('%(nameList)s %(transitionList)s', { nameList: nameList, transitionList: desc }); return _t('%(nameList)s %(transitionList)s', { nameList: nameList, transitionList: desc });
}); });
@ -132,7 +135,7 @@ module.exports = React.createClass({
* included before "and [n] others". * included before "and [n] others".
*/ */
_renderNameList: function(users) { _renderNameList: function(users) {
return this._renderCommaSeparatedList(users, this.props.summaryLength); return formatCommaSeparatedList(users, this.props.summaryLength);
}, },
/** /**
@ -283,35 +286,6 @@ module.exports = React.createClass({
return res; return res;
}, },
/**
* Constructs a written English string representing `items`, with an optional limit on
* the number of items included in the result. If specified and if the length of
*`items` is greater than the limit, the string "and n others" will be appended onto
* the result.
* If `items` is empty, returns the empty string. If there is only one item, return
* it.
* @param {string[]} items the items to construct a string from.
* @param {number?} itemLimit the number by which to limit the list.
* @returns {string} a string constructed by joining `items` with a comma between each
* item, but with the last item appended as " and [lastItem]".
*/
_renderCommaSeparatedList(items, itemLimit) {
const remaining = itemLimit === undefined ? 0 : Math.max(
items.length - itemLimit, 0,
);
if (items.length === 0) {
return "";
} else if (items.length === 1) {
return items[0];
} else if (remaining > 0) {
items = items.slice(0, itemLimit);
return _t("%(items)s and %(count)s others", { items: items.join(', '), count: remaining } );
} else {
const lastItem = items.pop();
return _t("%(items)s and %(lastItem)s", { items: items.join(', '), lastItem: lastItem });
}
},
_renderAvatars: function(roomMembers) { _renderAvatars: function(roomMembers) {
const avatars = roomMembers.slice(0, this.props.avatarsMaxLength).map((m) => { const avatars = roomMembers.slice(0, this.props.avatarsMaxLength).map((m) => {
return ( return (

View file

@ -21,6 +21,7 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index'; import sdk from '../../../index';
import { unicodeToShort } from '../../../HtmlUtils'; import { unicodeToShort } from '../../../HtmlUtils';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
export default class ReactionsRowButtonTooltip extends React.PureComponent { export default class ReactionsRowButtonTooltip extends React.PureComponent {
static propTypes = { static propTypes = {
@ -54,7 +55,7 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent {
{ {
reactors: () => { reactors: () => {
return <div className="mx_ReactionsRowButtonTooltip_senders"> return <div className="mx_ReactionsRowButtonTooltip_senders">
{senders.join(", ")} {formatCommaSeparatedList(senders, 6)}
</div>; </div>;
}, },
reactedWith: (sub) => { reactedWith: (sub) => {

View file

@ -253,6 +253,9 @@
"This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.", "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.",
"Please <a>contact your service administrator</a> to continue using the service.": "Please <a>contact your service administrator</a> to continue using the service.", "Please <a>contact your service administrator</a> to continue using the service.": "Please <a>contact your service administrator</a> to continue using the service.",
"Unable to connect to Homeserver. Retrying...": "Unable to connect to Homeserver. Retrying...", "Unable to connect to Homeserver. Retrying...": "Unable to connect to Homeserver. Retrying...",
"%(items)s and %(count)s others|other": "%(items)s and %(count)s others",
"%(items)s and %(count)s others|one": "%(items)s and one other",
"%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s",
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions", "Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
"Not a valid Riot keyfile": "Not a valid Riot keyfile", "Not a valid Riot keyfile": "Not a valid Riot keyfile",
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?", "Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
@ -1046,9 +1049,6 @@
"%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)schanged their avatar", "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)schanged their avatar",
"%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)schanged their avatar %(count)s times", "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)schanged their avatar %(count)s times",
"%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)schanged their avatar", "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)schanged their avatar",
"%(items)s and %(count)s others|other": "%(items)s and %(count)s others",
"%(items)s and %(count)s others|one": "%(items)s and one other",
"%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s",
"collapse": "collapse", "collapse": "collapse",
"expand": "expand", "expand": "expand",
"Power level": "Power level", "Power level": "Power level",

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -14,6 +15,8 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { _t } from '../languageHandler';
/** /**
* formats numbers to fit into ~3 characters, suitable for badge counts * formats numbers to fit into ~3 characters, suitable for badge counts
* e.g: 999, 9.9K, 99K, 0.9M, 9.9M, 99M, 0.9B, 9.9B * e.g: 999, 9.9K, 99K, 0.9M, 9.9M, 99M, 0.9B, 9.9B
@ -63,3 +66,31 @@ export function getUserNameColorClass(userId) {
const colorNumber = (hashCode(userId) % 8) + 1; const colorNumber = (hashCode(userId) % 8) + 1;
return `mx_Username_color${colorNumber}`; return `mx_Username_color${colorNumber}`;
} }
/**
* Constructs a written English string representing `items`, with an optional
* limit on the number of items included in the result. If specified and if the
* length of `items` is greater than the limit, the string "and n others" will
* be appended onto the result. If `items` is empty, returns the empty string.
* If there is only one item, return it.
* @param {string[]} items the items to construct a string from.
* @param {number?} itemLimit the number by which to limit the list.
* @returns {string} a string constructed by joining `items` with a comma
* between each item, but with the last item appended as " and [lastItem]".
*/
export function formatCommaSeparatedList(items, itemLimit) {
const remaining = itemLimit === undefined ? 0 : Math.max(
items.length - itemLimit, 0,
);
if (items.length === 0) {
return "";
} else if (items.length === 1) {
return items[0];
} else if (remaining > 0) {
items = items.slice(0, itemLimit);
return _t("%(items)s and %(count)s others", { items: items.join(', '), count: remaining } );
} else {
const lastItem = items.pop();
return _t("%(items)s and %(lastItem)s", { items: items.join(', '), lastItem: lastItem });
}
}