Hi again, thank you for your reponse.
I forgot to mention in my initial post that I did have to include the origin within the config in order for it to partially render, so all my examples were based off of that.
I did further digging, and believe I found the root cause of the issue, and it basically relates to how the viewer does iframe <-> window IPC:
- the iframe uses
window.postMessage
to send messages from the iframe → the app-level viewer package
- from the context of the iframe,
window
refers to the popout window, not the parent window. messages don’t get bubbled up.
- the webviewer lib which runs in our app code (i.e. not the viewer iframe, in the parent window) listens to the parent window’s
message
events, which doesn’t receive events from posted to the popup (child) window
- therefore there is a disconnect between the two: iframe sends messages to child window, app-level webviewer library listens for messages on the parent window
Now on your end, this should be a relatively simple fix, and an issue I’ve experienced / had to fix with a few other libraries when opening in a new controlled window:
The app/parent level library (npm module we import) should be using the element.ownerDocument.defaultView
of the element
which is provided in the WebViewer(..., element)
constructor as a target to subscribe to messages sent by the iframe, as opposed to the current behaviour of using the global window
variable, which would refer to the parent window in this context.
Doing one of those fixes would basically fix the whole issue and would be non-breaking for the regular use-case of rendering in the window that instantiates the viewer (since in that context, element.ownerDocument.defaultView === window
).
(Note: you could fix it the other way around: from iframe, doing parentWindow = window.parent?.opener || window
, but that’s less flexible as it wouldn’t enable an arbitrary level of window / iframe nesting, unlike the proposed fix).
I obviously don’t have access to your code, so I can’t easily propose detailed changes, but I was able to prove the above by crafting a small workaround which does make the viewer (and documents) successfully render in a popup window! It’s obviously very suboptimal and hackish, but proves that this is the issue:
const openViewer = () => {
const popout = window.open("about:blank", "_blank")
const element = document.createElement("div")
popout.document.body.appendChild(element)
let iframeRef = null
popout.addEventListener("message", event => {
if(!!e.source.instance) { // hack to check if it came from the webviewer iframe
iframeRef = e.source
data = event.data
if(typeof data === "object") {
// _source allows deduping and not sending msg back from parent -> iframe
data = {...data, _source: "pdfjs-express"}
}
// forward message to parent window
window.postMessage(event.data, event.origin)
}
})
// since webviewer replies to the message sent using event source,
// which is forwarded above in ctx of parent window,
// webviewer replies will be posted to parent window instead of iframe
window.addEventListener("message", event => {
// don't send back events that came from the iframe
if(iframeRef && e.data._source !== "pdfjs-express") {
// forward to iframe
iframeRef.postMessage(event.data, event.origin)
}
})
WebViewer({ path: WEBVIEWER_PATH, licenseKey: LICENSE_KEY }, element)
.then(instance => {...})
}
openViewer()
What would you recommend going forward? Would it be able to get this logged as a bug for your team to address?
I hope this helps, please let me know if you have any further questions or if I can provide any further information!