[build] upgrade eslint to 9.37.0 (#88)

Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/88
Co-authored-by: Zoë Bijl <moiety@noreply.codeberg.org>
Co-committed-by: Zoë Bijl <moiety@noreply.codeberg.org>
This commit is contained in:
Zoë Bijl
2025-10-12 13:42:02 +02:00
committed by tobi
parent 75d7a62693
commit 1ff70886a1
975 changed files with 22196 additions and 21964 deletions
@@ -1,55 +1,55 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import PropTypes from "prop-types";
import { PureComponent } from "react";
import { defineMessages, injectIntl } from 'react-intl';
import { defineMessages, injectIntl } from "react-intl";
import classNames from 'classnames';
import classNames from "classnames";
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import ImmutablePropTypes from "react-immutable-proptypes";
import { connect } from "react-redux";
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from "mastodon/permissions";
import { IconButton } from '../../../components/icon_button';
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
import { me } from '../../../initial_state';
import { IconButton } from "../../../components/icon_button";
import DropdownMenuContainer from "../../../containers/dropdown_menu_container";
import { me } from "../../../initial_state";
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
edit: { id: 'status.edit', defaultMessage: 'Edit' },
direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' },
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
reply: { id: 'status.reply', defaultMessage: 'Reply' },
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' },
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
favourite: { id: 'status.favourite', defaultMessage: 'Favorite' },
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
more: { id: 'status.more', defaultMessage: 'More' },
mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
block: { id: 'status.block', defaultMessage: 'Block @{name}' },
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
share: { id: 'status.share', defaultMessage: 'Share' },
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
embed: { id: 'status.embed', defaultMessage: 'Embed' },
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to post' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
delete: { id: "status.delete", defaultMessage: "Delete" },
redraft: { id: "status.redraft", defaultMessage: "Delete & re-draft" },
edit: { id: "status.edit", defaultMessage: "Edit" },
direct: { id: "status.direct", defaultMessage: "Privately mention @{name}" },
mention: { id: "status.mention", defaultMessage: "Mention @{name}" },
reply: { id: "status.reply", defaultMessage: "Reply" },
reblog: { id: "status.reblog", defaultMessage: "Boost" },
reblog_private: { id: "status.reblog_private", defaultMessage: "Boost with original visibility" },
cancel_reblog_private: { id: "status.cancel_reblog_private", defaultMessage: "Unboost" },
cannot_reblog: { id: "status.cannot_reblog", defaultMessage: "This post cannot be boosted" },
favourite: { id: "status.favourite", defaultMessage: "Favorite" },
bookmark: { id: "status.bookmark", defaultMessage: "Bookmark" },
more: { id: "status.more", defaultMessage: "More" },
mute: { id: "status.mute", defaultMessage: "Mute @{name}" },
muteConversation: { id: "status.mute_conversation", defaultMessage: "Mute conversation" },
unmuteConversation: { id: "status.unmute_conversation", defaultMessage: "Unmute conversation" },
block: { id: "status.block", defaultMessage: "Block @{name}" },
report: { id: "status.report", defaultMessage: "Report @{name}" },
share: { id: "status.share", defaultMessage: "Share" },
pin: { id: "status.pin", defaultMessage: "Pin on profile" },
unpin: { id: "status.unpin", defaultMessage: "Unpin from profile" },
embed: { id: "status.embed", defaultMessage: "Embed" },
admin_account: { id: "status.admin_account", defaultMessage: "Open moderation interface for @{name}" },
admin_status: { id: "status.admin_status", defaultMessage: "Open this post in the moderation interface" },
admin_domain: { id: "status.admin_domain", defaultMessage: "Open moderation interface for {domain}" },
copy: { id: "status.copy", defaultMessage: "Copy link to post" },
blockDomain: { id: "account.block_domain", defaultMessage: "Block domain {domain}" },
unblockDomain: { id: "account.unblock_domain", defaultMessage: "Unblock domain {domain}" },
unmute: { id: "account.unmute", defaultMessage: "Unmute @{name}" },
unblock: { id: "account.unblock", defaultMessage: "Unblock @{name}" },
openOriginalPage: { id: "account.open_original_page", defaultMessage: "Open original page" },
});
const mapStateToProps = (state, { status }) => ({
relationship: state.getIn(['relationships', status.getIn(['account', 'id'])]),
relationship: state.getIn(["relationships", status.getIn(["account", "id"])]),
});
class ActionBar extends PureComponent {
@@ -112,18 +112,18 @@ class ActionBar extends PureComponent {
};
handleDirectClick = () => {
this.props.onDirect(this.props.status.get('account'), this.context.router.history);
this.props.onDirect(this.props.status.get("account"), this.context.router.history);
};
handleMentionClick = () => {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
this.props.onMention(this.props.status.get("account"), this.context.router.history);
};
handleMuteClick = () => {
const { status, relationship, onMute, onUnmute } = this.props;
const account = status.get('account');
const account = status.get("account");
if (relationship && relationship.get('muting')) {
if (relationship && relationship.get("muting")) {
onUnmute(account);
} else {
onMute(account);
@@ -132,9 +132,9 @@ class ActionBar extends PureComponent {
handleBlockClick = () => {
const { status, relationship, onBlock, onUnblock } = this.props;
const account = status.get('account');
const account = status.get("account");
if (relationship && relationship.get('blocking')) {
if (relationship && relationship.get("blocking")) {
onUnblock(account);
} else {
onBlock(status);
@@ -143,16 +143,16 @@ class ActionBar extends PureComponent {
handleBlockDomain = () => {
const { status, onBlockDomain } = this.props;
const account = status.get('account');
const account = status.get("account");
onBlockDomain(account.get('acct').split('@')[1]);
onBlockDomain(account.get("acct").split("@")[1]);
};
handleUnblockDomain = () => {
const { status, onUnblockDomain } = this.props;
const account = status.get('account');
const account = status.get("account");
onUnblockDomain(account.get('acct').split('@')[1]);
onUnblockDomain(account.get("acct").split("@")[1]);
};
handleConversationMuteClick = () => {
@@ -169,7 +169,7 @@ class ActionBar extends PureComponent {
handleShare = () => {
navigator.share({
url: this.props.status.get('url'),
url: this.props.status.get("url"),
});
};
@@ -178,7 +178,7 @@ class ActionBar extends PureComponent {
};
handleCopy = () => {
const url = this.props.status.get('url');
const url = this.props.status.get("url");
navigator.clipboard.writeText(url);
};
@@ -186,22 +186,22 @@ class ActionBar extends PureComponent {
const { status, relationship, intl } = this.props;
const { signedIn, permissions } = this.context.identity;
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility'));
const mutingConversation = status.get('muted');
const account = status.get('account');
const writtenByMe = status.getIn(['account', 'id']) === me;
const isRemote = status.getIn(['account', 'username']) !== status.getIn(['account', 'acct']);
const publicStatus = ["public", "unlisted"].includes(status.get("visibility"));
const pinnableStatus = ["public", "unlisted", "private"].includes(status.get("visibility"));
const mutingConversation = status.get("muted");
const account = status.get("account");
const writtenByMe = status.getIn(["account", "id"]) === me;
const isRemote = status.getIn(["account", "username"]) !== status.getIn(["account", "acct"]);
let menu = [];
if (publicStatus && isRemote) {
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: status.get('url') });
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: status.get("url") });
}
menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
if (publicStatus && 'share' in navigator) {
if (publicStatus && "share" in navigator) {
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShare });
}
@@ -214,7 +214,7 @@ class ActionBar extends PureComponent {
if (writtenByMe) {
if (pinnableStatus) {
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
menu.push({ text: intl.formatMessage(status.get("pinned") ? messages.unpin : messages.pin), action: this.handlePinClick });
menu.push(null);
}
@@ -224,29 +224,29 @@ class ActionBar extends PureComponent {
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick, dangerous: true });
menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick, dangerous: true });
} else {
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(["account", "username"]) }), action: this.handleMentionClick });
menu.push(null);
if (relationship && relationship.get('muting')) {
menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.handleMuteClick });
if (relationship && relationship.get("muting")) {
menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get("username") }), action: this.handleMuteClick });
} else {
menu.push({ text: intl.formatMessage(messages.mute, { name: account.get('username') }), action: this.handleMuteClick, dangerous: true });
menu.push({ text: intl.formatMessage(messages.mute, { name: account.get("username") }), action: this.handleMuteClick, dangerous: true });
}
if (relationship && relationship.get('blocking')) {
menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get('username') }), action: this.handleBlockClick });
if (relationship && relationship.get("blocking")) {
menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get("username") }), action: this.handleBlockClick });
} else {
menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.handleBlockClick, dangerous: true });
menu.push({ text: intl.formatMessage(messages.block, { name: account.get("username") }), action: this.handleBlockClick, dangerous: true });
}
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport, dangerous: true });
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(["account", "username"]) }), action: this.handleReport, dangerous: true });
if (account.get('acct') !== account.get('username')) {
const domain = account.get('acct').split('@')[1];
if (account.get("acct") !== account.get("username")) {
const domain = account.get("acct").split("@")[1];
menu.push(null);
if (relationship && relationship.get('domain_blocking')) {
if (relationship && relationship.get("domain_blocking")) {
menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain }), action: this.handleUnblockDomain });
} else {
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.handleBlockDomain, dangerous: true });
@@ -256,11 +256,11 @@ class ActionBar extends PureComponent {
if ((permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS || (isRemote && (permissions & PERMISSION_MANAGE_FEDERATION) === PERMISSION_MANAGE_FEDERATION)) {
menu.push(null);
if ((permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) {
menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(["account", "username"]) }), href: `/admin/accounts/${status.getIn(["account", "id"])}` });
menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(["account", "id"])}/statuses/${status.get("id")}` });
}
if (isRemote && (permissions & PERMISSION_MANAGE_FEDERATION) === PERMISSION_MANAGE_FEDERATION) {
const domain = account.get('acct').split('@')[1];
const domain = account.get("acct").split("@")[1];
menu.push({ text: intl.formatMessage(messages.admin_domain, { domain: domain }), href: `/admin/instances/${domain}` });
}
}
@@ -268,16 +268,16 @@ class ActionBar extends PureComponent {
}
let replyIcon;
if (status.get('in_reply_to_id', null) === null) {
replyIcon = 'reply';
if (status.get("in_reply_to_id", null) === null) {
replyIcon = "reply";
} else {
replyIcon = 'reply-all';
replyIcon = "reply-all";
}
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
const reblogPrivate = status.getIn(["account", "id"]) === me && status.get("visibility") === "private";
let reblogTitle;
if (status.get('reblogged')) {
if (status.get("reblogged")) {
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
} else if (publicStatus) {
reblogTitle = intl.formatMessage(messages.reblog);
@@ -289,10 +289,10 @@ class ActionBar extends PureComponent {
return (
<div className='detailed-status__action-bar'>
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get("in_reply_to_account_id") === status.getIn(["account", "id"]) ? "reply" : replyIcon} onClick={this.handleReplyClick} /></div>
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get("reblogged")} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get("favourited")} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get("bookmarked")} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
<div className='detailed-status__action-bar-dropdown'>
<DropdownMenuContainer size={18} icon='ellipsis-h' status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
@@ -1,31 +1,31 @@
import punycode from 'punycode';
import punycode from "punycode";
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import PropTypes from "prop-types";
import { PureComponent } from "react";
import { FormattedMessage } from 'react-intl';
import { FormattedMessage } from "react-intl";
import classNames from 'classnames';
import classNames from "classnames";
import Immutable from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Immutable from "immutable";
import ImmutablePropTypes from "react-immutable-proptypes";
import { Blurhash } from 'mastodon/components/blurhash';
import { Icon } from 'mastodon/components/icon';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import { useBlurhash } from 'mastodon/initial_state';
import { Blurhash } from "mastodon/components/blurhash";
import { Icon } from "mastodon/components/icon";
import { RelativeTimestamp } from "mastodon/components/relative_timestamp";
import { useBlurhash } from "mastodon/initial_state";
const IDNA_PREFIX = 'xn--';
const IDNA_PREFIX = "xn--";
const decodeIDNA = domain => {
return domain
.split('.')
.split(".")
.map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)
.join('.');
.join(".");
};
const getHostname = url => {
const parser = document.createElement('a');
const parser = document.createElement("a");
parser.href = url;
return parser.hostname;
};
@@ -33,21 +33,21 @@ const getHostname = url => {
const domParser = new DOMParser();
const addAutoPlay = html => {
const document = domParser.parseFromString(html, 'text/html').documentElement;
const iframe = document.querySelector('iframe');
const document = domParser.parseFromString(html, "text/html").documentElement;
const iframe = document.querySelector("iframe");
if (iframe) {
if (iframe.src.indexOf('?') !== -1) {
iframe.src += '&';
if (iframe.src.indexOf("?") !== -1) {
iframe.src += "&";
} else {
iframe.src += '?';
iframe.src += "?";
}
iframe.src += 'autoplay=1&auto_play=1';
iframe.src += "autoplay=1&auto_play=1";
// DOM parser creates html/body elements around original HTML fragment,
// so we need to get innerHTML out of the body and not the entire document
return document.querySelector('body').innerHTML;
return document.querySelector("body").innerHTML;
}
return html;
@@ -78,11 +78,11 @@ export default class Card extends PureComponent {
}
componentDidMount () {
window.addEventListener('resize', this.handleResize, { passive: true });
window.addEventListener("resize", this.handleResize, { passive: true });
}
componentWillUnmount () {
window.removeEventListener('resize', this.handleResize);
window.removeEventListener("resize", this.handleResize);
}
handleEmbedClick = () => {
@@ -105,14 +105,14 @@ export default class Card extends PureComponent {
renderVideo () {
const { card } = this.props;
const content = { __html: addAutoPlay(card.get('html')) };
const content = { __html: addAutoPlay(card.get("html")) };
return (
<div
ref={this.setRef}
className='status-card__image status-card-video'
dangerouslySetInnerHTML={content}
style={{ aspectRatio: '16 / 9' }}
style={{ aspectRatio: "16 / 9" }}
/>
);
}
@@ -125,32 +125,32 @@ export default class Card extends PureComponent {
return null;
}
const provider = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name');
const interactive = card.get('type') === 'video';
const language = card.get('language') || '';
const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive;
const provider = card.get("provider_name").length === 0 ? decodeIDNA(getHostname(card.get("url"))) : card.get("provider_name");
const interactive = card.get("type") === "video";
const language = card.get("language") || "";
const largeImage = (card.get("image")?.length > 0 && card.get("width") > card.get("height")) || interactive;
const description = (
<div className='status-card__content'>
<span className='status-card__host'>
<span lang={language}>{provider}</span>
{card.get('published_at') && <> · <RelativeTimestamp timestamp={card.get('published_at')} /></>}
{card.get("published_at") && <> · <RelativeTimestamp timestamp={card.get("published_at")} /></>}
</span>
<strong className='status-card__title' title={card.get('title')} lang={language}>{card.get('title')}</strong>
<strong className='status-card__title' title={card.get("title")} lang={language}>{card.get("title")}</strong>
{card.get('author_name').length > 0 ? <span className='status-card__author'><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{card.get('author_name')}</strong> }} /></span> : <span className='status-card__description'>{card.get('description')}</span>}
{card.get("author_name").length > 0 ? <span className='status-card__author'><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{card.get("author_name")}</strong> }} /></span> : <span className='status-card__description'>{card.get("description")}</span>}
</div>
);
const thumbnailStyle = {
visibility: revealed ? null : 'hidden',
visibility: revealed ? null : "hidden",
};
if (largeImage && card.get('type') === 'video') {
thumbnailStyle.aspectRatio = `16 / 9`;
if (largeImage && card.get("type") === "video") {
thumbnailStyle.aspectRatio = "16 / 9";
} else if (largeImage) {
thumbnailStyle.aspectRatio = '1.91 / 1';
thumbnailStyle.aspectRatio = "1.91 / 1";
} else {
thumbnailStyle.aspectRatio = 1;
}
@@ -159,16 +159,16 @@ export default class Card extends PureComponent {
let canvas = (
<Blurhash
className={classNames('status-card__image-preview', {
'status-card__image-preview--hidden': revealed && this.state.previewLoaded,
className={classNames("status-card__image-preview", {
"status-card__image-preview--hidden": revealed && this.state.previewLoaded,
})}
hash={card.get('blurhash')}
hash={card.get("blurhash")}
dummy={!useBlurhash}
/>
);
const thumbnailDescription = card.get('image_description');
const thumbnail = <img src={card.get('image')} alt={thumbnailDescription} title={thumbnailDescription} lang={language} style={thumbnailStyle} onLoad={this.handleImageLoad} className='status-card__image-image' />;
const thumbnailDescription = card.get("image_description");
const thumbnail = <img src={card.get("image")} alt={thumbnailDescription} title={thumbnailDescription} lang={language} style={thumbnailStyle} onLoad={this.handleImageLoad} className='status-card__image-image' />;
let spoilerButton = (
<button type='button' onClick={this.handleReveal} className='spoiler-button__overlay'>
@@ -180,7 +180,7 @@ export default class Card extends PureComponent {
);
spoilerButton = (
<div className={classNames('spoiler-button', { 'spoiler-button--minified': revealed })}>
<div className={classNames("spoiler-button", { "spoiler-button--minified": revealed })}>
{spoilerButton}
</div>
);
@@ -198,7 +198,7 @@ export default class Card extends PureComponent {
<div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
<div>
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' /></button>
<a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' /></a>
<a href={card.get("url")} target='_blank' rel='noopener noreferrer'><Icon id='external-link' /></a>
</div>
</div>
) : spoilerButton}
@@ -207,12 +207,12 @@ export default class Card extends PureComponent {
}
return (
<div className={classNames('status-card', { expanded: largeImage })} ref={this.setRef} onClick={revealed ? null : this.handleReveal} role={revealed ? 'button' : null}>
<div className={classNames("status-card", { expanded: largeImage })} ref={this.setRef} onClick={revealed ? null : this.handleReveal} role={revealed ? "button" : null}>
{embed}
<a href={card.get('url')} target='_blank' rel='noopener noreferrer'>{description}</a>
<a href={card.get("url")} target='_blank' rel='noopener noreferrer'>{description}</a>
</div>
);
} else if (card.get('image')) {
} else if (card.get("image")) {
embed = (
<div className='status-card__image'>
{canvas}
@@ -228,7 +228,7 @@ export default class Card extends PureComponent {
}
return (
<a href={card.get('url')} className={classNames('status-card', { expanded: largeImage })} target='_blank' rel='noopener noreferrer' ref={this.setRef}>
<a href={card.get("url")} className={classNames("status-card", { expanded: largeImage })} target='_blank' rel='noopener noreferrer' ref={this.setRef}>
{embed}
{description}
</a>
@@ -1,34 +1,34 @@
import PropTypes from 'prop-types';
import PropTypes from "prop-types";
import { injectIntl, defineMessages, FormattedDate, FormattedMessage } from 'react-intl';
import { injectIntl, defineMessages, FormattedDate, FormattedMessage } from "react-intl";
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import classNames from "classnames";
import { Link } from "react-router-dom";
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from "react-immutable-proptypes";
import ImmutablePureComponent from "react-immutable-pure-component";
import { AnimatedNumber } from 'mastodon/components/animated_number';
import EditedTimestamp from 'mastodon/components/edited_timestamp';
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
import { Icon } from 'mastodon/components/icon';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import { AnimatedNumber } from "mastodon/components/animated_number";
import EditedTimestamp from "mastodon/components/edited_timestamp";
import { getHashtagBarForStatus } from "mastodon/components/hashtag_bar";
import { Icon } from "mastodon/components/icon";
import PictureInPicturePlaceholder from "mastodon/components/picture_in_picture_placeholder";
import { Avatar } from '../../../components/avatar';
import { DisplayName } from '../../../components/display_name';
import MediaGallery from '../../../components/media_gallery';
import StatusContent from '../../../components/status_content';
import Audio from '../../audio';
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
import Video from '../../video';
import { Avatar } from "../../../components/avatar";
import { DisplayName } from "../../../components/display_name";
import MediaGallery from "../../../components/media_gallery";
import StatusContent from "../../../components/status_content";
import Audio from "../../audio";
import scheduleIdleTask from "../../ui/util/schedule_idle_task";
import Video from "../../video";
import Card from './card';
import Card from "./card";
const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
public_short: { id: "privacy.public.short", defaultMessage: "Public" },
unlisted_short: { id: "privacy.unlisted.short", defaultMessage: "Unlisted" },
private_short: { id: "privacy.private.short", defaultMessage: "Followers only" },
direct_short: { id: "privacy.direct.short", defaultMessage: "Mentioned people only" },
});
class DetailedStatus extends ImmutablePureComponent {
@@ -62,14 +62,14 @@ class DetailedStatus extends ImmutablePureComponent {
handleAccountClick = (e) => {
if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.context.router) {
e.preventDefault();
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
this.context.router.history.push(`/@${this.props.status.getIn(["account", "acct"])}`);
}
e.stopPropagation();
};
handleOpenVideo = (options) => {
this.props.onOpenVideo(this.props.status.getIn(['media_attachments', 0]), options);
this.props.onOpenVideo(this.props.status.getIn(["media_attachments", 0]), options);
};
handleExpandedToggle = () => {
@@ -100,13 +100,13 @@ class DetailedStatus extends ImmutablePureComponent {
let href;
if (e.target.nodeName !== 'A') {
if (e.target.nodeName !== "A") {
href = e.target.parentNode.href;
} else {
href = e.target.href;
}
window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
window.open(href, "mastodon-intent", "width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes");
};
handleTranslate = () => {
@@ -117,88 +117,88 @@ class DetailedStatus extends ImmutablePureComponent {
_properStatus () {
const { status } = this.props;
if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
return status.get('reblog');
if (status.get("reblog", null) !== null && typeof status.get("reblog") === "object") {
return status.get("reblog");
} else {
return status;
}
}
getAttachmentAspectRatio () {
const attachments = this._properStatus().get('media_attachments');
const attachments = this._properStatus().get("media_attachments");
if (attachments.getIn([0, 'type']) === 'video') {
return `${attachments.getIn([0, 'meta', 'original', 'width'])} / ${attachments.getIn([0, 'meta', 'original', 'height'])}`;
} else if (attachments.getIn([0, 'type']) === 'audio') {
return '16 / 9';
if (attachments.getIn([0, "type"]) === "video") {
return `${attachments.getIn([0, "meta", "original", "width"])} / ${attachments.getIn([0, "meta", "original", "height"])}`;
} else if (attachments.getIn([0, "type"]) === "audio") {
return "16 / 9";
} else {
return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2';
return (attachments.size === 1 && attachments.getIn([0, "meta", "small", "aspect"])) ? attachments.getIn([0, "meta", "small", "aspect"]) : "3 / 2";
}
}
render () {
const status = this._properStatus();
const outerStyle = { boxSizing: 'border-box' };
const outerStyle = { boxSizing: "border-box" };
const { intl, compact, pictureInPicture } = this.props;
if (!status) {
return null;
}
let media = '';
let applicationLink = '';
let reblogLink = '';
let reblogIcon = 'retweet';
let favouriteLink = '';
let edited = '';
let media = "";
let applicationLink = "";
let reblogLink;
let reblogIcon = "retweet";
let favouriteLink;
let edited = "";
if (this.props.measureHeight) {
outerStyle.height = `${this.state.height}px`;
}
const language = status.getIn(['translation', 'language']) || status.get('language');
const language = status.getIn(["translation", "language"]) || status.get("language");
if (pictureInPicture.get('inUse')) {
if (pictureInPicture.get("inUse")) {
media = <PictureInPicturePlaceholder aspectRatio={this.getAttachmentAspectRatio()} />;
} else if (status.get('media_attachments').size > 0) {
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
const attachment = status.getIn(['media_attachments', 0]);
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
} else if (status.get("media_attachments").size > 0) {
if (status.getIn(["media_attachments", 0, "type"]) === "audio") {
const attachment = status.getIn(["media_attachments", 0]);
const description = attachment.getIn(["translation", "description"]) || attachment.get("description");
media = (
<Audio
src={attachment.get('url')}
src={attachment.get("url")}
alt={description}
lang={language}
duration={attachment.getIn(['meta', 'original', 'duration'], 0)}
poster={attachment.get('preview_url') || status.getIn(['account', 'avatar_static'])}
backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
sensitive={status.get('sensitive')}
duration={attachment.getIn(["meta", "original", "duration"], 0)}
poster={attachment.get("preview_url") || status.getIn(["account", "avatar_static"])}
backgroundColor={attachment.getIn(["meta", "colors", "background"])}
foregroundColor={attachment.getIn(["meta", "colors", "foreground"])}
accentColor={attachment.getIn(["meta", "colors", "accent"])}
sensitive={status.get("sensitive")}
visible={this.props.showMedia}
blurhash={attachment.get('blurhash')}
blurhash={attachment.get("blurhash")}
height={150}
onToggleVisibility={this.props.onToggleMediaVisibility}
/>
);
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
const attachment = status.getIn(['media_attachments', 0]);
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
} else if (status.getIn(["media_attachments", 0, "type"]) === "video") {
const attachment = status.getIn(["media_attachments", 0]);
const description = attachment.getIn(["translation", "description"]) || attachment.get("description");
media = (
<Video
preview={attachment.get('preview_url')}
frameRate={attachment.getIn(['meta', 'original', 'frame_rate'])}
aspectRatio={`${attachment.getIn(['meta', 'original', 'width'])} / ${attachment.getIn(['meta', 'original', 'height'])}`}
blurhash={attachment.get('blurhash')}
src={attachment.get('url')}
preview={attachment.get("preview_url")}
frameRate={attachment.getIn(["meta", "original", "frame_rate"])}
aspectRatio={`${attachment.getIn(["meta", "original", "width"])} / ${attachment.getIn(["meta", "original", "height"])}`}
blurhash={attachment.get("blurhash")}
src={attachment.get("url")}
alt={description}
lang={language}
width={300}
height={150}
onOpenVideo={this.handleOpenVideo}
sensitive={status.get('sensitive')}
sensitive={status.get("sensitive")}
visible={this.props.showMedia}
onToggleVisibility={this.props.onToggleMediaVisibility}
/>
@@ -207,8 +207,8 @@ class DetailedStatus extends ImmutablePureComponent {
media = (
<MediaGallery
standalone
sensitive={status.get('sensitive')}
media={status.get('media_attachments')}
sensitive={status.get("sensitive")}
media={status.get("media_attachments")}
lang={language}
height={300}
onOpenMedia={this.props.onOpenMedia}
@@ -217,34 +217,34 @@ class DetailedStatus extends ImmutablePureComponent {
/>
);
}
} else if (status.get('spoiler_text').length === 0) {
media = <Card sensitive={status.get('sensitive')} onOpenMedia={this.props.onOpenMedia} card={status.get('card', null)} />;
} else if (status.get("spoiler_text").length === 0) {
media = <Card sensitive={status.get("sensitive")} onOpenMedia={this.props.onOpenMedia} card={status.get("card", null)} />;
}
if (status.get('application')) {
applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
if (status.get("application")) {
applicationLink = <> · <a className='detailed-status__application' href={status.getIn(["application", "website"])} target='_blank' rel='noopener noreferrer'>{status.getIn(["application", "name"])}</a></>;
}
const visibilityIconInfo = {
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
"public": { icon: "globe", text: intl.formatMessage(messages.public_short) },
"unlisted": { icon: "unlock", text: intl.formatMessage(messages.unlisted_short) },
"private": { icon: "lock", text: intl.formatMessage(messages.private_short) },
"direct": { icon: "at", text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
const visibilityIcon = visibilityIconInfo[status.get("visibility")];
const visibilityLink = <> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></>;
if (['private', 'direct'].includes(status.get('visibility'))) {
reblogLink = '';
if (["private", "direct"].includes(status.get("visibility"))) {
reblogLink = "";
} else if (this.context.router) {
reblogLink = (
<>
{' · '}
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
{" · "}
<Link to={`/@${status.getIn(["account", "acct"])}/${status.get("id")}/reblogs`} className='detailed-status__link'>
<Icon id={reblogIcon} />
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
<AnimatedNumber value={status.get("reblogs_count")} />
</span>
</Link>
</>
@@ -252,11 +252,11 @@ class DetailedStatus extends ImmutablePureComponent {
} else {
reblogLink = (
<>
{' · '}
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
{" · "}
<a href={`/interact/${status.get("id")}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id={reblogIcon} />
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
<AnimatedNumber value={status.get("reblogs_count")} />
</span>
</a>
</>
@@ -265,53 +265,53 @@ class DetailedStatus extends ImmutablePureComponent {
if (this.context.router) {
favouriteLink = (
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
<Link to={`/@${status.getIn(["account", "acct"])}/${status.get("id")}/favourites`} className='detailed-status__link'>
<Icon id='star' />
<span className='detailed-status__favorites'>
<AnimatedNumber value={status.get('favourites_count')} />
<AnimatedNumber value={status.get("favourites_count")} />
</span>
</Link>
);
} else {
favouriteLink = (
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
<a href={`/interact/${status.get("id")}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id='star' />
<span className='detailed-status__favorites'>
<AnimatedNumber value={status.get('favourites_count')} />
<AnimatedNumber value={status.get("favourites_count")} />
</span>
</a>
);
}
if (status.get('edited_at')) {
if (status.get("edited_at")) {
edited = (
<>
{' · '}
<EditedTimestamp statusId={status.get('id')} timestamp={status.get('edited_at')} />
{" · "}
<EditedTimestamp statusId={status.get("id")} timestamp={status.get("edited_at")} />
</>
);
}
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;
const expanded = !status.get("hidden") || status.get("spoiler_text").length === 0;
return (
<div style={outerStyle}>
<div ref={this.setRef} className={classNames('detailed-status', { compact })}>
{status.get('visibility') === 'direct' && (
<div ref={this.setRef} className={classNames("detailed-status", { compact })}>
{status.get("visibility") === "direct" && (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
</div>
)}
<a href={`/@${status.getIn(['account', 'acct'])}`} onClick={this.handleAccountClick} className='detailed-status__display-name'>
<div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={46} /></div>
<DisplayName account={status.get('account')} localDomain={this.props.domain} />
<a href={`/@${status.getIn(["account", "acct"])}`} onClick={this.handleAccountClick} className='detailed-status__display-name'>
<div className='detailed-status__display-avatar'><Avatar account={status.get("account")} size={46} /></div>
<DisplayName account={status.get("account")} localDomain={this.props.domain} />
</a>
<StatusContent
status={status}
expanded={!status.get('hidden')}
expanded={!status.get("hidden")}
onExpandedToggle={this.handleExpandedToggle}
onTranslate={this.handleTranslate}
{...statusContentProps}
@@ -322,8 +322,8 @@ class DetailedStatus extends ImmutablePureComponent {
{expanded && hashtagBar}
<div className='detailed-status__meta'>
<a className='detailed-status__datetime' href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} target='_blank' rel='noopener noreferrer'>
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
<a className='detailed-status__datetime' href={`/@${status.getIn(["account", "acct"])}/${status.get("id")}`} target='_blank' rel='noopener noreferrer'>
<FormattedDate value={new Date(status.get("created_at"))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
</a>{edited}{visibilityLink}{applicationLink}{reblogLink} · {favouriteLink}
</div>
</div>
@@ -1,15 +1,15 @@
import { defineMessages, injectIntl } from 'react-intl';
import { defineMessages, injectIntl } from "react-intl";
import { connect } from 'react-redux';
import { connect } from "react-redux";
import { showAlertForError } from '../../../actions/alerts';
import { initBlockModal } from '../../../actions/blocks';
import { initBoostModal } from '../../../actions/boosts';
import { showAlertForError } from "../../../actions/alerts";
import { initBlockModal } from "../../../actions/blocks";
import { initBoostModal } from "../../../actions/boosts";
import {
replyCompose,
mentionCompose,
directCompose,
} from '../../../actions/compose';
} from "../../../actions/compose";
import {
reblog,
favourite,
@@ -17,28 +17,28 @@ import {
unfavourite,
pin,
unpin,
} from '../../../actions/interactions';
import { openModal } from '../../../actions/modal';
import { initMuteModal } from '../../../actions/mutes';
import { initReport } from '../../../actions/reports';
} from "../../../actions/interactions";
import { openModal } from "../../../actions/modal";
import { initMuteModal } from "../../../actions/mutes";
import { initReport } from "../../../actions/reports";
import {
muteStatus,
unmuteStatus,
deleteStatus,
hideStatus,
revealStatus,
} from '../../../actions/statuses';
import { boostModal, deleteModal } from '../../../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../../../selectors';
import DetailedStatus from '../components/detailed_status';
} from "../../../actions/statuses";
import { boostModal, deleteModal } from "../../../initial_state";
import { makeGetStatus, makeGetPictureInPicture } from "../../../selectors";
import DetailedStatus from "../components/detailed_status";
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' },
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
deleteConfirm: { id: "confirmations.delete.confirm", defaultMessage: "Delete" },
deleteMessage: { id: "confirmations.delete.message", defaultMessage: "Are you sure you want to delete this status?" },
redraftConfirm: { id: "confirmations.redraft.confirm", defaultMessage: "Delete & redraft" },
redraftMessage: { id: "confirmations.redraft.message", defaultMessage: "Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned." },
replyConfirm: { id: "confirmations.reply.confirm", defaultMessage: "Reply" },
replyMessage: { id: "confirmations.reply.message", defaultMessage: "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?" },
});
const makeMapStateToProps = () => {
@@ -47,7 +47,7 @@ const makeMapStateToProps = () => {
const mapStateToProps = (state, props) => ({
status: getStatus(state, props),
domain: state.getIn(['meta', 'domain']),
domain: state.getIn(["meta", "domain"]),
pictureInPicture: getPictureInPicture(state, props),
});
@@ -59,9 +59,9 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onReply (status, router) {
dispatch((_, getState) => {
let state = getState();
if (state.getIn(['compose', 'text']).trim().length !== 0) {
if (state.getIn(["compose", "text"]).trim().length !== 0) {
dispatch(openModal({
modalType: 'CONFIRM',
modalType: "CONFIRM",
modalProps: {
message: intl.formatMessage(messages.replyMessage),
confirm: intl.formatMessage(messages.replyConfirm),
@@ -79,7 +79,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
onReblog (status, e) {
if (status.get('reblogged')) {
if (status.get("reblogged")) {
dispatch(unreblog(status));
} else {
if (e.shiftKey || !boostModal) {
@@ -91,7 +91,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
onFavourite (status) {
if (status.get('favourited')) {
if (status.get("favourited")) {
dispatch(unfavourite(status));
} else {
dispatch(favourite(status));
@@ -99,7 +99,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
onPin (status) {
if (status.get('pinned')) {
if (status.get("pinned")) {
dispatch(unpin(status));
} else {
dispatch(pin(status));
@@ -108,9 +108,9 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onEmbed (status) {
dispatch(openModal({
modalType: 'EMBED',
modalType: "EMBED",
modalProps: {
id: status.get('id'),
id: status.get("id"),
onError: error => dispatch(showAlertForError(error)),
},
}));
@@ -118,14 +118,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onDelete (status, history, withRedraft = false) {
if (!deleteModal) {
dispatch(deleteStatus(status.get('id'), history, withRedraft));
dispatch(deleteStatus(status.get("id"), history, withRedraft));
} else {
dispatch(openModal({
modalType: 'CONFIRM',
modalType: "CONFIRM",
modalProps: {
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
onConfirm: () => dispatch(deleteStatus(status.get("id"), history, withRedraft)),
},
}));
}
@@ -141,25 +141,25 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onOpenMedia (media, index, lang) {
dispatch(openModal({
modalType: 'MEDIA',
modalType: "MEDIA",
modalProps: { media, index, lang },
}));
},
onOpenVideo (media, lang, options) {
dispatch(openModal({
modalType: 'VIDEO',
modalType: "VIDEO",
modalProps: { media, lang, options },
}));
},
onBlock (status) {
const account = status.get('account');
const account = status.get("account");
dispatch(initBlockModal(account));
},
onReport (status) {
dispatch(initReport(status.get('account'), status));
dispatch(initReport(status.get("account"), status));
},
onMute (account) {
@@ -167,18 +167,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
onMuteConversation (status) {
if (status.get('muted')) {
dispatch(unmuteStatus(status.get('id')));
if (status.get("muted")) {
dispatch(unmuteStatus(status.get("id")));
} else {
dispatch(muteStatus(status.get('id')));
dispatch(muteStatus(status.get("id")));
}
},
onToggleHidden (status) {
if (status.get('hidden')) {
dispatch(revealStatus(status.get('id')));
if (status.get("hidden")) {
dispatch(revealStatus(status.get("id")));
} else {
dispatch(hideStatus(status.get('id')));
dispatch(hideStatus(status.get("id")));
}
},
+131 -129
View File
@@ -1,38 +1,38 @@
import PropTypes from 'prop-types';
import PropTypes from "prop-types";
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
import classNames from 'classnames';
import { Helmet } from 'react-helmet';
import classNames from "classnames";
import { Helmet } from "react-helmet";
import Immutable from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import Immutable from "immutable";
import ImmutablePropTypes from "react-immutable-proptypes";
import ImmutablePureComponent from "react-immutable-pure-component";
import { connect } from "react-redux";
import { createSelector } from "reselect";
import { HotKeys } from 'react-hotkeys';
import { HotKeys } from "react-hotkeys";
import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import ScrollContainer from 'mastodon/containers/scroll_container';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
import { Icon } from "mastodon/components/icon";
import { LoadingIndicator } from "mastodon/components/loading_indicator";
import ScrollContainer from "mastodon/containers/scroll_container";
import BundleColumnError from "mastodon/features/ui/components/bundle_column_error";
import {
unblockAccount,
unmuteAccount,
} from '../../actions/accounts';
import { initBlockModal } from '../../actions/blocks';
import { initBoostModal } from '../../actions/boosts';
} from "../../actions/accounts";
import { initBlockModal } from "../../actions/blocks";
import { initBoostModal } from "../../actions/boosts";
import {
replyCompose,
mentionCompose,
directCompose,
} from '../../actions/compose';
} from "../../actions/compose";
import {
blockDomain,
unblockDomain,
} from '../../actions/domain_blocks';
} from "../../actions/domain_blocks";
import {
favourite,
unfavourite,
@@ -42,10 +42,10 @@ import {
unreblog,
pin,
unpin,
} from '../../actions/interactions';
import { openModal } from '../../actions/modal';
import { initMuteModal } from '../../actions/mutes';
import { initReport } from '../../actions/reports';
} from "../../actions/interactions";
import { openModal } from "../../actions/modal";
import { initMuteModal } from "../../actions/mutes";
import { initReport } from "../../actions/reports";
import {
fetchStatus,
muteStatus,
@@ -56,30 +56,30 @@ import {
revealStatus,
translateStatus,
undoStatusTranslation,
} from '../../actions/statuses';
import ColumnHeader from '../../components/column_header';
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import StatusContainer from '../../containers/status_container';
import { boostModal, deleteModal } from '../../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
import Column from '../ui/components/column';
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
} from "../../actions/statuses";
import ColumnHeader from "../../components/column_header";
import { textForScreenReader, defaultMediaVisibility } from "../../components/status";
import StatusContainer from "../../containers/status_container";
import { boostModal, deleteModal } from "../../initial_state";
import { makeGetStatus, makeGetPictureInPicture } from "../../selectors";
import Column from "../ui/components/column";
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from "../ui/util/fullscreen";
import ActionBar from './components/action_bar';
import DetailedStatus from './components/detailed_status';
import ActionBar from "./components/action_bar";
import DetailedStatus from "./components/detailed_status";
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.' },
revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
statusTitleWithAttachments: { id: 'status.title.with_attachments', defaultMessage: '{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}' },
detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
deleteConfirm: { id: "confirmations.delete.confirm", defaultMessage: "Delete" },
deleteMessage: { id: "confirmations.delete.message", defaultMessage: "Are you sure you want to delete this status?" },
redraftConfirm: { id: "confirmations.redraft.confirm", defaultMessage: "Delete & redraft" },
redraftMessage: { id: "confirmations.redraft.message", defaultMessage: "Are you sure you want to delete this status and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned." },
revealAll: { id: "status.show_more_all", defaultMessage: "Show more for all" },
hideAll: { id: "status.show_less_all", defaultMessage: "Show less for all" },
statusTitleWithAttachments: { id: "status.title.with_attachments", defaultMessage: "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}" },
detailedStatus: { id: "status.detailed_status", defaultMessage: "Detailed conversation view" },
replyConfirm: { id: "confirmations.reply.confirm", defaultMessage: "Reply" },
replyMessage: { id: "confirmations.reply.message", defaultMessage: "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?" },
blockDomainConfirm: { id: "confirmations.domain_block.confirm", defaultMessage: "Block entire domain" },
});
const makeMapStateToProps = () => {
@@ -88,7 +88,7 @@ const makeMapStateToProps = () => {
const getAncestorsIds = createSelector([
(_, { id }) => id,
state => state.getIn(['contexts', 'inReplyTos']),
state => state.getIn(["contexts", "inReplyTos"]),
], (statusId, inReplyTos) => {
let ancestorsIds = Immutable.List();
ancestorsIds = ancestorsIds.withMutations(mutable => {
@@ -105,8 +105,8 @@ const makeMapStateToProps = () => {
const getDescendantsIds = createSelector([
(_, { id }) => id,
state => state.getIn(['contexts', 'replies']),
state => state.get('statuses'),
state => state.getIn(["contexts", "replies"]),
state => state.get("statuses"),
], (statusId, contextReplies, statuses) => {
let descendantsIds = [];
const ids = [statusId];
@@ -121,15 +121,17 @@ const makeMapStateToProps = () => {
if (replies) {
replies.reverse().forEach(reply => {
if (!ids.includes(reply) && !descendantsIds.includes(reply) && statusId !== reply) ids.push(reply);
if (!ids.includes(reply) && !descendantsIds.includes(reply) && statusId !== reply) {
ids.push(reply);
}
});
}
}
let insertAt = descendantsIds.findIndex((id) => statuses.get(id).get('in_reply_to_account_id') !== statuses.get(id).get('account'));
let insertAt = descendantsIds.findIndex((id) => statuses.get(id).get("in_reply_to_account_id") !== statuses.get(id).get("account"));
if (insertAt !== -1) {
descendantsIds.forEach((id, idx) => {
if (idx > insertAt && statuses.get(id).get('in_reply_to_account_id') === statuses.get(id).get('account')) {
if (idx > insertAt && statuses.get(id).get("in_reply_to_account_id") === statuses.get(id).get("account")) {
descendantsIds.splice(idx, 1);
descendantsIds.splice(insertAt, 0, id);
insertAt += 1;
@@ -147,17 +149,17 @@ const makeMapStateToProps = () => {
let descendantsIds = Immutable.List();
if (status) {
ancestorsIds = getAncestorsIds(state, { id: status.get('in_reply_to_id') });
descendantsIds = getDescendantsIds(state, { id: status.get('id') });
ancestorsIds = getAncestorsIds(state, { id: status.get("in_reply_to_id") });
descendantsIds = getDescendantsIds(state, { id: status.get("id") });
}
return {
isLoading: state.getIn(['statuses', props.params.statusId, 'isLoading']),
isLoading: state.getIn(["statuses", props.params.statusId, "isLoading"]),
status,
ancestorsIds,
descendantsIds,
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
domain: state.getIn(['meta', 'domain']),
askReplyConfirmation: state.getIn(["compose", "text"]).trim().length !== 0,
domain: state.getIn(["meta", "domain"]),
pictureInPicture: getPictureInPicture(state, { id: props.params.statusId }),
};
};
@@ -168,18 +170,18 @@ const makeMapStateToProps = () => {
const truncate = (str, num) => {
const arr = Array.from(str);
if (arr.length > num) {
return arr.slice(0, num).join('') + '…';
return arr.slice(0, num).join("") + "…";
} else {
return str;
}
};
const titleFromStatus = (intl, status) => {
const displayName = status.getIn(['account', 'display_name']);
const username = status.getIn(['account', 'username']);
const displayName = status.getIn(["account", "display_name"]);
const username = status.getIn(["account", "username"]);
const user = displayName.trim().length === 0 ? username : displayName;
const text = status.get('search_index');
const attachmentCount = status.get('media_attachments').size;
const text = status.get("search_index");
const attachmentCount = status.get("media_attachments").size;
return text ? `${user}: "${truncate(text, 30)}"` : intl.formatMessage(messages.statusTitleWithAttachments, { user, attachmentCount });
};
@@ -229,8 +231,8 @@ class Status extends ImmutablePureComponent {
this.props.dispatch(fetchStatus(nextProps.params.statusId));
}
if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) {
this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get('id') });
if (nextProps.status && nextProps.status.get("id") !== this.state.loadedStatusId) {
this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get("id") });
}
}
@@ -243,25 +245,25 @@ class Status extends ImmutablePureComponent {
const { signedIn } = this.context.identity;
if (signedIn) {
if (status.get('favourited')) {
if (status.get("favourited")) {
dispatch(unfavourite(status));
} else {
dispatch(favourite(status));
}
} else {
dispatch(openModal({
modalType: 'INTERACTION',
modalType: "INTERACTION",
modalProps: {
type: 'favourite',
accountId: status.getIn(['account', 'id']),
url: status.get('uri'),
type: "favourite",
accountId: status.getIn(["account", "id"]),
url: status.get("uri"),
},
}));
}
};
handlePin = (status) => {
if (status.get('pinned')) {
if (status.get("pinned")) {
this.props.dispatch(unpin(status));
} else {
this.props.dispatch(pin(status));
@@ -275,7 +277,7 @@ class Status extends ImmutablePureComponent {
if (signedIn) {
if (askReplyConfirmation) {
dispatch(openModal({
modalType: 'CONFIRM',
modalType: "CONFIRM",
modalProps: {
message: intl.formatMessage(messages.replyMessage),
confirm: intl.formatMessage(messages.replyConfirm),
@@ -287,11 +289,11 @@ class Status extends ImmutablePureComponent {
}
} else {
dispatch(openModal({
modalType: 'INTERACTION',
modalType: "INTERACTION",
modalProps: {
type: 'reply',
accountId: status.getIn(['account', 'id']),
url: status.get('uri'),
type: "reply",
accountId: status.getIn(["account", "id"]),
url: status.get("uri"),
},
}));
}
@@ -306,7 +308,7 @@ class Status extends ImmutablePureComponent {
const { signedIn } = this.context.identity;
if (signedIn) {
if (status.get('reblogged')) {
if (status.get("reblogged")) {
dispatch(unreblog(status));
} else {
if ((e && e.shiftKey) || !boostModal) {
@@ -317,18 +319,18 @@ class Status extends ImmutablePureComponent {
}
} else {
dispatch(openModal({
modalType: 'INTERACTION',
modalType: "INTERACTION",
modalProps: {
type: 'reblog',
accountId: status.getIn(['account', 'id']),
url: status.get('uri'),
type: "reblog",
accountId: status.getIn(["account", "id"]),
url: status.get("uri"),
},
}));
}
};
handleBookmarkClick = (status) => {
if (status.get('bookmarked')) {
if (status.get("bookmarked")) {
this.props.dispatch(unbookmark(status));
} else {
this.props.dispatch(bookmark(status));
@@ -339,21 +341,21 @@ class Status extends ImmutablePureComponent {
const { dispatch, intl } = this.props;
if (!deleteModal) {
dispatch(deleteStatus(status.get('id'), history, withRedraft));
dispatch(deleteStatus(status.get("id"), history, withRedraft));
} else {
dispatch(openModal({
modalType: 'CONFIRM',
modalType: "CONFIRM",
modalProps: {
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
onConfirm: () => dispatch(deleteStatus(status.get("id"), history, withRedraft)),
},
}));
}
};
handleEditClick = (status, history) => {
this.props.dispatch(editStatus(status.get('id'), history));
this.props.dispatch(editStatus(status.get("id"), history));
};
handleDirectClick = (account, router) => {
@@ -366,15 +368,15 @@ class Status extends ImmutablePureComponent {
handleOpenMedia = (media, index, lang) => {
this.props.dispatch(openModal({
modalType: 'MEDIA',
modalProps: { statusId: this.props.status.get('id'), media, index, lang },
modalType: "MEDIA",
modalProps: { statusId: this.props.status.get("id"), media, index, lang },
}));
};
handleOpenVideo = (media, lang, options) => {
this.props.dispatch(openModal({
modalType: 'VIDEO',
modalProps: { statusId: this.props.status.get('id'), media, lang, options },
modalType: "VIDEO",
modalProps: { statusId: this.props.status.get("id"), media, lang, options },
}));
};
@@ -383,11 +385,11 @@ class Status extends ImmutablePureComponent {
e.preventDefault();
if (status.get('media_attachments').size > 0) {
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
this.handleOpenVideo(status.getIn(['media_attachments', 0]), { startTime: 0 });
if (status.get("media_attachments").size > 0) {
if (status.getIn(["media_attachments", 0, "type"]) === "video") {
this.handleOpenVideo(status.getIn(["media_attachments", 0]), { startTime: 0 });
} else {
this.handleOpenMedia(status.get('media_attachments'), 0);
this.handleOpenMedia(status.get("media_attachments"), 0);
}
}
};
@@ -397,26 +399,26 @@ class Status extends ImmutablePureComponent {
};
handleConversationMuteClick = (status) => {
if (status.get('muted')) {
this.props.dispatch(unmuteStatus(status.get('id')));
if (status.get("muted")) {
this.props.dispatch(unmuteStatus(status.get("id")));
} else {
this.props.dispatch(muteStatus(status.get('id')));
this.props.dispatch(muteStatus(status.get("id")));
}
};
handleToggleHidden = (status) => {
if (status.get('hidden')) {
this.props.dispatch(revealStatus(status.get('id')));
if (status.get("hidden")) {
this.props.dispatch(revealStatus(status.get("id")));
} else {
this.props.dispatch(hideStatus(status.get('id')));
this.props.dispatch(hideStatus(status.get("id")));
}
};
handleToggleAll = () => {
const { status, ancestorsIds, descendantsIds } = this.props;
const statusIds = [status.get('id')].concat(ancestorsIds.toJS(), descendantsIds.toJS());
const statusIds = [status.get("id")].concat(ancestorsIds.toJS(), descendantsIds.toJS());
if (status.get('hidden')) {
if (status.get("hidden")) {
this.props.dispatch(revealStatus(statusIds));
} else {
this.props.dispatch(hideStatus(statusIds));
@@ -426,41 +428,41 @@ class Status extends ImmutablePureComponent {
handleTranslate = status => {
const { dispatch } = this.props;
if (status.get('translation')) {
dispatch(undoStatusTranslation(status.get('id'), status.get('poll')));
if (status.get("translation")) {
dispatch(undoStatusTranslation(status.get("id"), status.get("poll")));
} else {
dispatch(translateStatus(status.get('id')));
dispatch(translateStatus(status.get("id")));
}
};
handleBlockClick = (status) => {
const { dispatch } = this.props;
const account = status.get('account');
const account = status.get("account");
dispatch(initBlockModal(account));
};
handleReport = (status) => {
this.props.dispatch(initReport(status.get('account'), status));
this.props.dispatch(initReport(status.get("account"), status));
};
handleEmbed = (status) => {
this.props.dispatch(openModal({
modalType: 'EMBED',
modalProps: { id: status.get('id') },
modalType: "EMBED",
modalProps: { id: status.get("id") },
}));
};
handleUnmuteClick = account => {
this.props.dispatch(unmuteAccount(account.get('id')));
this.props.dispatch(unmuteAccount(account.get("id")));
};
handleUnblockClick = account => {
this.props.dispatch(unblockAccount(account.get('id')));
this.props.dispatch(unblockAccount(account.get("id")));
};
handleBlockDomainClick = domain => {
this.props.dispatch(openModal({
modalType: 'CONFIRM',
modalType: "CONFIRM",
modalProps: {
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
confirm: this.props.intl.formatMessage(messages.blockDomainConfirm),
@@ -475,11 +477,11 @@ class Status extends ImmutablePureComponent {
handleHotkeyMoveUp = () => {
this.handleMoveUp(this.props.status.get('id'));
this.handleMoveUp(this.props.status.get("id"));
};
handleHotkeyMoveDown = () => {
this.handleMoveDown(this.props.status.get('id'));
this.handleMoveDown(this.props.status.get("id"));
};
handleHotkeyReply = e => {
@@ -497,11 +499,11 @@ class Status extends ImmutablePureComponent {
handleHotkeyMention = e => {
e.preventDefault();
this.handleMentionClick(this.props.status.get('account'));
this.handleMentionClick(this.props.status.get("account"));
};
handleHotkeyOpenProfile = () => {
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
this.context.router.history.push(`/@${this.props.status.getIn(["account", "acct"])}`);
};
handleHotkeyToggleHidden = () => {
@@ -515,7 +517,7 @@ class Status extends ImmutablePureComponent {
handleMoveUp = id => {
const { status, ancestorsIds, descendantsIds } = this.props;
if (id === status.get('id')) {
if (id === status.get("id")) {
this._selectChild(ancestorsIds.size - 1, true);
} else {
let index = ancestorsIds.indexOf(id);
@@ -532,7 +534,7 @@ class Status extends ImmutablePureComponent {
handleMoveDown = id => {
const { status, ancestorsIds, descendantsIds } = this.props;
if (id === status.get('id')) {
if (id === status.get("id")) {
this._selectChild(ancestorsIds.size + 1, false);
} else {
let index = ancestorsIds.indexOf(id);
@@ -548,7 +550,7 @@ class Status extends ImmutablePureComponent {
_selectChild (index, align_top) {
const container = this.node;
const element = container.querySelectorAll('.focusable')[index];
const element = container.querySelectorAll(".focusable")[index];
if (element) {
if (align_top && container.scrollTop > element.offsetTop) {
@@ -586,12 +588,12 @@ class Status extends ImmutablePureComponent {
if (status) {
window.requestAnimationFrame(() => {
this.node?.querySelector('.detailed-status__wrapper')?.scrollIntoView(true);
this.node?.querySelector(".detailed-status__wrapper")?.scrollIntoView(true);
// In the single-column interface, `scrollIntoView` will put the post behind the header,
// so compensate for that.
if (!multiColumn) {
const offset = document.querySelector('.column-header__wrapper')?.getBoundingClientRect()?.bottom;
const offset = document.querySelector(".column-header__wrapper")?.getBoundingClientRect()?.bottom;
if (offset) {
const scrollingElement = document.scrollingElement || document.body;
scrollingElement.scrollBy(0, -offset);
@@ -604,7 +606,7 @@ class Status extends ImmutablePureComponent {
componentDidUpdate (prevProps) {
const { status, ancestorsIds } = this.props;
if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get("id") !== status.get("id"))) {
this._scrollStatusIntoView();
}
}
@@ -624,7 +626,7 @@ class Status extends ImmutablePureComponent {
}
// Scroll to focused post if it is loaded
const child = this.node?.querySelector('.detailed-status__wrapper');
const child = this.node?.querySelector(".detailed-status__wrapper");
if (child) {
return [0, child.offsetTop];
}
@@ -660,8 +662,8 @@ class Status extends ImmutablePureComponent {
descendants = <>{this.renderChildren(descendantsIds)}</>;
}
const isLocal = status.getIn(['account', 'acct'], '').indexOf('@') === -1;
const isIndexable = !status.getIn(['account', 'noindex']);
const isLocal = status.getIn(["account", "acct"], "").indexOf("@") === -1;
const isIndexable = !status.getIn(["account", "noindex"]);
const handlers = {
moveUp: this.handleHotkeyMoveUp,
@@ -682,18 +684,18 @@ class Status extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
<button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
<button type='button' className='column-header__button' title={intl.formatMessage(status.get("hidden") ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get("hidden") ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get("hidden") ? "eye-slash" : "eye"} /></button>
)}
/>
<ScrollContainer scrollKey='thread' shouldUpdateScroll={this.shouldUpdateScroll}>
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
<div className={classNames("scrollable", { fullscreen })} ref={this.setRef}>
{ancestors}
<HotKeys handlers={handlers}>
<div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)}>
<div className={classNames("focusable", "detailed-status__wrapper", `detailed-status__wrapper-${status.get("visibility")}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)}>
<DetailedStatus
key={`details-${status.get('id')}`}
key={`details-${status.get("id")}`}
status={status}
onOpenVideo={this.handleOpenVideo}
onOpenMedia={this.handleOpenMedia}
@@ -706,7 +708,7 @@ class Status extends ImmutablePureComponent {
/>
<ActionBar
key={`action-bar-${status.get('id')}`}
key={`action-bar-${status.get("id")}`}
status={status}
onReply={this.handleReplyClick}
onFavourite={this.handleFavouriteClick}
@@ -736,8 +738,8 @@ class Status extends ImmutablePureComponent {
<Helmet>
<title>{titleFromStatus(intl, status)}</title>
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
<link rel='canonical' href={status.get('url')} />
<meta name='robots' content={(isLocal && isIndexable) ? "all" : "noindex"} />
<link rel='canonical' href={status.get("url")} />
</Helmet>
</Column>
);