Merge remote-tracking branch 'origin/develop' into 2-10-1-fixes
This commit is contained in:
commit
dcb7ed1b8c
428 changed files with 55612 additions and 18549 deletions
|
|
@ -1,34 +1,31 @@
|
|||
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
|
||||
import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faPlus,
|
||||
faMinus,
|
||||
faBookmark as faBookmarkRegular,
|
||||
faStar as faStarRegular,
|
||||
} from '@fortawesome/free-regular-svg-icons'
|
||||
import {
|
||||
faBookmark,
|
||||
faCheck,
|
||||
faTimes,
|
||||
faWrench,
|
||||
|
||||
faChevronRight,
|
||||
faChevronUp,
|
||||
|
||||
faExternalLinkAlt,
|
||||
faEyeSlash,
|
||||
faHistory,
|
||||
faMinus,
|
||||
faPlus,
|
||||
faReply,
|
||||
faRetweet,
|
||||
faStar,
|
||||
faSmileBeam,
|
||||
|
||||
faBookmark,
|
||||
faEyeSlash,
|
||||
faThumbtack,
|
||||
faShareAlt,
|
||||
faExternalLinkAlt,
|
||||
faHistory
|
||||
faSmileBeam,
|
||||
faStar,
|
||||
faThumbtack,
|
||||
faTimes,
|
||||
faWrench,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import {
|
||||
faStar as faStarRegular,
|
||||
faBookmark as faBookmarkRegular
|
||||
} from '@fortawesome/free-regular-svg-icons'
|
||||
|
||||
library.add(
|
||||
faPlus,
|
||||
|
|
@ -52,7 +49,7 @@ library.add(
|
|||
faThumbtack,
|
||||
faShareAlt,
|
||||
faExternalLinkAlt,
|
||||
faHistory
|
||||
faHistory,
|
||||
)
|
||||
|
||||
export default {
|
||||
|
|
@ -65,66 +62,78 @@ export default {
|
|||
'getClass',
|
||||
'getComponent',
|
||||
'doAction',
|
||||
'outerClose'
|
||||
],
|
||||
emits: [
|
||||
'interacted'
|
||||
'outerClose',
|
||||
],
|
||||
emits: ['interacted'],
|
||||
components: {
|
||||
StatusBookmarkFolderMenu,
|
||||
EmojiPicker,
|
||||
Popover
|
||||
Popover,
|
||||
},
|
||||
data: () => ({
|
||||
animationState: false
|
||||
animationState: false,
|
||||
}),
|
||||
computed: {
|
||||
buttonClass () {
|
||||
buttonClass() {
|
||||
return [
|
||||
this.button.name + '-button',
|
||||
{
|
||||
'-with-extra': this.button.name === 'bookmark',
|
||||
'-extra': this.extra,
|
||||
'-quick': !this.extra
|
||||
}
|
||||
'-quick': !this.extra,
|
||||
},
|
||||
]
|
||||
},
|
||||
userIsMuted () {
|
||||
userIsMuted() {
|
||||
return this.$store.getters.relationship(this.status.user.id).muting
|
||||
},
|
||||
threadIsMuted () {
|
||||
threadIsMuted() {
|
||||
return this.status.thread_muted
|
||||
},
|
||||
hideCustomEmoji () {
|
||||
hideCustomEmoji() {
|
||||
return !this.$store.state.instance.pleromaCustomEmojiReactionsAvailable
|
||||
},
|
||||
buttonInnerClass () {
|
||||
buttonInnerClass() {
|
||||
return [
|
||||
this.button.name + '-button',
|
||||
{
|
||||
'main-button': this.extra,
|
||||
'button-unstyled': !this.extra,
|
||||
'-active': this.button.active?.(this.funcArg),
|
||||
disabled: this.button.interactive ? !this.button.interactive(this.funcArg) : false
|
||||
}
|
||||
disabled: this.button.interactive
|
||||
? !this.button.interactive(this.funcArg)
|
||||
: false,
|
||||
},
|
||||
]
|
||||
},
|
||||
remoteInteractionLink () {
|
||||
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
|
||||
}
|
||||
remoteInteractionLink() {
|
||||
return this.$store.getters.remoteInteractionLink({
|
||||
statusId: this.status.id,
|
||||
})
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addReaction (event) {
|
||||
addReaction(event) {
|
||||
const emoji = event.insertion
|
||||
const existingReaction = this.status.emoji_reactions.find(r => r.name === emoji)
|
||||
const existingReaction = this.status.emoji_reactions.find(
|
||||
(r) => r.name === emoji,
|
||||
)
|
||||
if (existingReaction && existingReaction.me) {
|
||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||
} else {
|
||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||
}
|
||||
},
|
||||
doActionWrap (button, close = () => {}) {
|
||||
if (this.button.interactive ? !this.button.interactive(this.funcArg) : false) return
|
||||
doActionWrap(
|
||||
button,
|
||||
close = () => {
|
||||
/* no-op */
|
||||
},
|
||||
) {
|
||||
if (
|
||||
this.button.interactive ? !this.button.interactive(this.funcArg) : false
|
||||
)
|
||||
return
|
||||
this.$emit('interacted')
|
||||
if (button.name === 'emoji') {
|
||||
this.$refs.picker.showPicker()
|
||||
|
|
@ -136,6 +145,6 @@ export default {
|
|||
}, 500)
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,92 +1,90 @@
|
|||
import ActionButton from './action_button.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import MuteConfirm from 'src/components/confirm_modal/mute_confirm.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
|
||||
import ActionButton from './action_button.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faUser,
|
||||
faFolderTree,
|
||||
faGlobe,
|
||||
faFolderTree
|
||||
faUser,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faUser,
|
||||
faGlobe,
|
||||
faFolderTree
|
||||
)
|
||||
library.add(faUser, faGlobe, faFolderTree)
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActionButton,
|
||||
Popover,
|
||||
MuteConfirm,
|
||||
UserTimedFilterModal
|
||||
UserTimedFilterModal,
|
||||
},
|
||||
props: ['button', 'status'],
|
||||
emits: ['interacted'],
|
||||
mounted () {
|
||||
mounted() {
|
||||
if (this.button.name === 'mute') {
|
||||
this.$store.dispatch('fetchDomainMutes')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
buttonClass () {
|
||||
buttonClass() {
|
||||
return [
|
||||
this.button.name + '-button',
|
||||
{
|
||||
'-with-extra': this.button.name === 'bookmark',
|
||||
'-extra': this.extra,
|
||||
'-quick': !this.extra
|
||||
}
|
||||
'-quick': !this.extra,
|
||||
},
|
||||
]
|
||||
},
|
||||
user () {
|
||||
user() {
|
||||
return this.status.user
|
||||
},
|
||||
userIsMuted () {
|
||||
userIsMuted() {
|
||||
return this.$store.getters.relationship(this.user.id).muting
|
||||
},
|
||||
conversationIsMuted () {
|
||||
conversationIsMuted() {
|
||||
return this.status.thread_muted
|
||||
},
|
||||
domain () {
|
||||
domain() {
|
||||
return this.user.fqn.split('@')[1]
|
||||
},
|
||||
domainIsMuted () {
|
||||
return new Set(this.$store.state.users.currentUser.domainMutes).has(this.domain)
|
||||
}
|
||||
domainIsMuted() {
|
||||
return new Set(this.$store.state.users.currentUser.domainMutes).has(
|
||||
this.domain,
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
unmuteUser () {
|
||||
unmuteUser() {
|
||||
return this.$store.dispatch('unmuteUser', this.user.id)
|
||||
},
|
||||
unmuteConversation () {
|
||||
unmuteConversation() {
|
||||
return this.$store.dispatch('unmuteConversation', { id: this.status.id })
|
||||
},
|
||||
unmuteDomain () {
|
||||
unmuteDomain() {
|
||||
return this.$store.dispatch('unmuteDomain', this.domain)
|
||||
},
|
||||
toggleUserMute () {
|
||||
toggleUserMute() {
|
||||
if (this.userIsMuted) {
|
||||
this.unmuteUser()
|
||||
} else {
|
||||
this.$refs.confirmUser.optionallyPrompt()
|
||||
}
|
||||
},
|
||||
toggleConversationMute () {
|
||||
toggleConversationMute() {
|
||||
if (this.conversationIsMuted) {
|
||||
this.unmuteConversation()
|
||||
} else {
|
||||
this.$refs.confirmConversation.optionallyPrompt()
|
||||
}
|
||||
},
|
||||
toggleDomainMute () {
|
||||
toggleDomainMute() {
|
||||
if (this.domainIsMuted) {
|
||||
this.unmuteDomain()
|
||||
} else {
|
||||
this.$refs.confirmDomain.optionallyPrompt()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,257 +4,282 @@ import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
|||
|
||||
const PRIVATE_SCOPES = new Set(['private', 'direct'])
|
||||
const PUBLIC_SCOPES = new Set(['public', 'unlisted'])
|
||||
export const BUTTONS = [{
|
||||
// =========
|
||||
// REPLY
|
||||
// =========
|
||||
name: 'reply',
|
||||
label: 'tool_tip.reply',
|
||||
icon: 'reply',
|
||||
active: ({ replying }) => replying,
|
||||
counter: ({ status }) => status.replies_count,
|
||||
anon: true,
|
||||
anonLink: true,
|
||||
toggleable: true,
|
||||
closeIndicator: 'times',
|
||||
activeIndicator: 'none',
|
||||
action ({ emit }) {
|
||||
emit('toggleReplying')
|
||||
return Promise.resolve()
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// REPEAT
|
||||
// =========
|
||||
name: 'retweet',
|
||||
label: ({ status }) => status.repeated
|
||||
? 'tool_tip.unrepeat'
|
||||
: 'tool_tip.repeat',
|
||||
icon ({ status, currentUser }) {
|
||||
if (currentUser.id !== status.user.id && PRIVATE_SCOPES.has(status.visibility)) {
|
||||
return 'lock'
|
||||
}
|
||||
return 'retweet'
|
||||
export const BUTTONS = [
|
||||
{
|
||||
// =========
|
||||
// REPLY
|
||||
// =========
|
||||
name: 'reply',
|
||||
label: 'tool_tip.reply',
|
||||
icon: 'reply',
|
||||
active: ({ replying }) => replying,
|
||||
counter: ({ status }) => status.replies_count,
|
||||
anon: true,
|
||||
anonLink: true,
|
||||
toggleable: true,
|
||||
closeIndicator: 'times',
|
||||
activeIndicator: 'none',
|
||||
action({ emit }) {
|
||||
emit('toggleReplying')
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
animated: true,
|
||||
active: ({ status }) => status.repeated,
|
||||
counter: ({ status }) => status.repeat_num,
|
||||
anonLink: true,
|
||||
interactive: ({ status, currentUser }) => !!currentUser && (currentUser.id === status.user.id || !PRIVATE_SCOPES.has(status.visibility)),
|
||||
toggleable: true,
|
||||
confirm: ({ status, getters }) => !status.repeated && getters.mergedConfig.modalOnRepeat,
|
||||
confirmStrings: {
|
||||
title: 'status.repeat_confirm_title',
|
||||
body: 'status.repeat_confirm',
|
||||
confirm: 'status.repeat_confirm_accept_button',
|
||||
cancel: 'status.repeat_confirm_cancel_button'
|
||||
{
|
||||
// =========
|
||||
// REPEAT
|
||||
// =========
|
||||
name: 'retweet',
|
||||
label: ({ status }) =>
|
||||
status.repeated ? 'tool_tip.unrepeat' : 'tool_tip.repeat',
|
||||
icon({ status, currentUser }) {
|
||||
if (
|
||||
currentUser.id !== status.user.id &&
|
||||
PRIVATE_SCOPES.has(status.visibility)
|
||||
) {
|
||||
return 'lock'
|
||||
}
|
||||
return 'retweet'
|
||||
},
|
||||
animated: true,
|
||||
active: ({ status }) => status.repeated,
|
||||
counter: ({ status }) => status.repeat_num,
|
||||
anonLink: true,
|
||||
interactive: ({ status, currentUser }) =>
|
||||
!!currentUser &&
|
||||
(currentUser.id === status.user.id ||
|
||||
!PRIVATE_SCOPES.has(status.visibility)),
|
||||
toggleable: true,
|
||||
confirm: ({ status, getters }) =>
|
||||
!status.repeated && getters.mergedConfig.modalOnRepeat,
|
||||
confirmStrings: {
|
||||
title: 'status.repeat_confirm_title',
|
||||
body: 'status.repeat_confirm',
|
||||
confirm: 'status.repeat_confirm_accept_button',
|
||||
cancel: 'status.repeat_confirm_cancel_button',
|
||||
},
|
||||
action({ status, dispatch }) {
|
||||
if (!status.repeated) {
|
||||
return dispatch('retweet', { id: status.id })
|
||||
} else {
|
||||
return dispatch('unretweet', { id: status.id })
|
||||
}
|
||||
},
|
||||
},
|
||||
action ({ status, dispatch }) {
|
||||
if (!status.repeated) {
|
||||
return dispatch('retweet', { id: status.id })
|
||||
} else {
|
||||
return dispatch('unretweet', { id: status.id })
|
||||
}
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// FAVORITE
|
||||
// =========
|
||||
name: 'favorite',
|
||||
label: ({ status }) => status.favorited
|
||||
? 'tool_tip.unfavorite'
|
||||
: 'tool_tip.favorite',
|
||||
icon: ({ status }) => status.favorited
|
||||
? ['fas', 'star']
|
||||
: ['far', 'star'],
|
||||
animated: true,
|
||||
active: ({ status }) => status.favorited,
|
||||
counter: ({ status }) => status.fave_num,
|
||||
anonLink: true,
|
||||
toggleable: true,
|
||||
action ({ status, dispatch }) {
|
||||
if (!status.favorited) {
|
||||
return dispatch('favorite', { id: status.id })
|
||||
} else {
|
||||
return dispatch('unfavorite', { id: status.id })
|
||||
}
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// EMOJI REACTIONS
|
||||
// =========
|
||||
name: 'emoji',
|
||||
label: 'tool_tip.add_reaction',
|
||||
icon: ['far', 'smile-beam'],
|
||||
anonLink: true
|
||||
}, {
|
||||
// =========
|
||||
// MUTE
|
||||
// =========
|
||||
name: 'mute',
|
||||
icon: 'eye-slash',
|
||||
label: 'status.mute_ellipsis',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
toggleable: true,
|
||||
dropdown: true
|
||||
// action ({ status, dispatch, emit }) {
|
||||
// }
|
||||
}, {
|
||||
// =========
|
||||
// PIN STATUS
|
||||
// =========
|
||||
name: 'pin',
|
||||
icon: 'thumbtack',
|
||||
label: ({ status }) => status.pinned
|
||||
? 'status.unpin'
|
||||
: 'status.pin',
|
||||
if ({ status, loggedIn, currentUser }) {
|
||||
return loggedIn &&
|
||||
status.user.id === currentUser.id &&
|
||||
PUBLIC_SCOPES.has(status.visibility)
|
||||
{
|
||||
// =========
|
||||
// FAVORITE
|
||||
// =========
|
||||
name: 'favorite',
|
||||
label: ({ status }) =>
|
||||
status.favorited ? 'tool_tip.unfavorite' : 'tool_tip.favorite',
|
||||
icon: ({ status }) =>
|
||||
status.favorited ? ['fas', 'star'] : ['far', 'star'],
|
||||
animated: true,
|
||||
active: ({ status }) => status.favorited,
|
||||
counter: ({ status }) => status.fave_num,
|
||||
anonLink: true,
|
||||
toggleable: true,
|
||||
action({ status, dispatch }) {
|
||||
if (!status.favorited) {
|
||||
return dispatch('favorite', { id: status.id })
|
||||
} else {
|
||||
return dispatch('unfavorite', { id: status.id })
|
||||
}
|
||||
},
|
||||
},
|
||||
action ({ status, dispatch }) {
|
||||
if (status.pinned) {
|
||||
return dispatch('unpinStatus', status.id)
|
||||
} else {
|
||||
return dispatch('pinStatus', status.id)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// BOOKMARK
|
||||
// =========
|
||||
name: 'bookmark',
|
||||
icon: ({ status }) => status.bookmarked
|
||||
? ['fas', 'bookmark']
|
||||
: ['far', 'bookmark'],
|
||||
toggleable: true,
|
||||
active: ({ status }) => status.bookmarked,
|
||||
label: ({ status }) => status.bookmarked
|
||||
? 'status.unbookmark'
|
||||
: 'status.bookmark',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
action ({ status, dispatch }) {
|
||||
if (status.bookmarked) {
|
||||
return dispatch('unbookmark', { id: status.id })
|
||||
} else {
|
||||
return dispatch('bookmark', { id: status.id })
|
||||
}
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// EDIT HISTORY
|
||||
// =========
|
||||
name: 'editHistory',
|
||||
icon: 'history',
|
||||
label: 'status.status_history',
|
||||
if ({ status, state }) {
|
||||
return state.instance.editingAvailable &&
|
||||
status.edited_at !== null
|
||||
{
|
||||
// =========
|
||||
// EMOJI REACTIONS
|
||||
// =========
|
||||
name: 'emoji',
|
||||
label: 'tool_tip.add_reaction',
|
||||
icon: ['far', 'smile-beam'],
|
||||
anonLink: true,
|
||||
},
|
||||
action ({ status }) {
|
||||
const originalStatus = { ...status }
|
||||
const stripFieldsList = [
|
||||
'attachments',
|
||||
'created_at',
|
||||
'emojis',
|
||||
'text',
|
||||
'raw_html',
|
||||
'nsfw',
|
||||
'poll',
|
||||
'summary',
|
||||
'summary_raw_html'
|
||||
]
|
||||
stripFieldsList.forEach(p => delete originalStatus[p])
|
||||
useStatusHistoryStore().openStatusHistoryModal(originalStatus)
|
||||
return Promise.resolve()
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// EDIT
|
||||
// =========
|
||||
name: 'edit',
|
||||
icon: 'pen',
|
||||
label: 'status.edit',
|
||||
if ({ status, loggedIn, currentUser, state }) {
|
||||
return loggedIn &&
|
||||
state.instance.editingAvailable &&
|
||||
status.user.id === currentUser.id
|
||||
{
|
||||
// =========
|
||||
// MUTE
|
||||
// =========
|
||||
name: 'mute',
|
||||
icon: 'eye-slash',
|
||||
label: 'status.mute_ellipsis',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
toggleable: true,
|
||||
dropdown: true,
|
||||
// action ({ status, dispatch, emit }) {
|
||||
// }
|
||||
},
|
||||
action ({ dispatch, status }) {
|
||||
return dispatch('fetchStatusSource', { id: status.id })
|
||||
.then(data => useEditStatusStore().openEditStatusModal({
|
||||
statusId: status.id,
|
||||
subject: data.spoiler_text,
|
||||
statusText: data.text,
|
||||
statusIsSensitive: status.nsfw,
|
||||
statusPoll: status.poll,
|
||||
statusFiles: [...status.attachments],
|
||||
visibility: status.visibility,
|
||||
statusContentType: data.content_type
|
||||
}))
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// DELETE
|
||||
// =========
|
||||
name: 'delete',
|
||||
icon: 'times',
|
||||
label: 'status.delete',
|
||||
if ({ status, loggedIn, currentUser }) {
|
||||
return loggedIn && (
|
||||
status.user.id === currentUser.id ||
|
||||
currentUser.privileges.includes('messages_delete')
|
||||
)
|
||||
{
|
||||
// =========
|
||||
// PIN STATUS
|
||||
// =========
|
||||
name: 'pin',
|
||||
icon: 'thumbtack',
|
||||
label: ({ status }) => (status.pinned ? 'status.unpin' : 'status.pin'),
|
||||
if({ status, loggedIn, currentUser }) {
|
||||
return (
|
||||
loggedIn &&
|
||||
status.user.id === currentUser.id &&
|
||||
PUBLIC_SCOPES.has(status.visibility)
|
||||
)
|
||||
},
|
||||
action({ status, dispatch }) {
|
||||
if (status.pinned) {
|
||||
return dispatch('unpinStatus', status.id)
|
||||
} else {
|
||||
return dispatch('pinStatus', status.id)
|
||||
}
|
||||
},
|
||||
},
|
||||
confirm: ({ getters }) => getters.mergedConfig.modalOnDelete,
|
||||
confirmStrings: {
|
||||
title: 'status.delete_confirm_title',
|
||||
body: 'status.delete_confirm',
|
||||
confirm: 'status.delete_confirm_accept_button',
|
||||
cancel: 'status.delete_confirm_cancel_button'
|
||||
{
|
||||
// =========
|
||||
// BOOKMARK
|
||||
// =========
|
||||
name: 'bookmark',
|
||||
icon: ({ status }) =>
|
||||
status.bookmarked ? ['fas', 'bookmark'] : ['far', 'bookmark'],
|
||||
toggleable: true,
|
||||
active: ({ status }) => status.bookmarked,
|
||||
label: ({ status }) =>
|
||||
status.bookmarked ? 'status.unbookmark' : 'status.bookmark',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
action({ status, dispatch }) {
|
||||
if (status.bookmarked) {
|
||||
return dispatch('unbookmark', { id: status.id })
|
||||
} else {
|
||||
return dispatch('bookmark', { id: status.id })
|
||||
}
|
||||
},
|
||||
},
|
||||
action ({ dispatch, status }) {
|
||||
return dispatch('deleteStatus', { id: status.id })
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// SHARE/COPY
|
||||
// =========
|
||||
name: 'share',
|
||||
icon: 'share-alt',
|
||||
label: 'status.copy_link',
|
||||
action ({ state, status, router }) {
|
||||
navigator.clipboard.writeText([
|
||||
state.instance.server,
|
||||
router.resolve({ name: 'conversation', params: { id: status.id } }).href
|
||||
].join(''))
|
||||
return Promise.resolve()
|
||||
}
|
||||
}, {
|
||||
// =========
|
||||
// EXTERNAL
|
||||
// =========
|
||||
name: 'external',
|
||||
icon: 'external-link-alt',
|
||||
label: 'status.external_source',
|
||||
link: ({ status }) => status.external_url
|
||||
}, {
|
||||
// =========
|
||||
// REPORT
|
||||
// =========
|
||||
name: 'report',
|
||||
icon: 'flag',
|
||||
label: 'user_card.report',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
action ({ status }) {
|
||||
return useReportsStore().openUserReportingModal({ userId: status.user.id, statusIds: [status.id] })
|
||||
}
|
||||
}].map(button => {
|
||||
{
|
||||
// =========
|
||||
// EDIT HISTORY
|
||||
// =========
|
||||
name: 'editHistory',
|
||||
icon: 'history',
|
||||
label: 'status.status_history',
|
||||
if({ status, state }) {
|
||||
return state.instance.editingAvailable && status.edited_at !== null
|
||||
},
|
||||
action({ status }) {
|
||||
const originalStatus = { ...status }
|
||||
const stripFieldsList = [
|
||||
'attachments',
|
||||
'created_at',
|
||||
'emojis',
|
||||
'text',
|
||||
'raw_html',
|
||||
'nsfw',
|
||||
'poll',
|
||||
'summary',
|
||||
'summary_raw_html',
|
||||
]
|
||||
stripFieldsList.forEach((p) => delete originalStatus[p])
|
||||
useStatusHistoryStore().openStatusHistoryModal(originalStatus)
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
{
|
||||
// =========
|
||||
// EDIT
|
||||
// =========
|
||||
name: 'edit',
|
||||
icon: 'pen',
|
||||
label: 'status.edit',
|
||||
if({ status, loggedIn, currentUser, state }) {
|
||||
return (
|
||||
loggedIn &&
|
||||
state.instance.editingAvailable &&
|
||||
status.user.id === currentUser.id
|
||||
)
|
||||
},
|
||||
action({ dispatch, status }) {
|
||||
return dispatch('fetchStatusSource', { id: status.id }).then((data) =>
|
||||
useEditStatusStore().openEditStatusModal({
|
||||
statusId: status.id,
|
||||
subject: data.spoiler_text,
|
||||
statusText: data.text,
|
||||
statusIsSensitive: status.nsfw,
|
||||
statusPoll: status.poll,
|
||||
statusFiles: [...status.attachments],
|
||||
visibility: status.visibility,
|
||||
statusContentType: data.content_type,
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
// =========
|
||||
// DELETE
|
||||
// =========
|
||||
name: 'delete',
|
||||
icon: 'times',
|
||||
label: 'status.delete',
|
||||
if({ status, loggedIn, currentUser }) {
|
||||
return (
|
||||
loggedIn &&
|
||||
(status.user.id === currentUser.id ||
|
||||
currentUser.privileges.includes('messages_delete'))
|
||||
)
|
||||
},
|
||||
confirm: ({ getters }) => getters.mergedConfig.modalOnDelete,
|
||||
confirmStrings: {
|
||||
title: 'status.delete_confirm_title',
|
||||
body: 'status.delete_confirm',
|
||||
confirm: 'status.delete_confirm_accept_button',
|
||||
cancel: 'status.delete_confirm_cancel_button',
|
||||
},
|
||||
action({ dispatch, status }) {
|
||||
return dispatch('deleteStatus', { id: status.id })
|
||||
},
|
||||
},
|
||||
{
|
||||
// =========
|
||||
// SHARE/COPY
|
||||
// =========
|
||||
name: 'share',
|
||||
icon: 'share-alt',
|
||||
label: 'status.copy_link',
|
||||
action({ state, status, router }) {
|
||||
navigator.clipboard.writeText(
|
||||
[
|
||||
state.instance.server,
|
||||
router.resolve({ name: 'conversation', params: { id: status.id } })
|
||||
.href,
|
||||
].join(''),
|
||||
)
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
{
|
||||
// =========
|
||||
// EXTERNAL
|
||||
// =========
|
||||
name: 'external',
|
||||
icon: 'external-link-alt',
|
||||
label: 'status.external_source',
|
||||
link: ({ status }) => status.external_url,
|
||||
},
|
||||
{
|
||||
// =========
|
||||
// REPORT
|
||||
// =========
|
||||
name: 'report',
|
||||
icon: 'flag',
|
||||
label: 'user_card.report',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
action({ status }) {
|
||||
return useReportsStore().openUserReportingModal({
|
||||
userId: status.user.id,
|
||||
statusIds: [status.id],
|
||||
})
|
||||
},
|
||||
},
|
||||
].map((button) => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(button).map(([k, v]) => [
|
||||
k,
|
||||
(typeof v === 'function' || k === 'name') ? v : () => v
|
||||
])
|
||||
typeof v === 'function' || k === 'name' ? v : () => v,
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,59 +1,56 @@
|
|||
import { mapState } from 'pinia'
|
||||
|
||||
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
|
||||
import ActionButtonContainer from './action_button_container.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import genRandomSeed from 'src/services/random_seed/random_seed.service.js'
|
||||
|
||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||
|
||||
import ActionButtonContainer from './action_button_container.vue'
|
||||
import { BUTTONS } from './buttons_definitions.js'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faEllipsisH
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { faEllipsisH } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faEllipsisH
|
||||
)
|
||||
library.add(faEllipsisH)
|
||||
|
||||
const StatusActionButtons = {
|
||||
props: ['status', 'replying'],
|
||||
emits: ['toggleReplying', 'interacted'],
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
showPin: false,
|
||||
showingConfirmDialog: false,
|
||||
currentConfirmTitle: '',
|
||||
currentConfirmOkText: '',
|
||||
currentConfirmCancelText: '',
|
||||
currentConfirmAction: () => {},
|
||||
randomSeed: genRandomSeed()
|
||||
currentConfirmAction: () => {
|
||||
/* no-op */
|
||||
},
|
||||
randomSeed: genRandomSeed(),
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Popover,
|
||||
ConfirmModal,
|
||||
ActionButtonContainer
|
||||
ActionButtonContainer,
|
||||
},
|
||||
computed: {
|
||||
...mapState(useServerSideStorageStore, {
|
||||
pinnedItems: store => new Set(store.prefsStorage.collections.pinnedStatusActions)
|
||||
pinnedItems: (store) =>
|
||||
new Set(store.prefsStorage.collections.pinnedStatusActions),
|
||||
}),
|
||||
buttons () {
|
||||
return BUTTONS.filter(x => x.if ? x.if(this.funcArg) : true)
|
||||
buttons() {
|
||||
return BUTTONS.filter((x) => (x.if ? x.if(this.funcArg) : true))
|
||||
},
|
||||
quickButtons () {
|
||||
return this.buttons.filter(x => this.pinnedItems.has(x.name))
|
||||
quickButtons() {
|
||||
return this.buttons.filter((x) => this.pinnedItems.has(x.name))
|
||||
},
|
||||
extraButtons () {
|
||||
return this.buttons.filter(x => !this.pinnedItems.has(x.name))
|
||||
extraButtons() {
|
||||
return this.buttons.filter((x) => !this.pinnedItems.has(x.name))
|
||||
},
|
||||
currentUser () {
|
||||
currentUser() {
|
||||
return this.$store.state.users.currentUser
|
||||
},
|
||||
funcArg () {
|
||||
funcArg() {
|
||||
return {
|
||||
status: this.status,
|
||||
replying: this.replying,
|
||||
|
|
@ -63,25 +60,33 @@ const StatusActionButtons = {
|
|||
getters: this.$store.getters,
|
||||
router: this.$router,
|
||||
currentUser: this.currentUser,
|
||||
loggedIn: !!this.currentUser
|
||||
loggedIn: !!this.currentUser,
|
||||
}
|
||||
},
|
||||
triggerAttrs () {
|
||||
triggerAttrs() {
|
||||
return {
|
||||
title: this.$t('status.more_actions'),
|
||||
'aria-controls': `popup-menu-${this.randomSeed}`,
|
||||
'aria-haspopup': 'menu'
|
||||
'aria-haspopup': 'menu',
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
doAction (button) {
|
||||
doAction(button) {
|
||||
if (button.confirm?.(this.funcArg)) {
|
||||
// TODO move to action_button
|
||||
this.currentConfirmTitle = this.$t(button.confirmStrings(this.funcArg).title)
|
||||
this.currentConfirmOkText = this.$t(button.confirmStrings(this.funcArg).confirm)
|
||||
this.currentConfirmCancelText = this.$t(button.confirmStrings(this.funcArg).cancel)
|
||||
this.currentConfirmBody = this.$t(button.confirmStrings(this.funcArg).body)
|
||||
this.currentConfirmTitle = this.$t(
|
||||
button.confirmStrings(this.funcArg).title,
|
||||
)
|
||||
this.currentConfirmOkText = this.$t(
|
||||
button.confirmStrings(this.funcArg).confirm,
|
||||
)
|
||||
this.currentConfirmCancelText = this.$t(
|
||||
button.confirmStrings(this.funcArg).cancel,
|
||||
)
|
||||
this.currentConfirmBody = this.$t(
|
||||
button.confirmStrings(this.funcArg).body,
|
||||
)
|
||||
this.currentConfirmAction = () => {
|
||||
this.showingConfirmDialog = false
|
||||
this.doActionReal(button)
|
||||
|
|
@ -91,26 +96,33 @@ const StatusActionButtons = {
|
|||
this.doActionReal(button)
|
||||
}
|
||||
},
|
||||
doActionReal (button) {
|
||||
button.action(this.funcArg)
|
||||
doActionReal(button) {
|
||||
button
|
||||
.action(this.funcArg)
|
||||
.then(() => this.$emit('onSuccess'))
|
||||
.catch(err => this.$emit('onError', err.error.error))
|
||||
.catch((err) => this.$emit('onError', err.error.error))
|
||||
},
|
||||
onExtraClose () {
|
||||
onExtraClose() {
|
||||
this.showPin = false
|
||||
},
|
||||
isPinned (button) {
|
||||
isPinned(button) {
|
||||
return this.pinnedItems.has(button.name)
|
||||
},
|
||||
unpin (button) {
|
||||
useServerSideStorageStore().removeCollectionPreference({ path: 'collections.pinnedStatusActions', value: button.name })
|
||||
unpin(button) {
|
||||
useServerSideStorageStore().removeCollectionPreference({
|
||||
path: 'collections.pinnedStatusActions',
|
||||
value: button.name,
|
||||
})
|
||||
useServerSideStorageStore().pushServerSideStorage()
|
||||
},
|
||||
pin (button) {
|
||||
useServerSideStorageStore().addCollectionPreference({ path: 'collections.pinnedStatusActions', value: button.name })
|
||||
pin(button) {
|
||||
useServerSideStorageStore().addCollectionPreference({
|
||||
path: 'collections.pinnedStatusActions',
|
||||
value: button.name,
|
||||
})
|
||||
useServerSideStorageStore().pushServerSideStorage()
|
||||
},
|
||||
getComponent (button) {
|
||||
getComponent(button) {
|
||||
if (!this.$store.state.users.currentUser && button.anonLink) {
|
||||
return 'a'
|
||||
} else if (button.action == null && button.link != null) {
|
||||
|
|
@ -119,16 +131,18 @@ const StatusActionButtons = {
|
|||
return 'button'
|
||||
}
|
||||
},
|
||||
getClass (button) {
|
||||
getClass(button) {
|
||||
return {
|
||||
[button.name + '-button']: true,
|
||||
disabled: button.interactive ? !button.interactive(this.funcArg) : false,
|
||||
disabled: button.interactive
|
||||
? !button.interactive(this.funcArg)
|
||||
: false,
|
||||
'-pin-edit': this.showPin,
|
||||
'-dropdown': button.dropdown?.(),
|
||||
'-active': button.active?.(this.funcArg)
|
||||
'-active': button.active?.(this.funcArg),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default StatusActionButtons
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
:func-arg="funcArg"
|
||||
:get-class="getClass"
|
||||
:get-component="getComponent"
|
||||
:close="() => {}"
|
||||
:close="() => { /* no-op */ }"
|
||||
:do-action="doAction"
|
||||
@interacted="e => $emit('interacted')"
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue