mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(client): restore titles for cached views
Restore the resolved entity title whenever a kept-alive view becomes active. Prevent inactive cached views from replacing the current page title. Fixes #1261
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { defineComponent, h, KeepAlive, nextTick, ref } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { usePageTitle } from '@/composables/usePageTitle'
|
||||
|
||||
vi.mock('vue-router', () => ({
|
||||
useRoute: () => ({ matched: [] }),
|
||||
}))
|
||||
|
||||
describe('usePageTitle', () => {
|
||||
afterEach(() => {
|
||||
document.title = ''
|
||||
})
|
||||
|
||||
it('restores the resolved title when a kept-alive view is reactivated', async () => {
|
||||
const active = ref(true)
|
||||
const title = ref('Fiction')
|
||||
const TitledView = defineComponent({
|
||||
name: 'TitledView',
|
||||
setup() {
|
||||
usePageTitle(title)
|
||||
return () => h('div')
|
||||
},
|
||||
})
|
||||
const OtherView = defineComponent({
|
||||
name: 'OtherView',
|
||||
setup: () => () => h('div'),
|
||||
})
|
||||
const wrapper = mount(
|
||||
defineComponent({
|
||||
setup: () => () => h(KeepAlive, null, [h(active.value ? TitledView : OtherView)]),
|
||||
}),
|
||||
)
|
||||
|
||||
expect(document.title).toBe('Fiction · BookOrbit')
|
||||
|
||||
active.value = false
|
||||
await nextTick()
|
||||
document.title = 'Library #4 · BookOrbit'
|
||||
|
||||
active.value = true
|
||||
await nextTick()
|
||||
|
||||
expect(document.title).toBe('Fiction · BookOrbit')
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('does not let a deactivated view overwrite the active page title', async () => {
|
||||
const active = ref(true)
|
||||
const title = ref('Fiction')
|
||||
const TitledView = defineComponent({
|
||||
name: 'TitledView',
|
||||
setup() {
|
||||
usePageTitle(title)
|
||||
return () => h('div')
|
||||
},
|
||||
})
|
||||
const OtherView = defineComponent({
|
||||
name: 'OtherView',
|
||||
setup: () => () => h('div'),
|
||||
})
|
||||
const wrapper = mount(
|
||||
defineComponent({
|
||||
setup: () => () => h(KeepAlive, null, [h(active.value ? TitledView : OtherView)]),
|
||||
}),
|
||||
)
|
||||
|
||||
active.value = false
|
||||
await nextTick()
|
||||
document.title = 'Authors · BookOrbit'
|
||||
title.value = 'Renamed Fiction'
|
||||
await nextTick()
|
||||
|
||||
expect(document.title).toBe('Authors · BookOrbit')
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import { onBeforeUnmount, toValue, watch, type MaybeRefOrGetter } from 'vue'
|
||||
import { onActivated, onBeforeUnmount, onDeactivated, toValue, watch, type MaybeRefOrGetter } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { formatPageTitle } from '@/lib/page-title'
|
||||
import { resolveRouteTitle } from '@/router/title-resolver'
|
||||
@@ -10,16 +10,28 @@ function setTitle(title: string | null | undefined) {
|
||||
|
||||
export function usePageTitle(title: MaybeRefOrGetter<string | null | undefined>) {
|
||||
const route = useRoute()
|
||||
let active = true
|
||||
|
||||
const stop = watch(
|
||||
() => toValue(title),
|
||||
(value) => setTitle(value),
|
||||
(value) => {
|
||||
if (active) setTitle(value)
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onActivated(() => {
|
||||
active = true
|
||||
setTitle(toValue(title))
|
||||
})
|
||||
|
||||
onDeactivated(() => {
|
||||
active = false
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stop()
|
||||
if (typeof document !== 'undefined') {
|
||||
if (active && typeof document !== 'undefined') {
|
||||
document.title = resolveRouteTitle(route)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user