Posterverse: the open tab is in the page address
The shell reads ?tab= through the shared view-address helper and writes the open tab back through it: a reader's choice is a push, first paint a replace, and Back / Forward re-apply the tab without writing. Only the address owner writes (urlOwner 'app' on our own pages, 'host' hands the change to a host's router, absent on a partner's page = read only), so a reload keeps the tab and a sent link opens it.
This commit is contained in:
parent
30dc9a1457
commit
86f1c1a463
1 changed files with 16 additions and 4 deletions
|
|
@ -74,6 +74,7 @@ import BackToTopButton from '@map/components/BackToTopButton.vue'
|
||||||
import ShellLanguageMenu from '@map/components/ShellLanguageMenu.vue'
|
import ShellLanguageMenu from '@map/components/ShellLanguageMenu.vue'
|
||||||
import { saveLocale } from '@map/layouts/app-wrapper-material/languages.js'
|
import { saveLocale } from '@map/layouts/app-wrapper-material/languages.js'
|
||||||
import { loadScriptOnce, whenTagDefined } from '@map/utils/embedScript.js'
|
import { loadScriptOnce, whenTagDefined } from '@map/utils/embedScript.js'
|
||||||
|
import { readViewKeys, writeViewKeys, onAddressChange, urlOwnerOf } from '@map/composables/useViewAddress.js'
|
||||||
import { translate, LOCALES } from './src/strings.js'
|
import { translate, LOCALES } from './src/strings.js'
|
||||||
import { SECTIONS, TABS, resolveTabs } from './src/tabs.js'
|
import { SECTIONS, TABS, resolveTabs } from './src/tabs.js'
|
||||||
|
|
||||||
|
|
@ -226,11 +227,18 @@ export default defineComponent({
|
||||||
mounted() {
|
mounted() {
|
||||||
this.watchHostLang()
|
this.watchHostLang()
|
||||||
// Paint the rail at once; the manifest completes the rows in the background and re-drives the mount.
|
// Paint the rail at once; the manifest completes the rows in the background and re-drives the mount.
|
||||||
this.select(this.initialIndex())
|
// First paint is a REPLACE, so a reload or a shared link keeps the tab without adding a Back step.
|
||||||
|
this.select(this.initialIndex(), { firstPaint: true })
|
||||||
|
// Back / Forward re-apply the tab from the address and never write (writing would lose Forward).
|
||||||
|
this._offAddress = onAddressChange(({ tab }) => {
|
||||||
|
const i = this.tabs.findIndex((t) => t.id === tab)
|
||||||
|
this.select(i >= 0 ? i : 0, { fromHistory: true })
|
||||||
|
})
|
||||||
this.loadManifest()
|
this.loadManifest()
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
if (this._langObs) { this._langObs.disconnect(); this._langObs = null }
|
if (this._langObs) { this._langObs.disconnect(); this._langObs = null }
|
||||||
|
if (this._offAddress) { this._offAddress(); this._offAddress = null }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
tr(key, params) { return translate(this.uiLocale, key, params) },
|
tr(key, params) { return translate(this.uiLocale, key, params) },
|
||||||
|
|
@ -250,7 +258,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
requestedTab() {
|
requestedTab() {
|
||||||
let q = ''
|
let q = ''
|
||||||
try { q = new URLSearchParams(location.search).get('tab') || '' } catch { /* non-browser */ }
|
try { q = readViewKeys(location.search).tab } catch { /* non-browser */ }
|
||||||
return String(this.tab || this.cfg.tab || q || '').trim()
|
return String(this.tab || this.cfg.tab || q || '').trim()
|
||||||
},
|
},
|
||||||
initialIndex() {
|
initialIndex() {
|
||||||
|
|
@ -306,7 +314,7 @@ export default defineComponent({
|
||||||
const w = !this._honouredTab && want ? this.tabs.findIndex((t) => t.id === want) : -1
|
const w = !this._honouredTab && want ? this.tabs.findIndex((t) => t.id === want) : -1
|
||||||
const i = this.tabs.findIndex((t) => t.id === activeId)
|
const i = this.tabs.findIndex((t) => t.id === activeId)
|
||||||
this._honouredTab = true
|
this._honouredTab = true
|
||||||
this.select(w >= 0 ? w : (i >= 0 ? i : 0))
|
this.select(w >= 0 ? w : (i >= 0 ? i : 0), { firstPaint: true })
|
||||||
},
|
},
|
||||||
onSelect(key) {
|
onSelect(key) {
|
||||||
const i = this.tabs.findIndex((t) => t.id === key)
|
const i = this.tabs.findIndex((t) => t.id === key)
|
||||||
|
|
@ -322,7 +330,10 @@ export default defineComponent({
|
||||||
if (this.base) return this.base.replace(/\/+$/, '') + '/' + r
|
if (this.base) return this.base.replace(/\/+$/, '') + '/' + r
|
||||||
return '../' + r
|
return '../' + r
|
||||||
},
|
},
|
||||||
select(i) {
|
// The tab is written to the address by the ONE owner (urlOwner in profile-config: 'app' on our own pages,
|
||||||
|
// 'host' when a host's router writes, absent on a partner's page = read only). A reader's choice is a push;
|
||||||
|
// first paint is a replace; Back / Forward never write.
|
||||||
|
select(i, { fromHistory = false, firstPaint = false } = {}) {
|
||||||
const prevIndex = this.activeIndex
|
const prevIndex = this.activeIndex
|
||||||
this.activeIndex = i
|
this.activeIndex = i
|
||||||
// Release the outgoing heavy pane first, so at most one live map context exists at a time.
|
// Release the outgoing heavy pane first, so at most one live map context exists at a time.
|
||||||
|
|
@ -334,6 +345,7 @@ export default defineComponent({
|
||||||
if (!t) return
|
if (!t) return
|
||||||
// Tell the host which plugin is showing (CustomEvent 'tab-change', detail[0] = { id, label }).
|
// Tell the host which plugin is showing (CustomEvent 'tab-change', detail[0] = { id, label }).
|
||||||
if (prevIndex !== i || !this._announced) { this._announced = true; this.$emit('tab-change', { id: t.id, label: this.tabLabel(t) }) }
|
if (prevIndex !== i || !this._announced) { this._announced = true; this.$emit('tab-change', { id: t.id, label: this.tabLabel(t) }) }
|
||||||
|
if (!fromHistory) writeViewKeys({ tab: t.id }, { owner: urlOwnerOf(this.cfg), push: !firstPaint, el: this.$el })
|
||||||
if (!t.scriptUrl) return // applyManifest selects again once the manifest lands
|
if (!t.scriptUrl) return // applyManifest selects again once the manifest lands
|
||||||
// A heavy tab's slot exists only after its v-if subtree renders, so mount on the next tick.
|
// A heavy tab's slot exists only after its v-if subtree renders, so mount on the next tick.
|
||||||
if (!t.mounted) this.$nextTick(() => { if (this.activeIndex === i) this.mountElement(i) })
|
if (!t.mounted) this.$nextTick(() => { if (this.activeIndex === i) this.mountElement(i) })
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue