fb3dc00dda
`navigator.share()` rejects Promise if user cancelled sharing, and it may print it as an error on JavaScript console. This patch ignores it and prints other errors on the console.
190 lines
7.2 KiB
JavaScript
190 lines
7.2 KiB
JavaScript
import React from 'react';
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
import PropTypes from 'prop-types';
|
|
import IconButton from './icon_button';
|
|
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
import { me } from '../initial_state';
|
|
|
|
const messages = defineMessages({
|
|
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
|
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
|
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
|
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
|
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
|
share: { id: 'status.share', defaultMessage: 'Share' },
|
|
more: { id: 'status.more', defaultMessage: 'More' },
|
|
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
|
|
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
|
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
|
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
|
|
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
|
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
|
|
muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
|
|
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
|
|
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
|
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
|
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
|
});
|
|
|
|
@injectIntl
|
|
export default class StatusActionBar extends ImmutablePureComponent {
|
|
|
|
static contextTypes = {
|
|
router: PropTypes.object,
|
|
};
|
|
|
|
static propTypes = {
|
|
status: ImmutablePropTypes.map.isRequired,
|
|
onReply: PropTypes.func,
|
|
onFavourite: PropTypes.func,
|
|
onReblog: PropTypes.func,
|
|
onDelete: PropTypes.func,
|
|
onMention: PropTypes.func,
|
|
onMute: PropTypes.func,
|
|
onBlock: PropTypes.func,
|
|
onReport: PropTypes.func,
|
|
onEmbed: PropTypes.func,
|
|
onMuteConversation: PropTypes.func,
|
|
onPin: PropTypes.func,
|
|
withDismiss: PropTypes.bool,
|
|
intl: PropTypes.object.isRequired,
|
|
};
|
|
|
|
// Avoid checking props that are functions (and whose equality will always
|
|
// evaluate to false. See react-immutable-pure-component for usage.
|
|
updateOnProps = [
|
|
'status',
|
|
'withDismiss',
|
|
]
|
|
|
|
handleReplyClick = () => {
|
|
this.props.onReply(this.props.status, this.context.router.history);
|
|
}
|
|
|
|
handleShareClick = () => {
|
|
navigator.share({
|
|
text: this.props.status.get('search_index'),
|
|
url: this.props.status.get('url'),
|
|
}).catch((e) => {
|
|
if (e.name !== 'AbortError') console.error(e);
|
|
});
|
|
}
|
|
|
|
handleFavouriteClick = () => {
|
|
this.props.onFavourite(this.props.status);
|
|
}
|
|
|
|
handleReblogClick = (e) => {
|
|
this.props.onReblog(this.props.status, e);
|
|
}
|
|
|
|
handleDeleteClick = () => {
|
|
this.props.onDelete(this.props.status);
|
|
}
|
|
|
|
handlePinClick = () => {
|
|
this.props.onPin(this.props.status);
|
|
}
|
|
|
|
handleMentionClick = () => {
|
|
this.props.onMention(this.props.status.get('account'), this.context.router.history);
|
|
}
|
|
|
|
handleMuteClick = () => {
|
|
this.props.onMute(this.props.status.get('account'));
|
|
}
|
|
|
|
handleBlockClick = () => {
|
|
this.props.onBlock(this.props.status.get('account'));
|
|
}
|
|
|
|
handleOpen = () => {
|
|
this.context.router.history.push(`/statuses/${this.props.status.get('id')}`);
|
|
}
|
|
|
|
handleEmbed = () => {
|
|
this.props.onEmbed(this.props.status);
|
|
}
|
|
|
|
handleReport = () => {
|
|
this.props.onReport(this.props.status);
|
|
}
|
|
|
|
handleConversationMuteClick = () => {
|
|
this.props.onMuteConversation(this.props.status);
|
|
}
|
|
|
|
render () {
|
|
const { status, intl, withDismiss } = this.props;
|
|
|
|
const mutingConversation = status.get('muted');
|
|
const anonymousAccess = !me;
|
|
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
|
|
|
|
let menu = [];
|
|
let reblogIcon = 'retweet';
|
|
let replyIcon;
|
|
let replyTitle;
|
|
|
|
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
|
|
|
|
if (publicStatus) {
|
|
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
|
}
|
|
|
|
menu.push(null);
|
|
|
|
if (status.getIn(['account', 'id']) === me || withDismiss) {
|
|
menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
|
menu.push(null);
|
|
}
|
|
|
|
if (status.getIn(['account', 'id']) === me) {
|
|
if (publicStatus) {
|
|
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
|
}
|
|
|
|
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
|
|
} else {
|
|
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
|
menu.push(null);
|
|
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
|
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
|
menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
|
}
|
|
|
|
if (status.get('visibility') === 'direct') {
|
|
reblogIcon = 'envelope';
|
|
} else if (status.get('visibility') === 'private') {
|
|
reblogIcon = 'lock';
|
|
}
|
|
|
|
if (status.get('in_reply_to_id', null) === null) {
|
|
replyIcon = 'reply';
|
|
replyTitle = intl.formatMessage(messages.reply);
|
|
} else {
|
|
replyIcon = 'reply-all';
|
|
replyTitle = intl.formatMessage(messages.replyAll);
|
|
}
|
|
|
|
const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && (
|
|
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
|
|
);
|
|
|
|
return (
|
|
<div className='status__action-bar'>
|
|
<IconButton className='status__action-bar-button' disabled={anonymousAccess} title={replyTitle} icon={replyIcon} onClick={this.handleReplyClick} />
|
|
<IconButton className='status__action-bar-button' disabled={anonymousAccess || !publicStatus} active={status.get('reblogged')} pressed={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} />
|
|
<IconButton className='status__action-bar-button star-icon' disabled={anonymousAccess} animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />
|
|
{shareButton}
|
|
|
|
<div className='status__action-bar-dropdown'>
|
|
<DropdownMenuContainer disabled={anonymousAccess} status={status} items={menu} icon='ellipsis-h' size={18} direction='right' title={intl.formatMessage(messages.more)} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
}
|