12
votes

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.

3
I don't know, but ... if you open the Chrome DOM inspector, can you see any DOM elements for the PDF viewer? Perhaps also attach a click event to window, then console.log event.target to see if PDF viewer is recognized?Ted Fitzpatrick
This is how to JavaScript in pdf help.adobe.com/en_US/acrobat/acrobat_dc_sdk/2015/HTMLHelp/… and to add javascript without the acrobat, see this bililite.com/blog/2012/06/06/adding-javascript-to-pdf-files I think the solution, if there are any, is about JavaScript inside pdfEmeeus
I don't think you can detect this from a browser. The printing functionality is "outside" the browser sandbox for security reasons. This is also why you can't just make a web page start printing without the browser showing some sort of print dialog box or form. If this were allowed, Internet Baddies could just make a web page start printing reams of paper and cause grief, frustration and worse reactions. I think the bet approach would be like Emeeus is suggesting in that you have the PDF itself see if it can report printing.mrunion
And how would you even know if the user printed the document after downloading it ? - The statistic will be flawed however you try to solve this. This is a case where the business goal of these numbers is important.Falco

3 Answers

7
votes

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.

4
votes

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:

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

1
votes

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?