Closed webarp closed 7 months ago
The first bug is not a bug. At least, that's the technical point of view. It's a promise that has been rejected, and I don't know how to tell a "legally" rejected promise from a real error. So until someone teaches me how to do it, I prefer to err on the safe side. If it annoys you (and if you're not the one to teach me), you can use the log filtering feature to get rid of the message: https://pdfviewer.net/extended-pdf-viewer/filtering-console-log
The second bug may have something to do with showing multiple PDF files on the same page. That's the same problem as displaying two PDF files side-by-side. pdf.js pollutes the global namespace, and I suspect that's what you see.
A workaround is to use *ngIf
to make sure only one PDF file is shown at any point of time. Plus, add a timeout between hiding and showing the PDF file, because pdf.js is heavily asynchronous and takes some time to tidy up.
I'm closing the ticket now because I believe my hints help you. If I'm wrong, don't hesitate to add comments below.
Hi Stephan,
thank you for the clarifications.
I added the log filtering function but it doesn't seem to quite work.
It shows a log when the page loads but when I get the cancel print error, the function did not trigger.
Also, the pdf loading timeout didn't bring anything.
I still get the "the overlay does not exist" error.
Thank you very much from your time.
Best Regards
Can you send me a reproducer for the "overlay does not exist" bug?
Hi Stephan,
I'll try to explain what I'm doing.
I have a table with documents. Once I click on a link, I make an API request, I get a blob and send it to a subcomponent where I load the viewer.
I click on print as many times as I want and I can see the dialog window with the progress bar. It disappears when it's 100% and the standard printing dialog opens.
I don't open 2 viewers at once. Everything works perfectly as long as I don't load the pdfviewer again.
If I click on another section in the app and I open the same document in pdf viewer and try to print it again, it doesn't find the dialog window with progress bar anymore and it throws the error:
async open(e) {
if (!this.#G.has(e))
throw new Error("The overlay does not exist.");
if (this.#K) {
if (this.#K === e)
throw new Error("The overlay is already active.");
if (!this.#G.get(e).canForceClose)
throw new Error("Another overlay is currently active.");
await this.close()
}
this.#K = e;
e.showModal();
e.classList.remove("hidden")
}
What I guess is once the dialog disappeard, it shows up again only if the viewer is still loaded. Somehow, if the viewer it's gone and I load it again, it cannot find the dialog anymore.
I get the progress dialog as many times as I want as long as the viewer it's loaded. Once I'm in another section where come back, it doesn't find the dialog anymore.
Also without the dialog, the standard printing window comes, but after a while. It takes longer as usual and if it's a big document, you may believe that printing on the print button didn't actually work, because there is no progress dialog.
That's what I see in the DOM.
When I load the component, the dialog is in the DOM
I click on print. As long as the progress runs, the dialog tag gets an "open" attribute.
Once it's 100% loaded, the dialog dissapears and the dialog tag gets a hidden class.
So far so good.
But if I move to another section where I don't have the viewer loaded and I go back, even if I still see the dialog in the DOM
If I click on print, it doesn't get the "open" attribute anymore, it throws the overlay error and after I print, I can see the hidden class.
That "open" attribute or state or whatever it is :) causes some troubles.
But it doesn't get triggered if you come back to a section where you load the pdf viewer. I have to refresh the browser to get the dialog again.
It may need a sort of reset in ngOnDestroy or something similar, because Angular remembers some states even if the viewer is not in the DOM anymore and once you go back, it doesn't work properly anymore.
:(
Sorry for answering late - I was busy during the last two weeks.
Debugging gets easier if you set the attribute minifiedJSLibraries="false"
. Then you can see the proper source code of the offending method:
/**
* @param {HTMLDialogElement} dialog - The overlay's DOM element.
* @returns {Promise} A promise that is resolved when the overlay has been
* opened.
*/
async open(dialog) {
if (!this.#overlays.has(dialog)) {
throw new Error("The overlay does not exist.");
} else if (this.#active) {
if (this.#active === dialog) {
throw new Error("The overlay is already active.");
} else if (this.#overlays.get(dialog).canForceClose) {
await this.close();
} else {
throw new Error("Another overlay is currently active.");
}
}
this.#active = dialog;
dialog.showModal();
dialog.classList.remove("hidden"); // #1434 remove "hidden" class when opening the dialog for the second time
}
I can't reproduce the bug, so I need your help. Maybe you can find out why the dialog is missing in the #overlays
array. My best guess is that the asynchronous nature of pdf.js causes the problem. I've often seen that the new instance of the viewer is still being destroyed while the new instance already initializes. It's using global variables, so this can't go well.
However, you said you already added a timeout, so maybe it's a different problem.
You can also put the viewers into different iFrames. iFrames have their own set of global variables, so your problem is solved.
Hi Stephan,
I cound't find a way to fix it.
I removed the progress dialog completely because in the standard print window that comes afterwards, the users have to wait anyway again until the pdf loads.
With the progressbar window, they have to wait twice.
I added my own print button and I open directly the standard print window.
:)
That makes sense, and I guess it's a clever work-around. Thanks for updating me!
Best regards, Stephan
Hi Stephan,
it doesn't seem to work in Chrome.
I'm using a function to load the blob in an iframe but Chrome wants to download the PDF so it doesn't open it in the iframe:
printPdf() {
let blobURL = URL.createObjectURL(this.vm.reportPdf);
let iframe = document.createElement('iframe'); //load content in an iframe to print later
document.body.appendChild(iframe);
iframe.style.display = 'none';
iframe.src = blobURL;
iframe.onload = function () {
setTimeout(function () {
iframe.focus();
iframe.contentWindow.print();
}, 1);
};
}
Refused to frame 'blob...' because it violates the following Content Security Policy directive: "frame-src 'self'
Do you have a tip about how to open the standard printing window without getting this error?
Best regards, Max
No, I don't have a tip, but I've asked ChatGPT, and even though I can't guarantee the answer is correct, it doesn't seem to be entirely wrong. Maybe it helps!
The issue you're encountering with the iframe refusing to display the blob URL is due to the Content Security Policy (CSP) that is likely set on your web server. CSP is a security measure that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. The error message suggests that your CSP is configured to only allow framing content from the same origin ('self').
Here are some steps and tips to resolve the issue:
Content-Security-Policy: frame-src 'self' blob:;
This allows blob URLs to be used in frames while maintaining the rest of the CSP policy intact.
printPdf() {
let blobURL = URL.createObjectURL(this.vm.reportPdf);
window.open(blobURL, '_blank').focus();
}
This method opens the PDF in a new tab, and users can use the browser’s built-in print function to print the PDF.
Content-Disposition: inline; filename="filename.pdf"
Review and Test CSP Settings: Always ensure that your CSP settings do not inadvertently weaken your site’s security. Test your CSP changes thoroughly to ensure that they do not expose your site to XSS or other vulnerabilities.
Each method has its trade-offs in terms of user experience and security, so choose the one that best aligns with your application’s needs and security policies.
Hi Stephan,
thank you very much for the clarifications.
What are you using, because if I leave the standard print button, I don't get any CSP error. Only the progress bar dialog is the problem.
I thought there is a way to open the printing dialog without opening first the progress bar dialog.
:)
Hi Stephan,
we added Content-Security-Policy: frame-src 'self' blob:; and it worked.
Thank you.
That's the magic of AI: I've posted an answer that missed your question slightly, but even so, a short time later you come up with a solution... :)
I'm glad you've managed to solve the issue!
Hi Stephan,
I've noticed 2 JavaScript errors in the console if I try to print a document but cancel it.
After clicking on print, a small modal window with a progress bar shows up. If I click on cancel or cancel it with escape, I get an error:
Another issues I have seen, it's when there are multiple pdf files.
I habe a table with multiple files. I click on one and open the pdf in the viewer, I click on print and the modal window with the progress bar opens. Afterwards the printing dialog opens. So far so good.
I close it and click on another link from the table to open another pdf file. It opens but when I try to print it, I get a JavaScript error saying the "The overlay does not exist".
The modal window with the progress bar doesn't show up anymore but after a few seconds the printing dialog opens.
Is there a way to fix this?
Thank you very much for your time and for the great job.
Best Regards