-
Notifications
You must be signed in to change notification settings - Fork 204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert host <-> guest communication to use MessageChannel #3611
Changes from 4 commits
b4bfa9f
fdfb22f
e80beb5
a911407
a037456
2c9a094
6f482fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -27,7 +27,7 @@ const window_ = /** @type {HypothesisWindow} */ (window); | |||||||||||||||
|
||||||||||||||||
// Look up the URL of the sidebar. This element is added to the page by the | ||||||||||||||||
// boot script before the "annotator" bundle loads. | ||||||||||||||||
const appLinkEl = /** @type {Element} */ ( | ||||||||||||||||
const sidebarLinkElement = /** @type {HTMLLinkElement} */ ( | ||||||||||||||||
esanzgar marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
document.querySelector( | ||||||||||||||||
'link[type="application/annotator+html"][rel="sidebar"]' | ||||||||||||||||
) | ||||||||||||||||
|
@@ -68,28 +68,39 @@ function init() { | |||||||||||||||
sidebar = new Sidebar(document.body, eventBus, guest, getConfig('sidebar')); | ||||||||||||||||
|
||||||||||||||||
// Expose sidebar window reference for use by same-origin guest frames. | ||||||||||||||||
window_.__hypothesis.sidebarWindow = sidebar.iframe.contentWindow; | ||||||||||||||||
window_.__hypothesis.sidebarWindow = sidebar.ready.then( | ||||||||||||||||
() => sidebar.iframe.contentWindow | ||||||||||||||||
); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// Clear `annotations` value from the notebook's config to prevent direct-linked | ||||||||||||||||
// annotations from filtering the threads. | ||||||||||||||||
const notebook = new Notebook(document.body, eventBus, getConfig('notebook')); | ||||||||||||||||
|
||||||||||||||||
// Set up communication between this host/guest frame and the sidebar frame. | ||||||||||||||||
const sidebarWindow = sidebar | ||||||||||||||||
? sidebar.iframe.contentWindow | ||||||||||||||||
: /** @type {HypothesisWindow} */ (window.parent).__hypothesis | ||||||||||||||||
?.sidebarWindow; | ||||||||||||||||
let sidebarWindow = window_.__hypothesis.sidebarWindow; | ||||||||||||||||
try { | ||||||||||||||||
sidebarWindow = /** @type {HypothesisWindow} */ (window.parent).__hypothesis | ||||||||||||||||
?.sidebarWindow; | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a comment here. More importantly looking at this again made be realize there was a bug where the assignment in the |
||||||||||||||||
} catch { | ||||||||||||||||
// `window.parent` access can fail due to it being cross-origin. This is | ||||||||||||||||
// handled below. | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
if (sidebarWindow) { | ||||||||||||||||
guest.crossframe.connectToSidebar(sidebarWindow); | ||||||||||||||||
const sidebarOrigin = new URL(sidebarLinkElement.href).origin; | ||||||||||||||||
sidebarWindow.then(frame => | ||||||||||||||||
guest.crossframe.connectToSidebar(frame, sidebarOrigin) | ||||||||||||||||
); | ||||||||||||||||
} else { | ||||||||||||||||
// eslint-disable-next-line no-console | ||||||||||||||||
console.warn( | ||||||||||||||||
esanzgar marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
`Hypothesis guest frame in ${location.origin} could not find a sidebar to connect to` | ||||||||||||||||
`Hypothesis guest frame in ${location.origin} could not find a sidebar to connect to. | ||||||||||||||||
Guest frames can only connect to sidebars in their same-origin parent frame.` | ||||||||||||||||
); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
appLinkEl.addEventListener('destroy', () => { | ||||||||||||||||
sidebarLinkElement.addEventListener('destroy', () => { | ||||||||||||||||
delete window_.__hypothesis; | ||||||||||||||||
sidebar?.destroy(); | ||||||||||||||||
|
||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,9 @@ | ||
import { CrossFrame, $imports } from '../cross-frame'; | ||
|
||
describe('CrossFrame', () => { | ||
let fakeDiscovery; | ||
let fakeBridge; | ||
let fakeAnnotationSync; | ||
|
||
let proxyDiscovery; | ||
let proxyBridge; | ||
let proxyAnnotationSync; | ||
|
||
|
@@ -20,11 +18,6 @@ describe('CrossFrame', () => { | |
}; | ||
|
||
beforeEach(() => { | ||
fakeDiscovery = { | ||
startDiscovery: sinon.stub(), | ||
stopDiscovery: sinon.stub(), | ||
}; | ||
|
||
fakeBridge = { | ||
destroy: sinon.stub(), | ||
createChannel: sinon.stub(), | ||
|
@@ -36,13 +29,11 @@ describe('CrossFrame', () => { | |
fakeAnnotationSync = { sync: sinon.stub() }; | ||
|
||
proxyAnnotationSync = sinon.stub().returns(fakeAnnotationSync); | ||
proxyDiscovery = sinon.stub().returns(fakeDiscovery); | ||
proxyBridge = sinon.stub().returns(fakeBridge); | ||
|
||
$imports.$mock({ | ||
'./annotation-sync': proxyAnnotationSync, | ||
'../shared/bridge': proxyBridge, | ||
'../shared/discovery': proxyDiscovery, | ||
}); | ||
}); | ||
|
||
|
@@ -51,21 +42,6 @@ describe('CrossFrame', () => { | |
}); | ||
|
||
describe('CrossFrame constructor', () => { | ||
it('instantiates the Discovery component', () => { | ||
createCrossFrame(); | ||
assert.calledWith(proxyDiscovery, window); | ||
}); | ||
|
||
it('passes the options along to the bridge', () => { | ||
createCrossFrame({ server: true }); | ||
assert.calledWith(proxyDiscovery, window, { server: true }); | ||
}); | ||
|
||
it('instantiates the CrossFrame component', () => { | ||
createCrossFrame(); | ||
assert.calledWith(proxyDiscovery); | ||
}); | ||
|
||
it('instantiates the AnnotationSync component', () => { | ||
createCrossFrame(); | ||
assert.called(proxyAnnotationSync); | ||
|
@@ -81,34 +57,37 @@ describe('CrossFrame', () => { | |
}); | ||
|
||
describe('#connectToSidebar', () => { | ||
it('starts the discovery of new channels', async () => { | ||
it('sends a `hypothesisGuestReady` notification to the sidebar', async () => { | ||
const cf = createCrossFrame(); | ||
const sidebarFrame = {}; | ||
fakeDiscovery.startDiscovery.callsFake((callback, frames) => { | ||
setTimeout(() => callback(frames[0], 'ORIGIN', 'TOKEN'), 0); | ||
}); | ||
const sidebarFrame = { postMessage: sinon.stub() }; | ||
const sidebarOrigin = 'https://dummy.hypothes.is/'; | ||
|
||
cf.connectToSidebar(sidebarFrame, sidebarOrigin); | ||
|
||
assert.calledWith( | ||
sidebarFrame.postMessage, | ||
{ | ||
type: 'hypothesisGuestReady', | ||
}, | ||
sidebarOrigin, | ||
[sinon.match.instanceOf(MessagePort)] | ||
); | ||
}); | ||
|
||
await cf.connectToSidebar(sidebarFrame); | ||
it('creates a channel for communication with the sidebar', () => { | ||
const cf = createCrossFrame(); | ||
const sidebarFrame = { postMessage: sinon.stub() }; | ||
|
||
assert.calledWith(fakeDiscovery.startDiscovery, sinon.match.func, [ | ||
sidebarFrame, | ||
]); | ||
assert.called(fakeBridge.createChannel); | ||
assert.calledWith(fakeBridge.createChannel, { | ||
source: sidebarFrame, | ||
origin: 'ORIGIN', | ||
token: 'TOKEN', | ||
}); | ||
cf.connectToSidebar(sidebarFrame); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to add the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
|
||
assert.calledWith( | ||
fakeBridge.createChannel, | ||
sinon.match.instanceOf(MessagePort) | ||
); | ||
}); | ||
}); | ||
|
||
describe('#destroy', () => { | ||
it('stops the discovery of new frames', () => { | ||
const cf = createCrossFrame(); | ||
cf.destroy(); | ||
assert.called(fakeDiscovery.stopDiscovery); | ||
}); | ||
|
||
it('destroys the bridge object', () => { | ||
const cf = createCrossFrame(); | ||
cf.destroy(); | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -155,6 +155,27 @@ describe('Sidebar', () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
describe('#ready', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
it('returns a promise that resolves when `hypothesisSidebarReady` message is received', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const sidebar = createSidebar(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Check `sidebar.ready` is not resolved before `hypothesisSidebarReady` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// message is received. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
assert.equal( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await Promise.race([sidebar.ready, Promise.resolve('not-ready')]), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'not-ready' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
window.dispatchEvent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new MessageEvent('message', { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data: { type: 'hypothesisSidebarReady' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return sidebar.ready; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found this test a bit contrive. What about this alternative?
Suggested change
Or maybe:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Promises can only be resolved once, so unless |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function getConfigString(sidebar) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return sidebar.iframe.src; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optionally: