diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 3ea159f019..1f682d1321 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -785,11 +785,12 @@ export function insertExpirationCompose(position, data) { }; } -export function insertReferenceCompose(position, url) { +export function insertReferenceCompose(position, url, attributeType) { return { type: COMPOSE_REFERENCE_INSERT, position, url, + attributeType, }; } diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index d689b1ed03..02a42a92dd 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -52,6 +52,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: 'Add reference' }, + quote: { id: 'status.quote', defaultMessage: 'Add ref (quote in other servers)' }, hide: { id: 'status.hide', defaultMessage: 'Hide post' }, blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' }, unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' }, @@ -97,6 +98,8 @@ class StatusActionBar extends ImmutablePureComponent { onBookmarkCategoryAdder: PropTypes.func, onFilter: PropTypes.func, onAddFilter: PropTypes.func, + onReference: PropTypes.func, + onQuote: PropTypes.func, onInteractionModal: PropTypes.func, withDismiss: PropTypes.bool, withCounters: PropTypes.bool, @@ -271,6 +274,10 @@ class StatusActionBar extends ImmutablePureComponent { this.props.onReference(this.props.status); }; + handleQuote = () => { + this.props.onQuote(this.props.status); + }; + handleHideClick = () => { this.props.onFilter(); }; @@ -316,6 +323,7 @@ class StatusActionBar extends ImmutablePureComponent { if (publicStatus) { menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference }); + menu.push({ text: intl.formatMessage(messages.quote), action: this.handleQuote }); } menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClickOriginal }); diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index 5023b7ef03..da3058334b 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -203,7 +203,11 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ }, onReference (status) { - dispatch(insertReferenceCompose(0, status.get('url'))); + dispatch(insertReferenceCompose(0, status.get('url'), 'BT')); + }, + + onQuote (status) { + dispatch(insertReferenceCompose(0, status.get('url'), 'QT')); }, onTranslate (status) { diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index e80a83c907..56086075fc 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -46,6 +46,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: 'Add reference' }, + quote: { id: 'status.quote', defaultMessage: 'Add ref (quote in other servers)' }, 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}' }, @@ -74,6 +75,7 @@ class ActionBar extends PureComponent { onFavourite: PropTypes.func.isRequired, onEmojiReact: PropTypes.func.isRequired, onReference: PropTypes.func.isRequired, + onQuote: PropTypes.func.isRequired, onBookmark: PropTypes.func.isRequired, onBookmarkCategoryAdder: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, @@ -208,6 +210,10 @@ class ActionBar extends PureComponent { this.props.onReference(this.props.status); }; + handleQuote = () => { + this.props.onQuote(this.props.status); + }; + handleEmojiPick = (data) => { this.props.onEmojiReact(this.props.status, data); }; @@ -248,6 +254,7 @@ class ActionBar extends PureComponent { if (publicStatus) { menu.push({ text: intl.formatMessage(messages.reference), action: this.handleReference }); + menu.push({ text: intl.formatMessage(messages.quote), action: this.handleQuote }); } menu.push({ text: intl.formatMessage(messages.bookmark_category), action: this.handleBookmarkCategoryAdderClick }); diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index cf4c2bd6ce..03a721d9c8 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -363,7 +363,11 @@ class Status extends ImmutablePureComponent { }; handleReference = (status) => { - this.props.dispatch(insertReferenceCompose(0, status.get('url'))); + this.props.dispatch(insertReferenceCompose(0, status.get('url'), 'BT')); + }; + + handleQuote = (status) => { + this.props.dispatch(insertReferenceCompose(0, status.get('url'), 'QT')); }; handleBookmarkClick = (status) => { @@ -750,6 +754,7 @@ class Status extends ImmutablePureComponent { onReblog={this.handleReblogClick} onReblogForceModal={this.handleReblogForceModalClick} onReference={this.handleReference} + onQuote={this.handleQuote} 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 9de9b72162..b986b45b30 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -683,6 +683,7 @@ "status.open": "Expand this post", "status.pin": "Pin on profile", "status.pinned": "Pinned post", + "status.quote": "Ref (quote in other servers)", "status.read_more": "Read more", "status.reblog": "Boost", "status.reblog_private": "Boost with original visibility", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index d294d85e0b..e598512178 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -769,6 +769,7 @@ "status.open": "詳細を表示", "status.pin": "プロフィールに固定表示", "status.pinned": "固定された投稿", + "status.quote": "参照 (他サーバーで引用扱い)", "status.read_more": "もっと見る", "status.reblog": "ブースト", "status.reblog_private": "ブースト", diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 59be1ae6da..612ee01d9b 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -252,10 +252,11 @@ const insertExpiration = (state, position, data) => { }); }; -const insertReference = (state, url) => { +const insertReference = (state, url, attributeType) => { const oldText = state.get('text'); + const attribute = attributeType || 'BT'; - if (oldText.indexOf(`BT ${url}`) >= 0) { + if (oldText.indexOf(`${attribute} ${url}`) >= 0) { return state; } @@ -271,12 +272,12 @@ const insertReference = (state, url) => { if (oldText.length > 0) { const lastLine = oldText.slice(oldText.lastIndexOf('\n') + 1, oldText.length - 1); - if (lastLine.startsWith('BT ')) { + if (lastLine.startsWith(`${attribute} `)) { newLine = '\n'; } } - const referenceText = `${newLine}BT ${url}`; + const referenceText = `${newLine}${attribute} ${url}`; const text = `${oldText}${referenceText}`; return state.merge({ @@ -526,7 +527,7 @@ export default function compose(state = initialState, action) { case COMPOSE_EXPIRATION_INSERT: return insertExpiration(state, action.position, action.data); case COMPOSE_REFERENCE_INSERT: - return insertReference(state, action.url); + return insertReference(state, action.url, action.attributeType); case COMPOSE_UPLOAD_CHANGE_SUCCESS: return state .set('is_changing_upload', false)