Skip to content

Commit 6662519

Browse files
authored
fix(in-page-channel): connect panels nested in popup windows (#383)
1 parent 04c2aab commit 6662519

4 files changed

Lines changed: 46 additions & 11 deletions

File tree

packages/devframe/src/in-page-channel/in-page-channel.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,39 @@ function createWindowPair(origin = 'https://app.test'): { hostWin: FakeWindow, p
675675
const fastHello = { helloIntervalMs: 5, heartbeat: false as const }
676676

677677
describe('in-page channel handshake', () => {
678+
it.each([0, 1, 2])('connects through a popup opener with %i nested panel frames', async (depth) => {
679+
const { hostWin, panelWin } = createWindowPair()
680+
let popupWin = panelWin
681+
for (let i = 0; i < depth; i++) {
682+
const parent = createFakeWindow(hostWin.location.origin)
683+
popupWin.parent = parent
684+
popupWin = parent
685+
}
686+
popupWin.parent = popupWin
687+
popupWin.opener = hostWin
688+
const pageScript = createPageScriptChannel<TestProtocol>({
689+
name: 'devframes:test',
690+
window: asWindow(hostWin),
691+
heartbeat: false,
692+
functions: defaultPageScriptFunctions,
693+
})
694+
const panel = connectPanelChannel<TestProtocol>({
695+
name: 'devframes:test',
696+
window: asWindow(panelWin),
697+
...fastHello,
698+
functions: defaultPanelFunctions,
699+
})
700+
try {
701+
await panel.whenConnected(200)
702+
expect(panel.pageScript?.instanceId).toBe(pageScript.instanceId)
703+
await expect(panel.call('echo', 'popup')).resolves.toBe('popup')
704+
}
705+
finally {
706+
panel.close()
707+
pageScript.close()
708+
}
709+
})
710+
678711
it('connects a panel to the page script and survives page-script restarts', async () => {
679712
const { hostWin, panelWin } = createWindowPair()
680713
const pageScript = createPageScriptChannel<TestProtocol>({

packages/devframe/src/in-page-channel/panel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const DEFAULT_EVENT_BUFFER_LIMIT = 64
3838
* Connect the panel endpoint of an in-page channel.
3939
*
4040
* The panel initiates: it posts a versioned hello to every window a
41-
* same-tab page script can live in (its ancestor chain and its `opener`),
41+
* page script can live in (its ancestor chain and those windows' openers),
4242
* retrying with backoff until one answers with a dedicated port, so boot
4343
* order never matters, and a reload of either side is just a re-handshake
4444
* (`WindowProxy` references survive navigations). While `connecting`,

packages/devframe/src/in-page-channel/protocol.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ export function resolveAllowedOrigins(allowedOrigins: string[] | undefined, win:
9292
}
9393

9494
/**
95-
* Default handshake targets of a panel: its ancestor chain plus its
96-
* `opener`, every same-tab window a page script can live in. `WindowProxy`
95+
* Default handshake targets of a panel: its ancestor chain plus the
96+
* `opener` of each window, including a popup containing the panel iframe. `WindowProxy`
9797
* references stay valid across navigations, so hellos posted to these reach
9898
* a page script even after the host page reloads.
9999
*/
@@ -111,13 +111,15 @@ export function defaultHandshakeTargets(win: Window): Window[] {
111111
catch {
112112
// Walking stopped by the browser; keep what we have.
113113
}
114-
try {
115-
const opener = win.opener as Window | null
116-
if (opener && opener !== win)
117-
targets.push(opener)
118-
}
119-
catch {
120-
// Inaccessible opener; ignore.
114+
for (const current of [win, ...targets]) {
115+
try {
116+
const opener = current.opener as Window | null
117+
if (opener && opener !== win && !targets.includes(opener))
118+
targets.push(opener)
119+
}
120+
catch {
121+
// Inaccessible opener; continue with the other ancestors.
122+
}
121123
}
122124
return targets
123125
}

packages/devframe/src/in-page-channel/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export interface ConnectPanelChannelOptions<Protocol extends InPageChannelProtoc
274274
window?: Window | false
275275
/**
276276
* Windows the hello is posted to. Defaults to the panel's ancestor chain
277-
* plus its `opener`, the places a same-tab page script can live. When
277+
* plus those windows' openers, the places a page script can live. When
278278
* empty and no `transport` is given, the endpoint stays `connecting` and
279279
* warns once.
280280
*/

0 commit comments

Comments
 (0)