Search code examples
javascriptjsfpdfacrobatacrobat-sdk

How to implement ctrl click behavior to copy text from an embedded pdf in a webapp?


I have a requirement for a webapp to implement the following behavior:

After a webform is opened with an embedded PDF object is shown in the browser the user needs to be able to select a text in the document with a ctrl + mouse click after which the selected text is copied to an inputfield in the same webform that the embedded PDF object is shown.

Are there API's out there (preferably open source) that implement this behavior? Can I meet this requirement using techniques like JSP, JSF, PrimeFaces, Javascript or HTML5 and how would I do that?


Solution

  • In the example I'll use

    • PDF.js
    • JSF 2.2 (doesn't really matter what version, but it's better to be 2.x)
    • PrimeFaces (for the inputField or textArea) * optional

    Steps:

    • Downloading and Integrating PDF.js
    • Register Event on CTRL

    Downloading and Integrating PDF.js

    Download PDF.js, after the download is complete unzip it, you would see the following folder hierarchy

    .
     ├── LICENSE
     ├── build
     │   ├── pdf.js
     │   └── pdf.worker.js
     └── web
         ├── cmaps/
         ├── compatibility.js
         ├── compressed.tracemonkey-pldi-09.pdf
         ├── debugger.js
         ├── images/
         ├── l10n.js
         ├── locale/
         ├── viewer.css
         ├── viewer.html
         └── viewer.js
    

    Assuming you have a JSF project with a resources folder inside webapp, copy the following files from web folder (from the unziped file) into resources in which they would look like this :

    webapp/resources folder

    ├── css
    │   └── viewer.css (web/viewer.css)
    ├── images
    │   └── pdfjs
    │       ├── ** All the images inside (web/images)
    └── js
       └── pdfjs
           ├── compatibility.js (web/compatibility.js)
           ├── l10n.js (web/l10n.js)
           ├── pdf.js (web/pdf.js)
           ├── pdf.worker.js (web/pdf.worker.js)
           └── viewer.js (web/viewer.js)
    

    Edit viewer.css to resolve all the required images, replace each url with

    "#{resource['images/pdfjs/correspondingImageName']}"

    here's a full resolved viewer.css

    Create xhtml file with the content of viewer.html (web/viewer.html from zip), which would represent the viewer markup, the reason that I'de use the viewer with all the html 5 markup is the ability to select text, not like the canvas only example

    Here's a full copied example of viewer.html into viewer.xhml

    Notice in the end I've included the libraries in the following order:

    <h:outputScript name="js/pdfjs/compatibility.js" target="head" /> 
    <h:outputScript name="js/pdfjs/l10n.js" target="head" />
    <h:outputScript name="js/pdfjs/pdf.js" target="head" />  
    <h:outputScript name="js/pdfjs/viewer.js" target="head" />
    

    To get PDF.js running you need to specify two things, the pdf.worder.js location and the pdfURL (see in viewer.xhml)

     <script>
         var DEFAULT_URL = "#{pdfURL}"; //pdf should be hosted on your domain name (ajaxly loaded) 
         PDFJS.workerSrc = "#{resource['js/pdfjs/pdf.worker.js']}";
     </script>
    

    Register Event on CTRL

    Define an inputText or inputTextArea

    <p:inputTextarea id="inputTextArea" />
    

    Now register an event of keydown or whatever that fit, example:

     $('.pdfZone').keydown(function(event) {
        if (event.which == "17"){ // CTRL key
           $('#inputTextArea').text(window.getSelection().toString())
         }                 
     });
    

    .pdfZone is a div container of the pdf viewer

    You can find a full example on github [1] [2], and an online Demo.

    Note: I didn't use CTRL + Click because in my Mac OSX would trigger the Right Click, anyhow you could change the event handling.

    Suggestion to use CTRL + Click (but the demo would use only CTRL)

     $('.pdfZone').on('mouseup',function(e) {                       
        if (e.ctrlKey) {
           $('#inputTextArea').text(window.getSelection().toString());
         }
     });