optional chaining

This commit is contained in:
Henry Jameson 2026-08-04 15:59:52 +03:00
commit cf85b00c0a
26 changed files with 34 additions and 34 deletions

View file

@ -39,7 +39,7 @@ const ChatListItem = {
messageForStatusContent() { messageForStatusContent() {
const message = this.chat.lastMessage const message = this.chat.lastMessage
const messageEmojis = message ? message.emojis : [] const messageEmojis = message ? message.emojis : []
const isYou = message && message.account_id === this.currentUser.id const isYou = message?.account_id === this.currentUser.id
const content = message ? this.attachmentInfo || message.content : '' const content = message ? this.attachmentInfo || message.content : ''
const messagePreview = isYou const messagePreview = isYou
? `<i>${this.$t('chats.you')}</i> ${content}` ? `<i>${this.$t('chats.you')}</i> ${content}`

View file

@ -111,7 +111,7 @@ const ChatMessage = {
const user = this.$store.getters.findUser( const user = this.$store.getters.findUser(
this.message.in_reply_to_user_id, this.message.in_reply_to_user_id,
) )
return user && user.screen_name_ui return user?.screen_name_ui
} }
}, },
replyProfileLink() { replyProfileLink() {

View file

@ -53,7 +53,7 @@
:user-screen-name="message.in_reply_to_screen_name" :user-screen-name="message.in_reply_to_screen_name"
/> />
<!-- v-if is there because status might not be loaded yet --> <!-- v-if is there because status might not be loaded yet -->
<template v-if="customReplyTo && customReplyTo.text.trim().length > 0"> <template v-if="customReplyTo?.text.trim().length > 0">
: :
<StatusBody <StatusBody
class="reply-body faint" class="reply-body faint"

View file

@ -16,7 +16,7 @@
<RichContent <RichContent
v-if="user" v-if="user"
class="username" class="username"
:title="'@'+(user && user.screen_name_ui)" :title="'@'+(user?.screen_name_ui)"
:html="htmlTitle" :html="htmlTitle"
:emoji="user.emoji || []" :emoji="user.emoji || []"
:allow-non-square-emoji="allowNonSquareEmoji" :allow-non-square-emoji="allowNonSquareEmoji"

View file

@ -50,7 +50,7 @@
/> />
</button> </button>
<button <button
v-if="currentUser && currentUser.role === 'admin'" v-if="currentUser?.role === 'admin'"
class="button-unstyled nav-icon" class="button-unstyled nav-icon"
target="_blank" target="_blank"
:title="$t('nav.administration')" :title="$t('nav.administration')"

View file

@ -29,7 +29,7 @@ const FollowRequestCard = {
notif.from_profile.id === this.user.id && notif.from_profile.id === this.user.id &&
notif.type === 'follow_request', notif.type === 'follow_request',
) )
return notif && notif.id return notif?.id
}, },
showApproveConfirmDialog() { showApproveConfirmDialog() {
this.showingApproveConfirmDialog = true this.showingApproveConfirmDialog = true

View file

@ -411,7 +411,7 @@ const Popover = {
if (!scrollable) scrollable = window if (!scrollable) scrollable = window
this.scrollable = scrollable this.scrollable = scrollable
let parent = this.$parent let parent = this.$parent
while (parent && parent.$.type.name !== 'Popover') { while (parent?.$.type.name !== 'Popover') {
parent = parent.$parent parent = parent.$parent
} }
this.parentPopover = parent this.parentPopover = parent

View file

@ -89,7 +89,7 @@ export default {
this.error = false this.error = false
const notice = this.noticeRegex.exec(value) const notice = this.noticeRegex.exec(value)
if (notice && notice.length === 4) { if (notice?.length === 4) {
this.$emit('update:id', notice[3]) this.$emit('update:id', notice[3])
} else if (value) { } else if (value) {
this.loading = true this.loading = true
@ -102,7 +102,7 @@ export default {
type: 'statuses', type: 'statuses',
}) })
.then((data) => { .then((data) => {
if (data && data.statuses && data.statuses.length === 1) { if (data?.statuses && data.statuses.length === 1) {
this.$emit('update:id', data.statuses[0].id) this.$emit('update:id', data.statuses[0].id)
} else { } else {
this.handleError(true) this.handleError(true)

View file

@ -343,7 +343,7 @@
<li> <li>
<div class="meta-buttons"> <div class="meta-buttons">
<button <button
v-if="pack && pack.remote === undefined" v-if="pack?.remote === undefined"
class="button button-default btn" class="button button-default btn"
type="button" type="button"
@click="savePackMetadata" @click="savePackMetadata"
@ -351,7 +351,7 @@
{{ $t('admin_dash.emoji.save_meta') }} {{ $t('admin_dash.emoji.save_meta') }}
</button> </button>
<button <button
v-if="pack && pack.remote === undefined" v-if="pack?.remote === undefined"
class="button button-default btn" class="button button-default btn"
type="button" type="button"
@click="savePackMetadata" @click="savePackMetadata"
@ -374,7 +374,7 @@
class="emoji-list setting-list" class="emoji-list setting-list"
> >
<EmojiEditingPopover <EmojiEditingPopover
v-if="pack && pack.remote === undefined" v-if="pack?.remote === undefined"
class="emoji-item" class="emoji-item"
placement="bottom" placement="bottom"
new-upload new-upload

View file

@ -47,7 +47,7 @@ export default {
// In case of controlled component // In case of controlled component
if (this.activeTab) { if (this.activeTab) {
return this.slots().findIndex( return this.slots().findIndex(
(slot) => slot && slot.props && this.activeTab === slot.props.key, (slot) => slot?.props && this.activeTab === slot.props.key,
) )
} else { } else {
return this.active return this.active

View file

@ -236,7 +236,7 @@ const AppearanceTab = {
}, },
stylePalettes() { stylePalettes() {
const ruleset = useInterfaceStore().styleDataUsed || [] const ruleset = useInterfaceStore().styleDataUsed || []
if (!ruleset && ruleset.length === 0) return if (!ruleset?.length === 0) return
const meta = ruleset.find((x) => x.component === '@meta') const meta = ruleset.find((x) => x.component === '@meta')
const result = ruleset const result = ruleset
.filter((x) => x.component.startsWith('@palette')) .filter((x) => x.component.startsWith('@palette'))

View file

@ -95,7 +95,7 @@ const DataImportExportTab = {
return users return users
.map((user) => { .map((user) => {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user?.is_local) {
// append the instance address // append the instance address
return user.screen_name + '@' + location.hostname return user.screen_name + '@' + location.hostname
} }

View file

@ -81,7 +81,7 @@ const MutesAndBlocks = {
return users return users
.map((user) => { .map((user) => {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user?.is_local) {
// append the instance address // append the instance address
return user.screen_name + '@' + location.hostname return user.screen_name + '@' + location.hostname
} }

View file

@ -220,7 +220,7 @@
</router-link> </router-link>
</li> </li>
<li <li
v-if="currentUser && currentUser.role === 'admin'" v-if="currentUser?.role === 'admin'"
@click="toggleDrawer" @click="toggleDrawer"
> >
<button <button

View file

@ -316,11 +316,11 @@ const Status = {
return ( return (
(status.muted && !status.thread_muted) || (status.muted && !status.thread_muted) ||
// Reprööt of a muted post according to BE // Reprööt of a muted post according to BE
(reblog && reblog.muted && !reblog.thread_muted) || (reblog?.muted && !reblog.thread_muted) ||
// Muted user // Muted user
relationship.muting || relationship.muting ||
// Muted user of a reprööt // Muted user of a reprööt
(relationshipReblog && relationshipReblog.muting) (relationshipReblog?.muting)
) )
}, },
shouldNotMute() { shouldNotMute() {
@ -333,7 +333,7 @@ const Status = {
// Don't mute user's posts on user timeline (except reblogs) // Don't mute user's posts on user timeline (except reblogs)
((!reblog && status.user.id === this.profileUserId) || ((!reblog && status.user.id === this.profileUserId) ||
// Same as above but also allow self-reblogs // Same as above but also allow self-reblogs
(reblog && reblog.user.id === this.profileUserId))) || (reblog?.user.id === this.profileUserId))) ||
// Don't mute statuses in muted conversation when said conversation is opened // Don't mute statuses in muted conversation when said conversation is opened
(this.inConversation && status.thread_muted)) && (this.inConversation && status.thread_muted)) &&
// No excuses if post has muted words // No excuses if post has muted words
@ -374,7 +374,7 @@ const Status = {
const user = this.$store.getters.findUser( const user = this.$store.getters.findUser(
this.status.in_reply_to_user_id, this.status.in_reply_to_user_id,
) )
return user && user.screen_name_ui return user?.screen_name_ui
} }
}, },
combinedFavsAndRepeatsUsers() { combinedFavsAndRepeatsUsers() {

View file

@ -225,7 +225,7 @@
/> />
</button> </button>
<button <button
v-if="inThreadForest && replies && replies.length && !simpleTree" v-if="inThreadForest && replies?.length && !simpleTree"
class="button-unstyled" class="button-unstyled"
:title="threadShowing ? $t('status.thread_hide') : $t('status.thread_show')" :title="threadShowing ? $t('status.thread_hide') : $t('status.thread_show')"
:aria-expanded="threadShowing ? 'true' : 'false'" :aria-expanded="threadShowing ? 'true' : 'false'"
@ -426,7 +426,7 @@
/> />
<div <div
v-if="inConversation && !isPreview && replies && replies.length" v-if="inConversation && !isPreview && replies?.length"
class="replies" class="replies"
> >
<button <button

View file

@ -47,7 +47,7 @@ export default {
// In case of controlled component // In case of controlled component
if (this.activeTab) { if (this.activeTab) {
return this.slots().findIndex( return this.slots().findIndex(
(slot) => slot && slot.props && this.activeTab === slot.props.key, (slot) => slot?.props && this.activeTab === slot.props.key,
) )
} else { } else {
return this.active return this.active

View file

@ -231,7 +231,7 @@ const Timeline = {
tag: this.tag, tag: this.tag,
}) })
.then(({ statuses }) => { .then(({ statuses }) => {
if (statuses && statuses.length === 0) { if (statuses?.length === 0) {
this.bottomedOut = true this.bottomedOut = true
} }
}) })

View file

@ -1,6 +1,6 @@
<template> <template>
<FAIcon <FAIcon
v-if="user && user.screen_name_ui_contains_non_ascii" v-if="user?.screen_name_ui_contains_non_ascii"
icon="code" icon="code"
:title="$t('unicode_domain_indicator.tooltip')" :title="$t('unicode_domain_indicator.tooltip')"
/> />

View file

@ -68,7 +68,7 @@
> >
<button <button
v-if="editable" v-if="editable"
:disabled="newName && newName.length === 0" :disabled="newName?.length === 0"
class="btn button-unstyled edit-banner-button" class="btn button-unstyled edit-banner-button"
@click="changeBanner" @click="changeBanner"
> >

View file

@ -14,7 +14,7 @@ export function StatusCodeError(statusCode, body, options, response) {
this.name = 'StatusCodeError' this.name = 'StatusCodeError'
this.statusCode = statusCode this.statusCode = statusCode
this.statusText = body.error || body.errors || body this.statusText = body.error || body.errors || body
this.details = JSON && JSON.stringify ? JSON.stringify(body) : body this.details = JSON.stringify(body)
this.errorData = body.error || body.errors this.errorData = body.error || body.errors
this.message = this.statusCode + ' - ' + this.statusText this.message = this.statusCode + ' - ' + this.statusText
this.error = body // legacy attribute this.error = body // legacy attribute

View file

@ -231,7 +231,7 @@ export const SLOT_ORDERED = topoSort(
Object.entries(SLOT_INHERITANCE) Object.entries(SLOT_INHERITANCE)
.sort( .sort(
([, aV], [, bV]) => ([, aV], [, bV]) =>
((aV && aV.priority) || 0) - ((bV && bV.priority) || 0), ((aV?.priority) || 0) - ((bV && bV.priority) || 0),
) )
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}), .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}),
) )
@ -408,7 +408,7 @@ export const getColors = (sourceColors, sourceOpacity) =>
delete outputColor.a delete outputColor.a
} else { } else {
// Otherwise try to assign opacity // Otherwise try to assign opacity
if (dependencyColor && dependencyColor.a === 0) { if (dependencyColor?.a === 0) {
// transparent dependency shall make dependents transparent too // transparent dependency shall make dependents transparent too
outputColor.a = 0 outputColor.a = 0
} else { } else {

View file

@ -11,6 +11,6 @@ const generateProfileLink = (id, screenName, restrictedNicknames) => {
} }
} }
const isExternal = (screenName) => screenName && screenName.includes('@') const isExternal = (screenName) => screenName?.includes('@')
export default generateProfileLink export default generateProfileLink

View file

@ -74,7 +74,7 @@ export const useAnnouncementsStore = defineStore('announcements', {
} catch (error) { } catch (error) {
// If and only if backend does not support announcements, it would return 404. // If and only if backend does not support announcements, it would return 404.
// In this case, silently ignores it. // In this case, silently ignores it.
if (error && error.statusCode === 404) { if (error?.statusCode === 404) {
this.supportsAnnouncements = false this.supportsAnnouncements = false
} else { } else {
throw error throw error

View file

@ -790,7 +790,7 @@ export const normalizeThemeData = (input) => {
// New theme presets don't have 'theme' property, they use 'source' // New theme presets don't have 'theme' property, they use 'source'
let out // shout, shout let it all out let out // shout, shout let it all out
if (themeSource && themeSource.themeEngineVersion === CURRENT_VERSION) { if (themeSource?.themeEngineVersion === CURRENT_VERSION) {
// There are some themes in wild that have completely broken source // There are some themes in wild that have completely broken source
out = { ...(themeData || {}), ...themeSource } out = { ...(themeData || {}), ...themeSource }
} else { } else {

View file

@ -132,7 +132,7 @@ export const waitForEvent = (
return vi.waitFor( return vi.waitFor(
() => { () => {
const e = wrapper.emitted(event) const e = wrapper.emitted(event)
if (e && e.length >= timesEmitted) { if (e?.length >= timesEmitted) {
return return
} }
throw new Error('event is not emitted') throw new Error('event is not emitted')