Merge branch 'develop' into 'feat/timeline-quick-settings'
# Conflicts: # CHANGELOG.md
This commit is contained in:
commit
91f93d4a55
37 changed files with 127 additions and 70 deletions
|
@ -9,14 +9,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Fixed shoutbox not working in mobile layout
|
- Fixed shoutbox not working in mobile layout
|
||||||
- Fixed missing highlighted border in expanded conversations again
|
- Fixed missing highlighted border in expanded conversations again
|
||||||
- Fixed some UI jumpiness when opening images particularly in chat view
|
- Fixed some UI jumpiness when opening images particularly in chat view
|
||||||
|
- Fixed chat unread badge looking weird
|
||||||
|
- Fixed punycode names not working properly
|
||||||
|
- Fixed notifications crashing on an invalid notification
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Display 'people voted' instead of 'votes' for multi-choice polls
|
- Display 'people voted' instead of 'votes' for multi-choice polls
|
||||||
- Optimized chat to not get horrible performance after keeping the same chat open for a long time
|
- Optimized chat to not get horrible performance after keeping the same chat open for a long time
|
||||||
|
- When opening emoji picker or react picker, it automatically focuses the search field
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added reason field for registration when approval is required
|
- Added reason field for registration when approval is required
|
||||||
- Added a quick settings to timeline header for easier access
|
- Added a quick settings to timeline header for easier access
|
||||||
|
- Added option to mark posts as sensitive by default
|
||||||
|
|
||||||
## [2.2.3] - 2021-01-18
|
## [2.2.3] - 2021-01-18
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -103,7 +103,7 @@
|
||||||
"selenium-server": "2.53.1",
|
"selenium-server": "2.53.1",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"serviceworker-webpack-plugin": "^1.0.0",
|
"serviceworker-webpack-plugin": "^1.0.0",
|
||||||
"shelljs": "^0.7.4",
|
"shelljs": "^0.8.4",
|
||||||
"sinon": "^2.1.0",
|
"sinon": "^2.1.0",
|
||||||
"sinon-chai": "^2.8.0",
|
"sinon-chai": "^2.8.0",
|
||||||
"stylelint": "^13.6.1",
|
"stylelint": "^13.6.1",
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
class="basic-user-card-screen-name"
|
class="basic-user-card-screen-name"
|
||||||
:to="userProfileLink(user)"
|
:to="userProfileLink(user)"
|
||||||
>
|
>
|
||||||
@{{ user.screen_name }}
|
@{{ user.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -73,7 +73,7 @@ const Chat = {
|
||||||
},
|
},
|
||||||
formPlaceholder () {
|
formPlaceholder () {
|
||||||
if (this.recipient) {
|
if (this.recipient) {
|
||||||
return this.$t('chats.message_user', { nickname: this.recipient.screen_name })
|
return this.$t('chats.message_user', { nickname: this.recipient.screen_name_ui })
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,10 +98,10 @@
|
||||||
.unread-message-count {
|
.unread-message-count {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
|
||||||
border-radius: 100%;
|
|
||||||
margin-top: -1rem;
|
margin-top: -1rem;
|
||||||
padding: 0;
|
padding: 0.1em;
|
||||||
|
border-radius: 50px;
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-loading-error {
|
.chat-loading-error {
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default Vue.component('chat-title', {
|
||||||
],
|
],
|
||||||
computed: {
|
computed: {
|
||||||
title () {
|
title () {
|
||||||
return this.user ? this.user.screen_name : ''
|
return this.user ? this.user.screen_name_ui : ''
|
||||||
},
|
},
|
||||||
htmlTitle () {
|
htmlTitle () {
|
||||||
return this.user ? this.user.name_html : ''
|
return this.user ? this.user.name_html : ''
|
||||||
|
|
|
@ -194,11 +194,18 @@ const EmojiInput = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
focusPickerInput () {
|
||||||
|
const pickerEl = this.$refs.picker.$el
|
||||||
|
if (!pickerEl) return
|
||||||
|
const pickerInput = pickerEl.querySelector('input')
|
||||||
|
if (pickerInput) pickerInput.focus()
|
||||||
|
},
|
||||||
triggerShowPicker () {
|
triggerShowPicker () {
|
||||||
this.showPicker = true
|
this.showPicker = true
|
||||||
this.$refs.picker.startEmojiLoad()
|
this.$refs.picker.startEmojiLoad()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.scrollIntoView()
|
this.scrollIntoView()
|
||||||
|
this.focusPickerInput()
|
||||||
})
|
})
|
||||||
// This temporarily disables "click outside" handler
|
// This temporarily disables "click outside" handler
|
||||||
// since external trigger also means click originates
|
// since external trigger also means click originates
|
||||||
|
@ -214,6 +221,7 @@ const EmojiInput = {
|
||||||
if (this.showPicker) {
|
if (this.showPicker) {
|
||||||
this.scrollIntoView()
|
this.scrollIntoView()
|
||||||
this.$refs.picker.startEmojiLoad()
|
this.$refs.picker.startEmojiLoad()
|
||||||
|
this.$nextTick(this.focusPickerInput)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replace (replacement) {
|
replace (replacement) {
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
<button
|
<button
|
||||||
v-if="!hideEmojiButton"
|
v-if="!hideEmojiButton"
|
||||||
class="button-unstyled emoji-picker-icon"
|
class="button-unstyled emoji-picker-icon"
|
||||||
@click.prevent="togglePicker"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent="togglePicker"
|
||||||
>
|
>
|
||||||
<FAIcon :icon="['far', 'smile-beam']" />
|
<FAIcon :icon="['far', 'smile-beam']" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -116,8 +116,8 @@ export const suggestUsers = ({ dispatch, state }) => {
|
||||||
|
|
||||||
return diff + nameAlphabetically + screenNameAlphabetically
|
return diff + nameAlphabetically + screenNameAlphabetically
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
}).map(({ screen_name, name, profile_image_url_original }) => ({
|
}).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
|
||||||
displayText: screen_name,
|
displayText: screen_name_ui,
|
||||||
detailText: name,
|
detailText: name,
|
||||||
imageUrl: profile_image_url_original,
|
imageUrl: profile_image_url_original,
|
||||||
replacement: '@' + screen_name + ' '
|
replacement: '@' + screen_name + ' '
|
||||||
|
|
|
@ -25,16 +25,16 @@
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class="button-unstyled -link"
|
class="button-unstyled -link"
|
||||||
@click.prevent="requireTOTP"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent="requireTOTP"
|
||||||
>
|
>
|
||||||
{{ $t('login.enter_two_factor_code') }}
|
{{ $t('login.enter_two_factor_code') }}
|
||||||
</button>
|
</button>
|
||||||
<br>
|
<br>
|
||||||
<button
|
<button
|
||||||
class="button-unstyled -link"
|
class="button-unstyled -link"
|
||||||
@click.prevent="abortMFA"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent="abortMFA"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -27,16 +27,16 @@
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class="button-unstyled -link"
|
class="button-unstyled -link"
|
||||||
@click.prevent="requireRecovery"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent="requireRecovery"
|
||||||
>
|
>
|
||||||
{{ $t('login.enter_recovery_code') }}
|
{{ $t('login.enter_recovery_code') }}
|
||||||
</button>
|
</button>
|
||||||
<br>
|
<br>
|
||||||
<button
|
<button
|
||||||
class="button-unstyled -link"
|
class="button-unstyled -link"
|
||||||
@click.prevent="abortMFA"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent="abortMFA"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
>
|
>
|
||||||
<small>
|
<small>
|
||||||
<router-link :to="userProfileLink">
|
<router-link :to="userProfileLink">
|
||||||
{{ notification.from_profile.screen_name }}
|
{{ notification.from_profile.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</small>
|
</small>
|
||||||
<button
|
<button
|
||||||
|
@ -54,14 +54,14 @@
|
||||||
<bdi
|
<bdi
|
||||||
v-if="!!notification.from_profile.name_html"
|
v-if="!!notification.from_profile.name_html"
|
||||||
class="username"
|
class="username"
|
||||||
:title="'@'+notification.from_profile.screen_name"
|
:title="'@'+notification.from_profile.screen_name_ui"
|
||||||
v-html="notification.from_profile.name_html"
|
v-html="notification.from_profile.name_html"
|
||||||
/>
|
/>
|
||||||
<!-- eslint-enable vue/no-v-html -->
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
class="username"
|
class="username"
|
||||||
:title="'@'+notification.from_profile.screen_name"
|
:title="'@'+notification.from_profile.screen_name_ui"
|
||||||
>{{ notification.from_profile.name }}</span>
|
>{{ notification.from_profile.name }}</span>
|
||||||
<span v-if="notification.type === 'like'">
|
<span v-if="notification.type === 'like'">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -152,7 +152,7 @@
|
||||||
:to="userProfileLink"
|
:to="userProfileLink"
|
||||||
class="follow-name"
|
class="follow-name"
|
||||||
>
|
>
|
||||||
@{{ notification.from_profile.screen_name }}
|
@{{ notification.from_profile.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<div
|
<div
|
||||||
v-if="notification.type === 'follow_request'"
|
v-if="notification.type === 'follow_request'"
|
||||||
|
@ -177,7 +177,7 @@
|
||||||
class="move-text"
|
class="move-text"
|
||||||
>
|
>
|
||||||
<router-link :to="targetUserProfileLink">
|
<router-link :to="targetUserProfileLink">
|
||||||
@{{ notification.target.screen_name }}
|
@{{ notification.target.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
|
|
@ -128,9 +128,12 @@ const Popover = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showPopover () {
|
showPopover () {
|
||||||
if (this.hidden) this.$emit('show')
|
const wasHidden = this.hidden
|
||||||
this.hidden = false
|
this.hidden = false
|
||||||
this.$nextTick(this.updateStyles)
|
this.$nextTick(() => {
|
||||||
|
if (wasHidden) this.$emit('show')
|
||||||
|
this.updateStyles()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
hidePopover () {
|
hidePopover () {
|
||||||
if (!this.hidden) this.$emit('close')
|
if (!this.hidden) this.$emit('close')
|
||||||
|
|
|
@ -115,7 +115,7 @@ const PostStatusForm = {
|
||||||
? this.copyMessageScope
|
? this.copyMessageScope
|
||||||
: this.$store.state.users.currentUser.default_scope
|
: this.$store.state.users.currentUser.default_scope
|
||||||
|
|
||||||
const { postContentType: contentType } = this.$store.getters.mergedConfig
|
const { postContentType: contentType, sensitiveByDefault } = this.$store.getters.mergedConfig
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dropFiles: [],
|
dropFiles: [],
|
||||||
|
@ -126,7 +126,7 @@ const PostStatusForm = {
|
||||||
newStatus: {
|
newStatus: {
|
||||||
spoilerText: this.subject || '',
|
spoilerText: this.subject || '',
|
||||||
status: statusText,
|
status: statusText,
|
||||||
nsfw: false,
|
nsfw: !!sensitiveByDefault,
|
||||||
files: [],
|
files: [],
|
||||||
poll: {},
|
poll: {},
|
||||||
mediaDescriptions: {},
|
mediaDescriptions: {},
|
||||||
|
|
|
@ -23,6 +23,12 @@ const ReactButton = {
|
||||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||||
}
|
}
|
||||||
close()
|
close()
|
||||||
|
},
|
||||||
|
focusInput () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const input = this.$el.querySelector('input')
|
||||||
|
if (input) input.focus()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
:offset="{ y: 5 }"
|
:offset="{ y: 5 }"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
remove-padding
|
remove-padding
|
||||||
|
@show="focusInput"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
slot="content"
|
slot="content"
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
class="button-unstyled scope"
|
class="button-unstyled scope"
|
||||||
:class="css.direct"
|
:class="css.direct"
|
||||||
:title="$t('post_status.scope.direct')"
|
:title="$t('post_status.scope.direct')"
|
||||||
@click="changeVis('direct')"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click="changeVis('direct')"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
|
@ -21,8 +21,8 @@
|
||||||
class="button-unstyled scope"
|
class="button-unstyled scope"
|
||||||
:class="css.private"
|
:class="css.private"
|
||||||
:title="$t('post_status.scope.private')"
|
:title="$t('post_status.scope.private')"
|
||||||
@click="changeVis('private')"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click="changeVis('private')"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="lock"
|
icon="lock"
|
||||||
|
@ -34,8 +34,8 @@
|
||||||
class="button-unstyled scope"
|
class="button-unstyled scope"
|
||||||
:class="css.unlisted"
|
:class="css.unlisted"
|
||||||
:title="$t('post_status.scope.unlisted')"
|
:title="$t('post_status.scope.unlisted')"
|
||||||
@click="changeVis('unlisted')"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click="changeVis('unlisted')"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="lock-open"
|
icon="lock-open"
|
||||||
|
@ -47,8 +47,8 @@
|
||||||
class="button-unstyled scope"
|
class="button-unstyled scope"
|
||||||
:class="css.public"
|
:class="css.public"
|
||||||
:title="$t('post_status.scope.public')"
|
:title="$t('post_status.scope.public')"
|
||||||
@click="changeVis('public')"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click="changeVis('public')"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="globe"
|
icon="globe"
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn button-default search-button"
|
class="btn button-default search-button"
|
||||||
@click="newQuery(searchTerm)"
|
|
||||||
type="submit"
|
type="submit"
|
||||||
|
@click="newQuery(searchTerm)"
|
||||||
>
|
>
|
||||||
<FAIcon icon="search" />
|
<FAIcon icon="search" />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
v-if="hidden"
|
v-if="hidden"
|
||||||
class="button-unstyled nav-icon"
|
class="button-unstyled nav-icon"
|
||||||
:title="$t('nav.search')"
|
:title="$t('nav.search')"
|
||||||
@click.prevent.stop="toggleHidden"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent.stop="toggleHidden"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
fixed-width
|
fixed-width
|
||||||
|
@ -28,8 +28,8 @@
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button-default search-button"
|
class="button-default search-button"
|
||||||
@click="find(searchTerm)"
|
|
||||||
type="submit"
|
type="submit"
|
||||||
|
@click="find(searchTerm)"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
fixed-width
|
fixed-width
|
||||||
|
@ -38,8 +38,8 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button-unstyled cancel-search"
|
class="button-unstyled cancel-search"
|
||||||
@click.prevent.stop="toggleHidden"
|
|
||||||
type="button"
|
type="button"
|
||||||
|
@click.prevent.stop="toggleHidden"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
fixed-width
|
fixed-width
|
||||||
|
|
|
@ -2,21 +2,21 @@
|
||||||
<span
|
<span
|
||||||
v-if="changed"
|
v-if="changed"
|
||||||
class="ModifiedIndicator"
|
class="ModifiedIndicator"
|
||||||
>
|
>
|
||||||
<Popover
|
<Popover
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
>
|
>
|
||||||
<span slot="trigger">
|
<span slot="trigger">
|
||||||
|
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="wrench"
|
icon="wrench"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
class="modified-tooltip"
|
|
||||||
slot="content"
|
slot="content"
|
||||||
>
|
class="modified-tooltip"
|
||||||
{{ $t('settings.setting_changed') }}
|
>
|
||||||
|
{{ $t('settings.setting_changed') }}
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
</span>
|
</span>
|
||||||
|
@ -32,8 +32,8 @@ library.add(
|
||||||
)
|
)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['changed'],
|
components: { Popover },
|
||||||
components: { Popover }
|
props: ['changed']
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -75,8 +75,8 @@
|
||||||
<p>{{ $t('settings.filtering_explanation') }}</p>
|
<p>{{ $t('settings.filtering_explanation') }}</p>
|
||||||
<textarea
|
<textarea
|
||||||
id="muteWords"
|
id="muteWords"
|
||||||
class="resize-height"
|
|
||||||
v-model="muteWordsString"
|
v-model="muteWordsString"
|
||||||
|
class="resize-height"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -144,7 +144,12 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<BooleanSetting path="minimalScopesMode">
|
<BooleanSetting path="minimalScopesMode">
|
||||||
{{ $t('settings.minimal_scopes_mode') }} {{ minimalScopesModeDefaultValue }}
|
{{ $t('settings.minimal_scopes_mode') }}
|
||||||
|
</BooleanSetting>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<BooleanSetting path="sensitiveByDefault">
|
||||||
|
{{ $t('settings.sensitive_by_default') }}
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -136,7 +136,7 @@ const Status = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
retweet () { return !!this.statusoid.retweeted_status },
|
retweet () { return !!this.statusoid.retweeted_status },
|
||||||
retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name },
|
retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name_ui },
|
||||||
retweeterHtml () { return this.statusoid.user.name_html },
|
retweeterHtml () { return this.statusoid.user.name_html },
|
||||||
retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) },
|
retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) },
|
||||||
status () {
|
status () {
|
||||||
|
@ -216,7 +216,7 @@ const Status = {
|
||||||
return this.status.in_reply_to_screen_name
|
return this.status.in_reply_to_screen_name
|
||||||
} else {
|
} else {
|
||||||
const user = this.$store.getters.findUser(this.status.in_reply_to_user_id)
|
const user = this.$store.getters.findUser(this.status.in_reply_to_user_id)
|
||||||
return user && user.screen_name
|
return user && user.screen_name_ui
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replySubject () {
|
replySubject () {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
icon="retweet"
|
icon="retweet"
|
||||||
/>
|
/>
|
||||||
<router-link :to="userProfileLink">
|
<router-link :to="userProfileLink">
|
||||||
{{ status.user.screen_name }}
|
{{ status.user.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</small>
|
</small>
|
||||||
<small
|
<small
|
||||||
|
@ -156,10 +156,10 @@
|
||||||
</h4>
|
</h4>
|
||||||
<router-link
|
<router-link
|
||||||
class="account-name"
|
class="account-name"
|
||||||
:title="status.user.screen_name"
|
:title="status.user.screen_name_ui"
|
||||||
:to="userProfileLink"
|
:to="userProfileLink"
|
||||||
>
|
>
|
||||||
{{ status.user.screen_name }}
|
{{ status.user.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<img
|
<img
|
||||||
v-if="!!(status.user && status.user.favicon)"
|
v-if="!!(status.user && status.user.favicon)"
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<StillImage
|
<StillImage
|
||||||
v-if="user"
|
v-if="user"
|
||||||
class="Avatar"
|
class="Avatar"
|
||||||
:alt="user.screen_name"
|
:alt="user.screen_name_ui"
|
||||||
:title="user.screen_name"
|
:title="user.screen_name_ui"
|
||||||
:src="imgSrc(user.profile_image_url_original)"
|
:src="imgSrc(user.profile_image_url_original)"
|
||||||
:class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }"
|
:class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }"
|
||||||
:image-load-error="imageLoadError"
|
:image-load-error="imageLoadError"
|
||||||
|
|
|
@ -73,10 +73,10 @@
|
||||||
<div class="bottom-line">
|
<div class="bottom-line">
|
||||||
<router-link
|
<router-link
|
||||||
class="user-screen-name"
|
class="user-screen-name"
|
||||||
:title="user.screen_name"
|
:title="user.screen_name_ui"
|
||||||
:to="userProfileLink(user)"
|
:to="userProfileLink(user)"
|
||||||
>
|
>
|
||||||
@{{ user.screen_name }}
|
@{{ user.screen_name_ui }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<template v-if="!hideBio">
|
<template v-if="!hideBio">
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<span v-html="user.name_html" />
|
<span v-html="user.name_html" />
|
||||||
<!-- eslint-enable vue/no-v-html -->
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
<span class="user-list-screen-name">{{ user.screen_name }}</span>
|
<span class="user-list-screen-name">{{ user.screen_name_ui }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="user-reporting-panel panel">
|
<div class="user-reporting-panel panel">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
{{ $t('user_reporting.title', [user.screen_name]) }}
|
{{ $t('user_reporting.title', [user.screen_name_ui]) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|
|
@ -434,6 +434,7 @@
|
||||||
"subject_line_mastodon": "Like mastodon: copy as is",
|
"subject_line_mastodon": "Like mastodon: copy as is",
|
||||||
"subject_line_noop": "Do not copy",
|
"subject_line_noop": "Do not copy",
|
||||||
"post_status_content_type": "Post status content type",
|
"post_status_content_type": "Post status content type",
|
||||||
|
"sensitive_by_default": "Mark posts as sensitive by default",
|
||||||
"stop_gifs": "Play-on-hover GIFs",
|
"stop_gifs": "Play-on-hover GIFs",
|
||||||
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
|
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
|
||||||
"user_mutes": "Users",
|
"user_mutes": "Users",
|
||||||
|
|
|
@ -67,7 +67,8 @@ export const defaultState = {
|
||||||
greentext: undefined, // instance default
|
greentext: undefined, // instance default
|
||||||
hidePostStats: undefined, // instance default
|
hidePostStats: undefined, // instance default
|
||||||
hideUserStats: undefined, // instance default
|
hideUserStats: undefined, // instance default
|
||||||
virtualScrolling: undefined // instance default
|
virtualScrolling: undefined, // instance default
|
||||||
|
sensitiveByDefault: undefined // instance default
|
||||||
}
|
}
|
||||||
|
|
||||||
// caching the instance default properties
|
// caching the instance default properties
|
||||||
|
|
|
@ -43,6 +43,7 @@ const defaultState = {
|
||||||
subjectLineBehavior: 'email',
|
subjectLineBehavior: 'email',
|
||||||
theme: 'pleroma-dark',
|
theme: 'pleroma-dark',
|
||||||
virtualScrolling: true,
|
virtualScrolling: true,
|
||||||
|
sensitiveByDefault: false,
|
||||||
|
|
||||||
// Nasty stuff
|
// Nasty stuff
|
||||||
customEmoji: [],
|
customEmoji: [],
|
||||||
|
|
|
@ -13,7 +13,11 @@ import {
|
||||||
omitBy
|
omitBy
|
||||||
} from 'lodash'
|
} from 'lodash'
|
||||||
import { set } from 'vue'
|
import { set } from 'vue'
|
||||||
import { isStatusNotification, maybeShowNotification } from '../services/notification_utils/notification_utils.js'
|
import {
|
||||||
|
isStatusNotification,
|
||||||
|
isValidNotification,
|
||||||
|
maybeShowNotification
|
||||||
|
} from '../services/notification_utils/notification_utils.js'
|
||||||
import apiService from '../services/api/api.service.js'
|
import apiService from '../services/api/api.service.js'
|
||||||
|
|
||||||
const emptyTl = (userId = 0) => ({
|
const emptyTl = (userId = 0) => ({
|
||||||
|
@ -310,8 +314,24 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateNotificationsMinMaxId = (state, notification) => {
|
||||||
|
state.notifications.maxId = notification.id > state.notifications.maxId
|
||||||
|
? notification.id
|
||||||
|
: state.notifications.maxId
|
||||||
|
state.notifications.minId = notification.id < state.notifications.minId
|
||||||
|
? notification.id
|
||||||
|
: state.notifications.minId
|
||||||
|
}
|
||||||
|
|
||||||
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters, newNotificationSideEffects }) => {
|
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters, newNotificationSideEffects }) => {
|
||||||
each(notifications, (notification) => {
|
each(notifications, (notification) => {
|
||||||
|
// If invalid notification, update ids but don't add it to store
|
||||||
|
if (!isValidNotification(notification)) {
|
||||||
|
console.error('Invalid notification:', notification)
|
||||||
|
updateNotificationsMinMaxId(state, notification)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (isStatusNotification(notification.type)) {
|
if (isStatusNotification(notification.type)) {
|
||||||
notification.action = addStatusToGlobalStorage(state, notification.action).item
|
notification.action = addStatusToGlobalStorage(state, notification.action).item
|
||||||
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
|
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
|
||||||
|
@ -323,12 +343,7 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
||||||
|
|
||||||
// Only add a new notification if we don't have one for the same action
|
// Only add a new notification if we don't have one for the same action
|
||||||
if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
|
if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
|
||||||
state.notifications.maxId = notification.id > state.notifications.maxId
|
updateNotificationsMinMaxId(state, notification)
|
||||||
? notification.id
|
|
||||||
: state.notifications.maxId
|
|
||||||
state.notifications.minId = notification.id < state.notifications.minId
|
|
||||||
? notification.id
|
|
||||||
: state.notifications.minId
|
|
||||||
|
|
||||||
state.notifications.data.push(notification)
|
state.notifications.data.push(notification)
|
||||||
state.notifications.idStore[notification.id] = notification
|
state.notifications.idStore[notification.id] = notification
|
||||||
|
|
|
@ -203,7 +203,8 @@ export const parseUser = (data) => {
|
||||||
output.rights = output.rights || {}
|
output.rights = output.rights || {}
|
||||||
output.notification_settings = output.notification_settings || {}
|
output.notification_settings = output.notification_settings || {}
|
||||||
|
|
||||||
// Convert punycode to unicode
|
// Convert punycode to unicode for UI
|
||||||
|
output.screen_name_ui = output.screen_name
|
||||||
if (output.screen_name.includes('@')) {
|
if (output.screen_name.includes('@')) {
|
||||||
const parts = output.screen_name.split('@')
|
const parts = output.screen_name.split('@')
|
||||||
let unicodeDomain = punycode.toUnicode(parts[1])
|
let unicodeDomain = punycode.toUnicode(parts[1])
|
||||||
|
@ -211,7 +212,7 @@ export const parseUser = (data) => {
|
||||||
// Add some identifier so users can potentially spot spoofing attempts:
|
// Add some identifier so users can potentially spot spoofing attempts:
|
||||||
// lain.com and xn--lin-6cd.com would appear identical otherwise.
|
// lain.com and xn--lin-6cd.com would appear identical otherwise.
|
||||||
unicodeDomain = '🌏' + unicodeDomain
|
unicodeDomain = '🌏' + unicodeDomain
|
||||||
output.screen_name = [parts[0], unicodeDomain].join('@')
|
output.screen_name_ui = [parts[0], unicodeDomain].join('@')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,13 @@ const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reactio
|
||||||
|
|
||||||
export const isStatusNotification = (type) => includes(statusNotifications, type)
|
export const isStatusNotification = (type) => includes(statusNotifications, type)
|
||||||
|
|
||||||
|
export const isValidNotification = (notification) => {
|
||||||
|
if (isStatusNotification(notification.type) && !notification.status) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
const sortById = (a, b) => {
|
const sortById = (a, b) => {
|
||||||
const seqA = Number(a.id)
|
const seqA = Number(a.id)
|
||||||
const seqB = Number(b.id)
|
const seqB = Number(b.id)
|
||||||
|
|
|
@ -31,13 +31,15 @@ const testGetters = {
|
||||||
const localUser = {
|
const localUser = {
|
||||||
id: 100,
|
id: 100,
|
||||||
is_local: true,
|
is_local: true,
|
||||||
screen_name: 'testUser'
|
screen_name: 'testUser',
|
||||||
|
screen_name_ui: 'testUser'
|
||||||
}
|
}
|
||||||
|
|
||||||
const extUser = {
|
const extUser = {
|
||||||
id: 100,
|
id: 100,
|
||||||
is_local: false,
|
is_local: false,
|
||||||
screen_name: 'testUser@test.instance'
|
screen_name: 'testUser@test.instance',
|
||||||
|
screen_name_ui: 'testUser@test.instance'
|
||||||
}
|
}
|
||||||
|
|
||||||
const externalProfileStore = new Vuex.Store({
|
const externalProfileStore = new Vuex.Store({
|
||||||
|
|
|
@ -315,7 +315,7 @@ describe('API Entities normalizer', () => {
|
||||||
it('converts IDN to unicode and marks it as internatonal', () => {
|
it('converts IDN to unicode and marks it as internatonal', () => {
|
||||||
const user = makeMockUserMasto({ acct: 'lain@xn--lin-6cd.com' })
|
const user = makeMockUserMasto({ acct: 'lain@xn--lin-6cd.com' })
|
||||||
|
|
||||||
expect(parseUser(user)).to.have.property('screen_name').that.equal('lain@🌏lаin.com')
|
expect(parseUser(user)).to.have.property('screen_name_ui').that.equal('lain@🌏lаin.com')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -7842,9 +7842,10 @@ shebang-regex@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||||
|
|
||||||
shelljs@^0.7.4:
|
shelljs@^0.8.4:
|
||||||
version "0.7.8"
|
version "0.8.4"
|
||||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
|
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
|
||||||
|
integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.0.0"
|
glob "^7.0.0"
|
||||||
interpret "^1.0.0"
|
interpret "^1.0.0"
|
||||||
|
|
Loading…
Reference in a new issue