diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 7778265151..5d01f00140 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -79,6 +79,7 @@ class Status extends ImmutablePureComponent { onEmojiReact: PropTypes.func, onUnEmojiReact: PropTypes.func, onReblog: PropTypes.func, + onReblogForceModal: PropTypes.func, onDelete: PropTypes.func, onDirect: PropTypes.func, onMention: PropTypes.func, diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 6768f45643..ba42a3b09a 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -24,6 +24,7 @@ const messages = defineMessages({ more: { id: 'status.more', defaultMessage: 'More' }, replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, + cancelReblog: { id: 'status.cancel_reblog', defaultMessage: 'Unboost' }, 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' }, @@ -69,6 +70,7 @@ class StatusActionBar extends ImmutablePureComponent { onFavourite: PropTypes.func, onEmojiReact: PropTypes.func, onReblog: PropTypes.func, + onReblogForceModal: PropTypes.func, onDelete: PropTypes.func, onDirect: PropTypes.func, onMention: PropTypes.func, @@ -151,6 +153,10 @@ class StatusActionBar extends ImmutablePureComponent { } }; + handleReblogForceModalClick = e => { + this.props.onReblogForceModal(this.props.status, e); + }; + handleBookmarkClick = () => { this.props.onBookmark(this.props.status); }; @@ -272,6 +278,7 @@ class StatusActionBar extends ImmutablePureComponent { menu.push(null); + menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancelReblog : messages.reblog), action: this.handleReblogForceModalClick }); menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClick }); if (writtenByMe && pinnableStatus) { diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index 1b581a3119..85b0092ac9 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -110,6 +110,10 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ } }, + onReblogForceModal (status) { + dispatch(initBoostModal({ status, onReblog: this.onModalReblog })); + }, + onFavourite (status) { if (status.get('favourited')) { dispatch(unfavourite(status)); diff --git a/app/javascript/mastodon/features/notifications/containers/notification_container.js b/app/javascript/mastodon/features/notifications/containers/notification_container.js index 2353cb8222..51052cdf38 100644 --- a/app/javascript/mastodon/features/notifications/containers/notification_container.js +++ b/app/javascript/mastodon/features/notifications/containers/notification_container.js @@ -54,6 +54,14 @@ const mapDispatchToProps = dispatch => ({ } }, + onReblogForceModal (status) { + if (status.get('reblogged')) { + dispatch(unreblog(status)); + } else { + dispatch(initBoostModal({ status, onReblog: this.onModalReblog })); + } + }, + onFavourite (status) { if (status.get('favourited')) { dispatch(unfavourite(status)); diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index d6e89a6e3d..ae963fd5bd 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -61,6 +61,7 @@ class ActionBar extends React.PureComponent { relationship: ImmutablePropTypes.map, onReply: PropTypes.func.isRequired, onReblog: PropTypes.func.isRequired, + onReblogForceModal: PropTypes.func.isRequired, onFavourite: PropTypes.func.isRequired, onEmojiReact: PropTypes.func.isRequired, onBookmark: PropTypes.func.isRequired, @@ -89,6 +90,10 @@ class ActionBar extends React.PureComponent { this.props.onReblog(this.props.status, e); }; + handleReblogForceModalClick = (e) => { + this.props.onReblogForceModal(this.props.status, e); + }; + handleFavouriteClick = () => { this.props.onFavourite(this.props.status); }; @@ -208,6 +213,8 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy }); menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed }); menu.push(null); + menu.push({ text: intl.formatMessage(messages.reblog), action: this.handleReblogForceModalClick }); + menu.push(null); } if (writtenByMe) { diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js index 99c4c3b2f4..f2c1d8187b 100644 --- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -87,6 +87,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ } }, + onReblogForceModal (status) { + if (status.get('reblogged')) { + dispatch(unreblog(status)); + } else { + dispatch(initBoostModal({ status, onReblog: this.onModalReblog })); + } + }, + onFavourite (status) { if (status.get('favourited')) { dispatch(unfavourite(status)); diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 0e65a6d974..e0f536f56c 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -310,7 +310,7 @@ class Status extends ImmutablePureComponent { this.props.dispatch(reblog(status, privacy)); }; - handleReblogClick = (status, e) => { + handleReblogClick = (status, e, force = false) => { const { dispatch } = this.props; const { signedIn } = this.context.identity; @@ -318,7 +318,7 @@ class Status extends ImmutablePureComponent { if (status.get('reblogged')) { dispatch(unreblog(status)); } else { - if ((e && e.shiftKey) || !boostModal) { + if (!force && ((e && e.shiftKey) || !boostModal)) { this.handleModalReblog(status); } else { dispatch(initBoostModal({ status, onReblog: this.handleModalReblog })); @@ -333,6 +333,10 @@ class Status extends ImmutablePureComponent { } }; + handleReblogForceModalClick = (status, e) => { + this.handleReblogClick(status, e, true); + }; + handleBookmarkClick = (status) => { if (status.get('bookmarked')) { this.props.dispatch(unbookmark(status)); @@ -678,6 +682,7 @@ class Status extends ImmutablePureComponent { onFavourite={this.handleFavouriteClick} onEmojiReact={this.handleEmojiReact} onReblog={this.handleReblogClick} + onReblogForceModal={this.handleReblogForceModalClick} onBookmark={this.handleBookmarkClick} onDelete={this.handleDeleteClick} onEdit={this.handleEditClick}