Merge branch 'tusooa/quote' into 'develop'
Quote See merge request pleroma/pleroma-fe!1846
This commit is contained in:
commit
f059c1f314
1
changelog.d/quote.add
Normal file
1
changelog.d/quote.add
Normal file
@ -0,0 +1 @@
|
|||||||
|
Implement quoting
|
@ -259,6 +259,7 @@ const getNodeInfo = async ({ store }) => {
|
|||||||
store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') })
|
store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') })
|
||||||
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
|
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
|
||||||
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
|
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
|
||||||
|
store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') })
|
||||||
|
|
||||||
const uploadLimits = metadata.uploadLimits
|
const uploadLimits = metadata.uploadLimits
|
||||||
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
|
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
|
||||||
|
@ -156,11 +156,13 @@ const PostStatusForm = {
|
|||||||
poll: this.statusPoll || {},
|
poll: this.statusPoll || {},
|
||||||
mediaDescriptions: this.statusMediaDescriptions || {},
|
mediaDescriptions: this.statusMediaDescriptions || {},
|
||||||
visibility: this.statusScope || scope,
|
visibility: this.statusScope || scope,
|
||||||
contentType: statusContentType
|
contentType: statusContentType,
|
||||||
|
quoting: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
randomSeed: `${Math.random()}`.replace('.', '-'),
|
||||||
dropFiles: [],
|
dropFiles: [],
|
||||||
uploadingFiles: false,
|
uploadingFiles: false,
|
||||||
error: null,
|
error: null,
|
||||||
@ -265,6 +267,30 @@ const PostStatusForm = {
|
|||||||
isEdit () {
|
isEdit () {
|
||||||
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
|
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
|
||||||
},
|
},
|
||||||
|
quotable () {
|
||||||
|
if (!this.$store.state.instance.quotingAvailable) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.replyTo) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const repliedStatus = this.$store.state.statuses.allStatusesObject[this.replyTo]
|
||||||
|
if (!repliedStatus) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repliedStatus.visibility === 'public' ||
|
||||||
|
repliedStatus.visibility === 'unlisted' ||
|
||||||
|
repliedStatus.visibility === 'local') {
|
||||||
|
return true
|
||||||
|
} else if (repliedStatus.visibility === 'private') {
|
||||||
|
return repliedStatus.user.id === this.$store.state.users.currentUser.id
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
...mapGetters(['mergedConfig']),
|
...mapGetters(['mergedConfig']),
|
||||||
...mapState({
|
...mapState({
|
||||||
mobileLayout: state => state.interface.mobileLayout
|
mobileLayout: state => state.interface.mobileLayout
|
||||||
@ -292,7 +318,8 @@ const PostStatusForm = {
|
|||||||
visibility: newStatus.visibility,
|
visibility: newStatus.visibility,
|
||||||
contentType: newStatus.contentType,
|
contentType: newStatus.contentType,
|
||||||
poll: {},
|
poll: {},
|
||||||
mediaDescriptions: {}
|
mediaDescriptions: {},
|
||||||
|
quoting: false
|
||||||
}
|
}
|
||||||
this.pollFormVisible = false
|
this.pollFormVisible = false
|
||||||
this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
|
this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
|
||||||
@ -340,6 +367,8 @@ const PostStatusForm = {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const replyOrQuoteAttr = newStatus.quoting ? 'quoteId' : 'inReplyToStatusId'
|
||||||
|
|
||||||
const postingOptions = {
|
const postingOptions = {
|
||||||
status: newStatus.status,
|
status: newStatus.status,
|
||||||
spoilerText: newStatus.spoilerText || null,
|
spoilerText: newStatus.spoilerText || null,
|
||||||
@ -347,7 +376,7 @@ const PostStatusForm = {
|
|||||||
sensitive: newStatus.nsfw,
|
sensitive: newStatus.nsfw,
|
||||||
media: newStatus.files,
|
media: newStatus.files,
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
inReplyToStatusId: this.replyTo,
|
[replyOrQuoteAttr]: this.replyTo,
|
||||||
contentType: newStatus.contentType,
|
contentType: newStatus.contentType,
|
||||||
poll,
|
poll,
|
||||||
idempotencyKey: this.idempotencyKey
|
idempotencyKey: this.idempotencyKey
|
||||||
@ -373,6 +402,7 @@ const PostStatusForm = {
|
|||||||
}
|
}
|
||||||
const newStatus = this.newStatus
|
const newStatus = this.newStatus
|
||||||
this.previewLoading = true
|
this.previewLoading = true
|
||||||
|
const replyOrQuoteAttr = newStatus.quoting ? 'quoteId' : 'inReplyToStatusId'
|
||||||
statusPoster.postStatus({
|
statusPoster.postStatus({
|
||||||
status: newStatus.status,
|
status: newStatus.status,
|
||||||
spoilerText: newStatus.spoilerText || null,
|
spoilerText: newStatus.spoilerText || null,
|
||||||
@ -380,7 +410,7 @@ const PostStatusForm = {
|
|||||||
sensitive: newStatus.nsfw,
|
sensitive: newStatus.nsfw,
|
||||||
media: [],
|
media: [],
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
inReplyToStatusId: this.replyTo,
|
[replyOrQuoteAttr]: this.replyTo,
|
||||||
contentType: newStatus.contentType,
|
contentType: newStatus.contentType,
|
||||||
poll: {},
|
poll: {},
|
||||||
preview: true
|
preview: true
|
||||||
|
@ -126,6 +126,36 @@
|
|||||||
class="preview-status"
|
class="preview-status"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="quotable"
|
||||||
|
role="radiogroup"
|
||||||
|
class="btn-group reply-or-quote-selector"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
:id="`reply-or-quote-option-${randomSeed}-reply`"
|
||||||
|
class="btn button-default reply-or-quote-option"
|
||||||
|
:class="{ toggled: !newStatus.quoting }"
|
||||||
|
tabindex="0"
|
||||||
|
role="radio"
|
||||||
|
:aria-labelledby="`reply-or-quote-option-${randomSeed}-reply`"
|
||||||
|
:aria-checked="!newStatus.quoting"
|
||||||
|
@click="newStatus.quoting = false"
|
||||||
|
>
|
||||||
|
{{ $t('post_status.reply_option') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:id="`reply-or-quote-option-${randomSeed}-quote`"
|
||||||
|
class="btn button-default reply-or-quote-option"
|
||||||
|
:class="{ toggled: newStatus.quoting }"
|
||||||
|
tabindex="0"
|
||||||
|
role="radio"
|
||||||
|
:aria-labelledby="`reply-or-quote-option-${randomSeed}-quote`"
|
||||||
|
:aria-checked="newStatus.quoting"
|
||||||
|
@click="newStatus.quoting = true"
|
||||||
|
>
|
||||||
|
{{ $t('post_status.quote_option') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<EmojiInput
|
<EmojiInput
|
||||||
v-if="!disableSubject && (newStatus.spoilerText || alwaysShowSubject)"
|
v-if="!disableSubject && (newStatus.spoilerText || alwaysShowSubject)"
|
||||||
v-model="newStatus.spoilerText"
|
v-model="newStatus.spoilerText"
|
||||||
@ -420,6 +450,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reply-or-quote-selector {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
.text-format {
|
.text-format {
|
||||||
.only-format {
|
.only-format {
|
||||||
color: $fallback--faint;
|
color: $fallback--faint;
|
||||||
|
@ -133,6 +133,7 @@ const Status = {
|
|||||||
'showPinned',
|
'showPinned',
|
||||||
'inProfile',
|
'inProfile',
|
||||||
'profileUserId',
|
'profileUserId',
|
||||||
|
'inQuote',
|
||||||
|
|
||||||
'simpleTree',
|
'simpleTree',
|
||||||
'controlledThreadDisplayStatus',
|
'controlledThreadDisplayStatus',
|
||||||
@ -159,7 +160,8 @@ const Status = {
|
|||||||
uncontrolledMediaPlaying: [],
|
uncontrolledMediaPlaying: [],
|
||||||
suspendable: true,
|
suspendable: true,
|
||||||
error: null,
|
error: null,
|
||||||
headTailLinks: null
|
headTailLinks: null,
|
||||||
|
displayQuote: !this.inQuote
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -401,6 +403,18 @@ const Status = {
|
|||||||
},
|
},
|
||||||
editingAvailable () {
|
editingAvailable () {
|
||||||
return this.$store.state.instance.editingAvailable
|
return this.$store.state.instance.editingAvailable
|
||||||
|
},
|
||||||
|
hasVisibleQuote () {
|
||||||
|
return this.status.quote_url && this.status.quote_visible
|
||||||
|
},
|
||||||
|
hasInvisibleQuote () {
|
||||||
|
return this.status.quote_url && !this.status.quote_visible
|
||||||
|
},
|
||||||
|
quotedStatus () {
|
||||||
|
return this.status.quote_id ? this.$store.state.statuses.allStatusesObject[this.status.quote_id] : undefined
|
||||||
|
},
|
||||||
|
shouldDisplayQuote () {
|
||||||
|
return this.quotedStatus && this.displayQuote
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -469,6 +483,18 @@ const Status = {
|
|||||||
window.scrollBy(0, rect.bottom - window.innerHeight + 50)
|
window.scrollBy(0, rect.bottom - window.innerHeight + 50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
toggleDisplayQuote () {
|
||||||
|
if (this.shouldDisplayQuote) {
|
||||||
|
this.displayQuote = false
|
||||||
|
} else if (!this.quotedStatus) {
|
||||||
|
this.$store.dispatch('fetchStatus', this.status.quote_id)
|
||||||
|
.then(() => {
|
||||||
|
this.displayQuote = true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.displayQuote = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -422,4 +422,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quoted-status {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
border: 1px solid var(--border, $fallback--border);
|
||||||
|
border-radius: var(--attachmentRadius, $fallback--attachmentRadius);
|
||||||
|
|
||||||
|
&.-unavailable-prompt {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-quoted-status-button {
|
||||||
|
margin: 0.5em;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,6 +364,45 @@
|
|||||||
@parseReady="setHeadTailLinks"
|
@parseReady="setHeadTailLinks"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<article
|
||||||
|
v-if="hasVisibleQuote"
|
||||||
|
class="quoted-status"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="button-unstyled -link display-quoted-status-button"
|
||||||
|
:aria-expanded="shouldDisplayQuote"
|
||||||
|
@click="toggleDisplayQuote"
|
||||||
|
>
|
||||||
|
{{ shouldDisplayQuote ? $t('status.hide_quote') : $t('status.display_quote') }}
|
||||||
|
<FAIcon
|
||||||
|
class="display-quoted-status-button-icon"
|
||||||
|
:icon="shouldDisplayQuote ? 'chevron-up' : 'chevron-down'"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<Status
|
||||||
|
v-if="shouldDisplayQuote"
|
||||||
|
:statusoid="quotedStatus"
|
||||||
|
:in-quote="true"
|
||||||
|
/>
|
||||||
|
</article>
|
||||||
|
<p
|
||||||
|
v-else-if="hasInvisibleQuote"
|
||||||
|
class="quoted-status -unavailable-prompt"
|
||||||
|
>
|
||||||
|
<i18n-t keypath="status.invisible_quote">
|
||||||
|
<template #link>
|
||||||
|
<bdi>
|
||||||
|
<a
|
||||||
|
:href="status.quote_url"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ status.quote_url }}
|
||||||
|
</a>
|
||||||
|
</bdi>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="inConversation && !isPreview && replies && replies.length"
|
v-if="inConversation && !isPreview && replies && replies.length"
|
||||||
class="replies"
|
class="replies"
|
||||||
|
@ -261,6 +261,8 @@
|
|||||||
"post_status": {
|
"post_status": {
|
||||||
"edit_status": "Edit status",
|
"edit_status": "Edit status",
|
||||||
"new_status": "Post new status",
|
"new_status": "Post new status",
|
||||||
|
"reply_option": "Reply to this status",
|
||||||
|
"quote_option": "Quote this status",
|
||||||
"account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.",
|
"account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.",
|
||||||
"account_not_locked_warning_link": "locked",
|
"account_not_locked_warning_link": "locked",
|
||||||
"attachments_sensitive": "Mark attachments as sensitive",
|
"attachments_sensitive": "Mark attachments as sensitive",
|
||||||
@ -1028,7 +1030,10 @@
|
|||||||
"show_all_conversation": "Show full conversation ({numStatus} other status) | Show full conversation ({numStatus} other statuses)",
|
"show_all_conversation": "Show full conversation ({numStatus} other status) | Show full conversation ({numStatus} other statuses)",
|
||||||
"show_only_conversation_under_this": "Only show replies to this status",
|
"show_only_conversation_under_this": "Only show replies to this status",
|
||||||
"status_history": "Status history",
|
"status_history": "Status history",
|
||||||
"reaction_count_label": "{num} person reacted | {num} people reacted"
|
"reaction_count_label": "{num} person reacted | {num} people reacted",
|
||||||
|
"hide_quote": "Hide the quoted status",
|
||||||
|
"display_quote": "Display the quoted status",
|
||||||
|
"invisible_quote": "Quoted status unavailable: {link}"
|
||||||
},
|
},
|
||||||
"user_card": {
|
"user_card": {
|
||||||
"approve": "Approve",
|
"approve": "Approve",
|
||||||
|
@ -128,6 +128,7 @@ const defaultState = {
|
|||||||
mediaProxyAvailable: false,
|
mediaProxyAvailable: false,
|
||||||
suggestionsEnabled: false,
|
suggestionsEnabled: false,
|
||||||
suggestionsWeb: '',
|
suggestionsWeb: '',
|
||||||
|
quotingAvailable: false,
|
||||||
|
|
||||||
// Html stuff
|
// Html stuff
|
||||||
instanceSpecificPanelContent: '',
|
instanceSpecificPanelContent: '',
|
||||||
|
@ -229,6 +229,10 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||||||
timelineObject.newStatusCount += 1
|
timelineObject.newStatusCount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status.quote) {
|
||||||
|
addStatus(status.quote, /* showImmediately = */ false, /* addToTimeline = */ false)
|
||||||
|
}
|
||||||
|
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,6 +827,7 @@ const postStatus = ({
|
|||||||
poll,
|
poll,
|
||||||
mediaIds = [],
|
mediaIds = [],
|
||||||
inReplyToStatusId,
|
inReplyToStatusId,
|
||||||
|
quoteId,
|
||||||
contentType,
|
contentType,
|
||||||
preview,
|
preview,
|
||||||
idempotencyKey
|
idempotencyKey
|
||||||
@ -859,6 +860,9 @@ const postStatus = ({
|
|||||||
if (inReplyToStatusId) {
|
if (inReplyToStatusId) {
|
||||||
form.append('in_reply_to_id', inReplyToStatusId)
|
form.append('in_reply_to_id', inReplyToStatusId)
|
||||||
}
|
}
|
||||||
|
if (quoteId) {
|
||||||
|
form.append('quote_id', quoteId)
|
||||||
|
}
|
||||||
if (preview) {
|
if (preview) {
|
||||||
form.append('preview', 'true')
|
form.append('preview', 'true')
|
||||||
}
|
}
|
||||||
|
@ -325,6 +325,10 @@ export const parseStatus = (data) => {
|
|||||||
output.thread_muted = pleroma.thread_muted
|
output.thread_muted = pleroma.thread_muted
|
||||||
output.emoji_reactions = pleroma.emoji_reactions
|
output.emoji_reactions = pleroma.emoji_reactions
|
||||||
output.parent_visible = pleroma.parent_visible === undefined ? true : pleroma.parent_visible
|
output.parent_visible = pleroma.parent_visible === undefined ? true : pleroma.parent_visible
|
||||||
|
output.quote = pleroma.quote ? parseStatus(pleroma.quote) : undefined
|
||||||
|
output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined)
|
||||||
|
output.quote_url = pleroma.quote_url
|
||||||
|
output.quote_visible = pleroma.quote_visible
|
||||||
} else {
|
} else {
|
||||||
output.text = data.content
|
output.text = data.content
|
||||||
output.summary = data.spoiler_text
|
output.summary = data.spoiler_text
|
||||||
|
@ -10,6 +10,7 @@ const postStatus = ({
|
|||||||
poll,
|
poll,
|
||||||
media = [],
|
media = [],
|
||||||
inReplyToStatusId = undefined,
|
inReplyToStatusId = undefined,
|
||||||
|
quoteId = undefined,
|
||||||
contentType = 'text/plain',
|
contentType = 'text/plain',
|
||||||
preview = false,
|
preview = false,
|
||||||
idempotencyKey = ''
|
idempotencyKey = ''
|
||||||
@ -24,6 +25,7 @@ const postStatus = ({
|
|||||||
sensitive,
|
sensitive,
|
||||||
mediaIds,
|
mediaIds,
|
||||||
inReplyToStatusId,
|
inReplyToStatusId,
|
||||||
|
quoteId,
|
||||||
contentType,
|
contentType,
|
||||||
poll,
|
poll,
|
||||||
preview,
|
preview,
|
||||||
|
Loading…
Reference in New Issue
Block a user