pane-wrapper: a pending link is also retried by a bounded rAF with an observer present, and by every settled scroll
From the 5B: an observer fires only when the COLUMN resizes. A pane whose height arrives later (styles adopted late in a shadow root) would have left the link pending, and a pending link blocks the settle's write. check:view-address covers it: a fresh load whose observer never fires again still opens the link (43 poisons).
This commit is contained in:
parent
2b62cc0120
commit
6f94ff0e30
2 changed files with 24 additions and 2 deletions
|
|
@ -296,6 +296,24 @@ async function arms({ va, sv, counts, pw, src }, { skipF = false } = {}) {
|
|||
c.destroy()
|
||||
delete globalThis.ResizeObserver
|
||||
}
|
||||
if (!skipF) {
|
||||
// The same fresh load, where the observer NEVER fires again after layout (a pane's height arrived after the
|
||||
// column's last resize): the bounded rAF loop must still open the link.
|
||||
const ros = []
|
||||
globalThis.ResizeObserver = class { constructor(cb) { this.cb = cb; ros.push(this) } observe() {} disconnect() { this.off = true } }
|
||||
globalThis.requestAnimationFrame = (cb) => setTimeout(cb, 5)
|
||||
const b = browser('https://x.test/upg-100-mfe?pane=dashboard')
|
||||
const host = new FakeEl()
|
||||
FakeEl.h0 = 0
|
||||
const c = pw.buildPaneColumn(SPEC, { host, address: { owner: () => 'app' } })
|
||||
FakeEl.h0 = undefined
|
||||
const col = host.children[0]
|
||||
col.clientHeight = 100; await settle()
|
||||
if (col.scrollTop !== 100) fails.push(`F: with an observer that never fires again, the bounded rAF did not open the link (scrollTop ${col.scrollTop})`)
|
||||
if (b.writes.push + b.writes.replace) fails.push('F: the rAF-opened link wrote the address')
|
||||
c.destroy()
|
||||
delete globalThis.ResizeObserver; delete globalThis.requestAnimationFrame
|
||||
}
|
||||
if (!skipF) {
|
||||
// A KEPT-ALIVE column whose tab is hidden and shown again (ResizeObserver: no height, then height).
|
||||
const ros = []
|
||||
|
|
@ -442,6 +460,7 @@ if (process.argv.includes('--self-test')) {
|
|||
['pane-wrapper writing on Back (the pane it is leaving)', { ...real, pw: await pwVariant("show(known(pane) ? pane : column[0].id, 'smooth')", "(claimPane(current(), true), show(known(pane) ? pane : column[0].id, 'smooth'))") }, /^F: Back did not show the address's pane, or it WROTE/],
|
||||
['pane-wrapper opening a link at build time only (before the column has a layout)', { ...real, pw: await pwVariant("let pending = known(linked) && linked !== column[0].id ? linked : ''", "let pending = ''; if (known(linked)) show(linked, 'instant')") }, /^F: a FRESH LOAD with \?pane=dashboard did not open/],
|
||||
['pane-wrapper whose settle overwrites a link still waiting to open', { ...real, pw: await pwVariant('if (col.clientHeight && !pending) claimPane(current(), false)', 'if (!pending || true) claimPane(current(), false)') }, /^F: before its layout, the column overwrote the link/],
|
||||
['pane-wrapper retrying a pending link by rAF only when there is no observer', { ...real, pw: await pwVariant("if (pending && typeof requestAnimationFrame !== 'undefined') {", "if (pending && typeof ResizeObserver === 'undefined' && typeof requestAnimationFrame !== 'undefined') {") }, /^F: with an observer that never fires again/],
|
||||
['pane-wrapper ignoring a link', { ...real, pw: await pwVariant("let pending = known(linked) && linked !== column[0].id ? linked : ''", "let pending = ''") }, /^F: a link to \?pane=dashboard did not open/],
|
||||
['pane-wrapper writing without the opt-in', { ...real, pw: await pwVariant("=> address && claimView({ pane: id === column[0].id ? '' : id, ...changes }, { owner: address.owner(),", "=> claimView({ pane: id === column[0].id ? '' : id, ...changes }, { owner: address ? address.owner() : 'app',") }, /^F: a column WITHOUT the address opt-in/],
|
||||
['ownAddress that lets a nested element switch the tab', { ...real, va: { ...va, ownAddress: (el, g) => { const h = (e) => { const o = g(); if (o) { e.stopPropagation(); va.writeViewKeys(e.detail.changes, { owner: o, el, push: e.detail.push }) } }; el.addEventListener(va.VIEW_EVENT, h); return () => el.removeEventListener(va.VIEW_EVENT, h) } } }, /^E: a nested announcement switched the OWNER's tab/],
|
||||
|
|
|
|||
|
|
@ -201,7 +201,10 @@ export function buildPaneColumn(spec, { host, mountPane, address }) {
|
|||
pending = ''
|
||||
}
|
||||
openLink()
|
||||
if (pending && typeof ResizeObserver === 'undefined' && typeof requestAnimationFrame !== 'undefined') {
|
||||
// Retried by the ResizeObserver below, by every settled scroll, and by a bounded rAF loop that runs even WITH an
|
||||
// observer: the observer fires only when the COLUMN resizes, and a pane's height can arrive later (styles adopted
|
||||
// late in a shadow root).
|
||||
if (pending && typeof requestAnimationFrame !== 'undefined') {
|
||||
let n = 0
|
||||
const tick = () => { openLink(); if (pending && ++n < 120) requestAnimationFrame(tick) }
|
||||
requestAnimationFrame(tick)
|
||||
|
|
@ -210,7 +213,7 @@ export function buildPaneColumn(spec, { host, mountPane, address }) {
|
|||
// step per scroll. A column with no height (a hidden tab) has no "where", and a link still waiting to open must
|
||||
// not be overwritten, so neither writes.
|
||||
let t = null
|
||||
const settle = () => { if (t) clearTimeout(t); t = setTimeout(() => { if (col.clientHeight && !pending) claimPane(current(), false) }, 120) }
|
||||
const settle = () => { if (t) clearTimeout(t); t = setTimeout(() => { openLink(); if (col.clientHeight && !pending) claimPane(current(), false) }, 120) }
|
||||
col.addEventListener('scroll', settle, { passive: true })
|
||||
offs.push(() => { if (t) clearTimeout(t); col.removeEventListener('scroll', settle) })
|
||||
offs.push(onAddressChange(({ pane }) => show(known(pane) ? pane : column[0].id, 'smooth')))
|
||||
|
|
|
|||
Loading…
Reference in a new issue