diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 240ff6cff9..8145c15307 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -69,6 +69,7 @@ const messages = defineMessages({ admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' }, copy: { id: 'status.copy', defaultMessage: 'Copy link to post' }, reference: { id: 'status.reference', defaultMessage: 'Link' }, + quoteLink: { id: 'status.quote_link', defaultMessage: 'Insert quote link' }, 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}' }, @@ -109,6 +110,7 @@ class StatusActionBar extends ImmutablePureComponent { onFilter: PropTypes.func, onAddFilter: PropTypes.func, onReference: PropTypes.func, + onInsertQuoteLink: PropTypes.func, onInteractionModal: PropTypes.func, withDismiss: PropTypes.bool, withCounters: PropTypes.bool, @@ -282,6 +284,10 @@ class StatusActionBar extends ImmutablePureComponent { navigator.clipboard.writeText(url); }; + handleInsertQuoteLink = () => { + this.props.onInsertQuoteLink(this.props.status, this.props.history); + }; + handleReference = () => { this.props.onReference(this.props.status, this.props.history); }; @@ -328,6 +334,8 @@ class StatusActionBar extends ImmutablePureComponent { } if (!boostMenu) { + menu.push({ text: intl.formatMessage(messages.quoteLink), action: this.handleInsertQuoteLink, tag: 'reblog' }); + if (account.getIn(['server_features', 'status_reference']) || !isHideItem('status_reference_unavailable_server')) { menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference, tag: 'reblog' }); } @@ -412,6 +420,8 @@ class StatusActionBar extends ImmutablePureComponent { } if (publicStatus) { + reblogMenu.push({ text: intl.formatMessage(messages.quoteLink), action: this.handleInsertQuoteLink, tag: 'reblog' }); + if (account.getIn(['server_features', 'status_reference']) || !isHideItem('status_reference_unavailable_server')) { reblogMenu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference }); } diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index 3371bd37d2..973e464940 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -152,6 +152,10 @@ const mapDispatchToProps = (dispatch, { contextType }) => ({ dispatch(insertReferenceCompose(0, status.get('url'), 'BT', router)); }, + onInsertQuoteLink (status, router) { + dispatch(insertReferenceCompose(0, status.get('url'), 'QT', router)); + }, + onTranslate (status) { if (status.get('translation')) { dispatch(undoStatusTranslation(status.get('id'), status.get('poll'))); diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index 63b91b287c..3a8a4020ad 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -65,6 +65,7 @@ const messages = defineMessages({ admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' }, copy: { id: 'status.copy', defaultMessage: 'Copy link to post' }, reference: { id: 'status.reference', defaultMessage: 'Link' }, + quoteLink: { id: 'status.quote_link', defaultMessage: 'Insert quote link' }, 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}' }, @@ -88,6 +89,7 @@ class ActionBar extends PureComponent { onFavourite: PropTypes.func.isRequired, onEmojiReact: PropTypes.func.isRequired, onReference: PropTypes.func.isRequired, + onInsertQuoteLink: PropTypes.func.isRequired, onBookmark: PropTypes.func.isRequired, onBookmarkCategoryAdder: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, @@ -219,6 +221,10 @@ class ActionBar extends PureComponent { navigator.clipboard.writeText(url); }; + handleInsertQuoteLink = () => { + this.props.onInsertQuoteLink(this.props.status, this.props.history); + }; + handleReference = () => { this.props.onReference(this.props.status, this.props.history); }; @@ -262,6 +268,8 @@ class ActionBar extends PureComponent { menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog : messages.reblog), action: this.handleReblogForceModalClick, tag: 'reblog' }); if (publicStatus) { + menu.push({ text: intl.formatMessage(messages.quoteLink), action: this.handleInsertQuoteLink, tag: 'reblog' }); + if (account.getIn(['server_features', 'status_reference']) || !isHideItem('status_reference_unavailable_server')) { menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference, tag: 'reblog' }); } @@ -339,6 +347,8 @@ class ActionBar extends PureComponent { } if (publicStatus) { + reblogMenu.push({ text: intl.formatMessage(messages.quoteLink), action: this.handleInsertQuoteLink, tag: 'reblog' }); + if (account.getIn(['server_features', 'status_reference']) || !isHideItem('status_reference_unavailable_server')) { reblogMenu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference }); } diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 4ccaaec7bb..7979c3c5fb 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -280,6 +280,10 @@ class Status extends ImmutablePureComponent { this.props.dispatch(insertReferenceCompose(0, status.get('url'), 'BT', router)); }; + handleInsertQuoteLink = (status, router) => { + this.props.dispatch(insertReferenceCompose(0, status.get('url'), 'QT', router)); + }; + handleBookmarkClick = (status) => { if (bookmarkCategoryNeeded) { this.handleBookmarkCategoryAdderClick(status); @@ -709,6 +713,7 @@ class Status extends ImmutablePureComponent { onReblog={this.handleReblogClick} onReblogForceModal={this.handleReblogForceModalClick} onReference={this.handleReference} + onInsertQuoteLink={this.handleInsertQuoteLink} onBookmark={this.handleBookmarkClick} onBookmarkCategoryAdder={this.handleBookmarkCategoryAdderClick} onDelete={this.handleDeleteClick} diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index bda67034b1..f45443326d 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -1085,6 +1085,7 @@ "status.quote_error.rejected": "This post cannot be displayed as the original author does not allow it to be quoted.", "status.quote_error.removed": "This post was removed by its author.", "status.quote_error.unauthorized": "This post cannot be displayed as you are not authorized to view it.", + "status.quote_link": "Insert quote link", "status.quote_post_author": "Post by {name}", "status.read_more": "Read more", "status.reblog": "Boost", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 4ffec1f09b..5ab1b172ed 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -1044,6 +1044,7 @@ "status.mute_conversation": "会話をミュート", "status.open": "詳細を表示", "status.quote": "リンク", + "status.quote_link": "引用リンクを挿入", "status.read_more": "もっと見る", "status.reblog": "ブースト", "status.reblog_private": "ブースト",