Merge develop and fix conflict
This commit is contained in:
commit
0ab828bb30
25 changed files with 2489 additions and 312 deletions
|
@ -14,7 +14,7 @@ const Attachment = {
|
|||
],
|
||||
data () {
|
||||
return {
|
||||
nsfwImage: this.$store.state.config.nsfwCensorImage || nsfwImage,
|
||||
nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage,
|
||||
hideNsfwLocal: this.$store.state.config.hideNsfw,
|
||||
preloadImage: this.$store.state.config.preloadImage,
|
||||
loading: false,
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
:href="attachment.url" target="_blank"
|
||||
:title="attachment.description"
|
||||
>
|
||||
<StillImage referrerpolicy="referrerPolicy" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/>
|
||||
<StillImage :referrerpolicy="referrerpolicy" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/>
|
||||
</a>
|
||||
|
||||
<a class="video-container"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Conversation from '../conversation/conversation.vue'
|
||||
import { find, toInteger } from 'lodash'
|
||||
import { find } from 'lodash'
|
||||
|
||||
const conversationPage = {
|
||||
components: {
|
||||
|
@ -7,7 +7,7 @@ const conversationPage = {
|
|||
},
|
||||
computed: {
|
||||
statusoid () {
|
||||
const id = toInteger(this.$route.params.id)
|
||||
const id = this.$route.params.id
|
||||
const statuses = this.$store.state.statuses.allStatuses
|
||||
const status = find(statuses, {id})
|
||||
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
import { reduce, filter, sortBy } from 'lodash'
|
||||
import { statusType } from '../../modules/statuses.js'
|
||||
import { reduce, filter } from 'lodash'
|
||||
import Status from '../status/status.vue'
|
||||
|
||||
const sortById = (a, b) => {
|
||||
const seqA = Number(a.id)
|
||||
const seqB = Number(b.id)
|
||||
const isSeqA = !Number.isNaN(seqA)
|
||||
const isSeqB = !Number.isNaN(seqB)
|
||||
if (isSeqA && isSeqB) {
|
||||
return seqA < seqB ? -1 : 1
|
||||
} else if (isSeqA && !isSeqB) {
|
||||
return 1
|
||||
} else if (!isSeqA && isSeqB) {
|
||||
return -1
|
||||
} else {
|
||||
return a.id < b.id ? -1 : 1
|
||||
}
|
||||
}
|
||||
|
||||
const sortAndFilterConversation = (conversation) => {
|
||||
conversation = filter(conversation, (status) => statusType(status) !== 'retweet')
|
||||
return sortBy(conversation, 'id')
|
||||
conversation = filter(conversation, (status) => status.type !== 'retweet')
|
||||
return conversation.filter(_ => _).sort(sortById)
|
||||
}
|
||||
|
||||
const conversation = {
|
||||
|
@ -18,10 +33,12 @@ const conversation = {
|
|||
'collapsable'
|
||||
],
|
||||
computed: {
|
||||
status () { return this.statusoid },
|
||||
status () {
|
||||
return this.statusoid
|
||||
},
|
||||
conversation () {
|
||||
if (!this.status) {
|
||||
return false
|
||||
return []
|
||||
}
|
||||
|
||||
const conversationId = this.status.statusnet_conversation_id
|
||||
|
@ -32,7 +49,9 @@ const conversation = {
|
|||
replies () {
|
||||
let i = 1
|
||||
return reduce(this.conversation, (result, {id, in_reply_to_status_id}) => {
|
||||
const irid = Number(in_reply_to_status_id)
|
||||
/* eslint-disable camelcase */
|
||||
const irid = in_reply_to_status_id
|
||||
/* eslint-enable camelcase */
|
||||
if (irid) {
|
||||
result[irid] = result[irid] || []
|
||||
result[irid].push({
|
||||
|
@ -69,7 +88,6 @@ const conversation = {
|
|||
}
|
||||
},
|
||||
getReplies (id) {
|
||||
id = Number(id)
|
||||
return this.replies[id] || []
|
||||
},
|
||||
focused (id) {
|
||||
|
@ -80,7 +98,7 @@ const conversation = {
|
|||
}
|
||||
},
|
||||
setHighlight (id) {
|
||||
this.highlight = Number(id)
|
||||
this.highlight = id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,14 @@ const Status = {
|
|||
return (this.$store.state.config.hideAttachments && !this.inConversation) ||
|
||||
(this.$store.state.config.hideAttachmentsInConv && this.inConversation)
|
||||
},
|
||||
userProfileLink () {
|
||||
return this.generateUserProfileLink(this.status.user.id, this.status.user.screen_name)
|
||||
},
|
||||
replyProfileLink () {
|
||||
if (this.isReply) {
|
||||
return this.generateUserProfileLink(this.status.in_reply_to_status_id, this.replyToName)
|
||||
}
|
||||
},
|
||||
retweet () { return !!this.statusoid.retweeted_status },
|
||||
retweeter () { return this.statusoid.user.name },
|
||||
retweeterHtml () { return this.statusoid.user.name_html },
|
||||
|
@ -122,6 +130,14 @@ const Status = {
|
|||
isReply () {
|
||||
return !!this.status.in_reply_to_status_id
|
||||
},
|
||||
replyToName () {
|
||||
const user = this.$store.state.users.usersObject[this.status.in_reply_to_user_id]
|
||||
if (user) {
|
||||
return user.screen_name
|
||||
} else {
|
||||
return this.status.in_reply_to_screen_name
|
||||
}
|
||||
},
|
||||
hideReply () {
|
||||
if (this.$store.state.config.replyVisibility === 'all') {
|
||||
return false
|
||||
|
@ -132,7 +148,7 @@ const Status = {
|
|||
if (this.status.user.id === this.$store.state.users.currentUser.id) {
|
||||
return false
|
||||
}
|
||||
if (this.status.activity_type === 'repeat') {
|
||||
if (this.status.type === 'retweet') {
|
||||
return false
|
||||
}
|
||||
var checkFollowing = this.$store.state.config.replyVisibility === 'following'
|
||||
|
@ -281,7 +297,7 @@ const Status = {
|
|||
},
|
||||
replyEnter (id, event) {
|
||||
this.showPreview = true
|
||||
const targetId = Number(id)
|
||||
const targetId = id
|
||||
const statuses = this.$store.state.statuses.allStatuses
|
||||
|
||||
if (!this.preview) {
|
||||
|
@ -300,7 +316,7 @@ const Status = {
|
|||
replyLeave () {
|
||||
this.showPreview = false
|
||||
},
|
||||
userProfileLink (id, name) {
|
||||
generateUserProfileLink (id, name) {
|
||||
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
|
||||
},
|
||||
setMedia () {
|
||||
|
@ -310,7 +326,6 @@ const Status = {
|
|||
},
|
||||
watch: {
|
||||
'highlight': function (id) {
|
||||
id = Number(id)
|
||||
if (this.status.id === id) {
|
||||
let rect = this.$el.getBoundingClientRect()
|
||||
if (rect.top < 100) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<template v-if="muted && !noReplyLinks">
|
||||
<div class="media status container muted">
|
||||
<small>
|
||||
<router-link :to="userProfileLink(status.user.id, status.user.screen_name)">
|
||||
<router-link :to="userProfileLink">
|
||||
{{status.user.screen_name}}
|
||||
</router-link>
|
||||
</small>
|
||||
|
@ -38,16 +38,16 @@
|
|||
<h4 class="user-name" v-if="status.user.name_html" v-html="status.user.name_html"></h4>
|
||||
<h4 class="user-name" v-else>{{status.user.name}}</h4>
|
||||
<span class="links">
|
||||
<router-link :to="userProfileLink(status.user.id, status.user.screen_name)">
|
||||
<router-link :to="userProfileLink">
|
||||
{{status.user.screen_name}}
|
||||
</router-link>
|
||||
<span v-if="status.in_reply_to_screen_name" class="faint reply-info">
|
||||
<span v-if="isReply" class="faint reply-info">
|
||||
<i class="icon-right-open"></i>
|
||||
<router-link :to="userProfileLink(status.in_reply_to_user_id, status.in_reply_to_screen_name)">
|
||||
{{status.in_reply_to_screen_name}}
|
||||
<router-link :to="replyProfileLink">
|
||||
{{replyToName}}
|
||||
</router-link>
|
||||
</span>
|
||||
<a v-if="isReply && !noReplyLinks" href="#" @click.prevent="gotoOriginal(status.in_reply_to_status_id)" :title="$t('tool_tip.reply')">
|
||||
<a v-if="isReply && !noReplyLinks" href="#" @click.prevent="gotoOriginal(status.in_reply_to_status_id)" :aria-label="$t('tool_tip.reply')">
|
||||
<i class="button-icon icon-reply" @mouseenter="replyEnter(status.in_reply_to_status_id, $event)" @mouseout="replyLeave()"></i>
|
||||
</a>
|
||||
</span>
|
||||
|
|
|
@ -6,18 +6,26 @@ export default Vue.component('tab-switcher', {
|
|||
name: 'TabSwitcher',
|
||||
data () {
|
||||
return {
|
||||
active: 0
|
||||
active: this.$slots.default.findIndex(_ => _.tag)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
activateTab(index) {
|
||||
return () => this.active = index;
|
||||
activateTab (index) {
|
||||
return () => {
|
||||
this.active = index
|
||||
}
|
||||
}
|
||||
},
|
||||
render(h) {
|
||||
beforeUpdate () {
|
||||
const currentSlot = this.$slots.default[this.active]
|
||||
if (!currentSlot.tag) {
|
||||
this.active = this.$slots.default.findIndex(_ => _.tag)
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
const tabs = this.$slots.default
|
||||
.filter(slot => slot.data)
|
||||
.map((slot, index) => {
|
||||
if (!slot.tag) return
|
||||
const classesTab = ['tab']
|
||||
const classesWrapper = ['tab-wrapper']
|
||||
|
||||
|
@ -25,20 +33,24 @@ export default Vue.component('tab-switcher', {
|
|||
classesTab.push('active')
|
||||
classesWrapper.push('active')
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={ classesWrapper.join(' ')}>
|
||||
<button onClick={this.activateTab(index)} class={ classesTab.join(' ') }>{slot.data.attrs.label}</button>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
const contents = this.$slots.default.filter(_=>_.data).map(( slot, index ) => {
|
||||
})
|
||||
|
||||
const contents = this.$slots.default.map((slot, index) => {
|
||||
if (!slot.tag) return
|
||||
const active = index === this.active
|
||||
return (
|
||||
<div class={active ? 'active' : 'hidden'}>
|
||||
{slot}
|
||||
</div>
|
||||
)
|
||||
});
|
||||
})
|
||||
|
||||
return (
|
||||
<div class="tab-switcher">
|
||||
<div class="tabs">
|
||||
|
|
|
@ -5,24 +5,33 @@ import Timeline from '../timeline/timeline.vue'
|
|||
const UserProfile = {
|
||||
created () {
|
||||
this.$store.commit('clearTimeline', { timeline: 'user' })
|
||||
this.$store.commit('clearTimeline', { timeline: 'favorites' })
|
||||
this.$store.dispatch('startFetching', ['user', this.fetchBy])
|
||||
this.$store.dispatch('startFetching', ['favorites', this.fetchBy])
|
||||
if (!this.user.id) {
|
||||
this.$store.dispatch('fetchUser', this.fetchBy)
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
this.$store.dispatch('stopFetching', 'user')
|
||||
this.$store.dispatch('stopFetching', 'favorites')
|
||||
},
|
||||
computed: {
|
||||
timeline () {
|
||||
return this.$store.state.statuses.timelines.user
|
||||
},
|
||||
favorites () {
|
||||
return this.$store.state.statuses.timelines.favorites
|
||||
},
|
||||
userId () {
|
||||
return this.$route.params.id || this.user.id
|
||||
},
|
||||
userName () {
|
||||
return this.$route.params.name || this.user.screen_name
|
||||
},
|
||||
isUs () {
|
||||
return this.userId === this.$store.state.users.currentUser.id
|
||||
},
|
||||
friends () {
|
||||
return this.user.friends
|
||||
},
|
||||
|
@ -62,21 +71,28 @@ const UserProfile = {
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
// TODO get rid of this copypasta
|
||||
userName () {
|
||||
if (this.isExternal) {
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('stopFetching', 'user')
|
||||
this.$store.dispatch('stopFetching', 'favorites')
|
||||
this.$store.commit('clearTimeline', { timeline: 'user' })
|
||||
this.$store.commit('clearTimeline', { timeline: 'favorites' })
|
||||
this.$store.dispatch('startFetching', ['user', this.fetchBy])
|
||||
this.$store.dispatch('startFetching', ['favorites', this.fetchBy])
|
||||
},
|
||||
userId () {
|
||||
if (!this.isExternal) {
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('stopFetching', 'user')
|
||||
this.$store.dispatch('stopFetching', 'favorites')
|
||||
this.$store.commit('clearTimeline', { timeline: 'user' })
|
||||
this.$store.commit('clearTimeline', { timeline: 'favorites' })
|
||||
this.$store.dispatch('startFetching', ['user', this.fetchBy])
|
||||
this.$store.dispatch('startFetching', ['favorites', this.fetchBy])
|
||||
},
|
||||
user () {
|
||||
if (this.user.id && !this.user.followers) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<i class="icon-spin3 animate-spin"></i>
|
||||
</div>
|
||||
</div>
|
||||
<Timeline v-if="isUs" :label="$t('user_card.favorites')" :embedded="true" :title="$t('user_profile.favorites_title')" timeline-name="favorites" :timeline="favorites"/>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
<div v-else class="panel user-profile-placeholder">
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import apiService from '../../services/api/api.service.js'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
import _ from 'lodash'
|
||||
import { shuffle } from 'lodash'
|
||||
|
||||
function showWhoToFollow (panel, reply) {
|
||||
_.shuffle(reply)
|
||||
const shuffled = shuffle(reply)
|
||||
|
||||
panel.usersToFollow.forEach((toFollow, index) => {
|
||||
let user = reply[index]
|
||||
let user = shuffled[index]
|
||||
let img = user.avatar || '/images/avi.png'
|
||||
let name = user.acct
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue