Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you detect when a PDF is printed or downloaded from the browser PDF viewer?

We have an AngularJS web app that loads PDF documents from the server and displays them within the page like this:

<object id="preview" type="application/pdf" data="blob:{fileUrl}">

We have a new requirement to audit whenever a user performs certain actions:

  1. views a document (done)
  2. prints a document
  3. downloads a document

The PDF download and print controls are within the browser PDF viewer. We only have to support latest Google Chrome (Chrome 68 as of July 2018).

Is it possible to detect when the file is downloaded or printed from the PDF viewer? I'm not seeing any beforeprint/afterprint events, I assume because it's cross-origin. We don't need to control the handlers, just detect the events somehow.

like image 577
jbkly Avatar asked Jul 25 '18 23:07

jbkly


3 Answers

Unfortunately, you can not append any script to the PDF window because it is from MIME type "application/pdf".

If you load some PDF in your Chrome browser and then look into developer console you will see some code like follows:

<embed width="100%" height="100%" name="plugin" id="plugin"
    src="your-pdf-path.pdf" type="application/pdf" internalinstanceid="7">

I have tried to add some script into PDF window like follows:

<style type="text/css">html,body{height:100%;margin:0}</style>
<iframe id="iframe1" src="your-pdf-path.pdf" frameborder="0"
    style="display:block;width:100%;height:100%"></iframe>

<script type="text/javascript">
var ifrDoc = document.getElementById('iframe1').contentWindow.document;
var script = ifrDoc.createElement('script');
script.type = 'text/javascript';
script.innerText = 'alert(1)';
//OR: script.src = 'your-js-file-path.js'

ifrDoc.getElementsByTagName('head')[0].appendChild(script);
</script>

But it does nothing because the MIME type is "application/pdf".

You can detect the print events only for HTML-documents like follows:

function beforePrint(){alert('before print')}

function afterPrint(){alert('after print')}

if(window.onafterprint !== void 0)
{
    window.onbeforeprint = beforePrint;
    window.onafterprint = afterPrint;
}
else if(window.matchMedia)
{
    var mediaQueryList = window.matchMedia('print');
    mediaQueryList.addListener(function(mql)
    {
        if(mql.matches)
            beforePrint();
        else afterPrint()
    });
}

For more details into and what it can be used for you can read this article.

May be you can use this code but I think not for this case.

Because of all this you can write a solution only if you write your own PDF viewer. You can use PDF.js for example for this goal. PDF.js is Portable Document Format (PDF) viewer that is written in JavaScript. It is open source and you can download the full source code on GitHub here.

And for download is the same (only with your own PDF viewer), but I would like to recomend to read following links:

  • Detect when browser receives file download.
  • The onCreated() event of the downloads API

And may be with my answer you could save your time!

like image 76
Bharata Avatar answered Oct 29 '22 01:10

Bharata


Have you tried creating your own pdf viewer?

There are pdf viewer components readily available where you can edit your pdf viewer(like add event listeners to buttons, position them, etc).

I remember building one on top of pdf.js in angular a long time ago. I am sure with pdf.js you can implement all the above-mentioned use cases.

like image 45
TheViralGriffin Avatar answered Oct 28 '22 23:10

TheViralGriffin


You said it is to detect from the browser. print() is a window level function.

I hope the first two answers from this link helps you with your printing listening. how to detect window.print() finish

Regarding you download complete listener, you need to implement logic

if your download progress bar is at 100% when downloaded part of the document is not increasing.

then it means printing is completed. And this perfectly works for you as you are downloading pdf documents, which don't get downloaded in multiple files.

So, you set up a progress bar. You use that progress bar until the downloaded file keep incrementing in each interval (you set timeout here). Even after waiting for timeout interval, you don't have your downloaded file incremented, you define that as an end for your progress bar.

elementType.onclick = function() { 
        // if progress bar completes when file download stops
        // call downloadcompleted() function           
   }

For the link click listener: Adding an onclick function to go to url in JavaScript?

like image 33
Uddhav P. Gautam Avatar answered Oct 29 '22 01:10

Uddhav P. Gautam