PDF hostContainer callback
Asked Answered
P

1

10

Following this SO solution here to notify clients of a click event in a PDF document, how is it possible to notify the client when the PDF gets submitted by the client using this.myPDF.submitForm("localhost/Handler.ashx?r=2) function?

The PDF File is created inside a user control then rendered into a HTML object:

string container = ("<object data='/myfile.pdf' type='application/pdf'></object>");

The JS file attached to the PDF is done like this:

 var webClient = new WebClient();
 string htmlContent = webClient.DownloadString(fileurl + "pdf_script.js");
 PdfAction action = PdfAction.JavaScript(htmlContnent, pdfstamper.Writer);
 pdfstamper.Writer.SetOpenAction(action);

And the content of the js file:

this.disclosed = true;
if (this.external && this.hostContainer) {

function onMessageFunc(stringArray) {
     try {
          this.myPDF.submitForm("http://localhost/Handler.ashx?EmpNo=12345" + "#FDF", false);

        }
        catch (e) {

        }
    }
    function onErrorFunc(e) {
        console.show();
        console.println(e.toString());
    }
    try {
        if (!this.hostContainer.messageHandler);
        this.hostContainer.messageHandler = new Object();
        this.hostContainer.messageHandler.myPDF = this;
        this.hostContainer.messageHandler.onMessage = onMessageFunc;
        this.hostContainer.messageHandler.onError = onErrorFunc;
        this.hostContainer.messageHandler.onDisclose = function () { return true; };
    }
    catch (e) {
        onErrorFunc(e);
    }
}

When the submitForm call is made the PDF contents (form fields) get saved successfully and an alert is displayed in the PDF by doing this:

message = "%FDF-1.2
                   1 0 obj
                   <<
                   /FDF
                   <<
                      /Status("Success!")
                   >>
                   >>
                   endobj
                   trailer
                   <</Root 1 0 R>>
           %%EOF");
return message;

What I'm trying to do is to get the PDF to callback the client after the form submit call sent from this client, a way to acknowledge the client that the form has been submitted, not in a form of an alert, but rather, a way to trigger a function in the host (the container, an iframe, object...etc).

Prothonotary answered 12/12, 2012 at 9:49 Comment(3)
I'm missing some information regarding this step: "When the submitForm call is made the PDF gets created successfully and an alert is displayed in the PDF by doing this:". I assume that a PDF is created on the server and displayed on the client, but maybe I'm wrong. Maybe the server is returning an FDF file. Can you clarify?Diclinous
Ooops, my mistake, the submitForm call is made to SAVE the contents of the PDF not creating it, it is already rendered in a user control and embedded into an <object> apologies, I have corrected the question and added more details about how the PDF is renderedProthonotary
I don't understand above where is says "if (!this.hostContainer.messageHandler);" Why does that line have a semicolon at the end? Is this an error? if not, what is the purpose of that line? many thanks!Snooperscope
D
5

The FDF response you used was unknown to me, so I've learned something new from your question. I've studied the AcroJS Reference and the FDF specification in the PDF Reference, and now I have a better understanding of what your code does. Thank you for that.

I assume that you already know how to trigger a JavaScript message in an HTML file using a JavaScript call from a PDF. See the createMessageHandler() in the JavaScript Communication between HTML and PDF article.

I interpret your question as: "How to I invoke this method after a successful submission of the data?"

If there's a solution to this question, it will involve JavaScript. I see that one can add JavaScript in an FDF file, but I'm not sure if that JavaScript can 'talk to' HTML. I'm not sure if you can call a JavaScript function in your initial PDF from the FDF response. If it's possible, you should add a JavaScript entry to your PDF similar to the /Status entry.

The value of this entry is a dictionary, something like:

<<
/Before (app.alert\("before!"\))
/After (app.alert\("after"\))
/Doc [/MyDocScript1, (myFunc1\(\)),
      /MyDocScript2, (myFunc2\(\))
>>

In your case, I would remove the /Before and /Doc keys. I don't think you need them, I'd reduce the dictionary to:

<<
/After (talkToHtml\(\))
>>

Where talkToHtml() is a method already present in the PDF:

function talkToHtml() {
    var names = new Array();
    names[0] = "Success!";
    try{
        this.hostContainer.postMessage(names);
    }
    catch(e){
        app.alert(e.message);
    }
}

I don't know if this will work. I've never tried it myself. I'm basing my answer on the specs.

I don't know if you really need to use FDF. Have you tried adding JavaScript to your submitForm() method? Something like:

this.myPDF.submitForm({
    cURL: "http://localhost/Handler.ashx?EmpNo=12345",
    cSubmitAs: "FDF",
    oJavaScript: {
        Before: 'app.alert("before!")',
        After: 'app.alert("after")',
        Doc: ["MyDocScript1", "myFunc1()",
              "MyDocScript2", "myFunc2()" ]
    }
});

This will only work if you submit as FDF. I don't think there's a solution if you submit an HTML query string.

In case you're wondering what MyDocScript1 and MyDocScript2 are:

Doc defines an array defining additional JavaScript scripts to be added to those defined in the JavaScript entry of the document’s name dictionary. The array contains an even number of elements, organized in pairs. The first element of each pair is a name and the second is a text string or text stream defining the script corresponding to that name. Each of the defined scripts is added to those already defined in the name dictionary and then executed before the script defined in the Before entry is executed. (ISO-32000-1 Table 245)

I'm not sure if all of this will work in practice. Please let me know either way.

Diclinous answered 16/12, 2012 at 13:21 Comment(4)
At last this is working now practically, client an PDF can talk both ways, in case you want to update the answer I had to amend the /After line to be: /JavaScript << /After (saveComplete()) >> . Thanks, you got the bounty!Prothonotary
@Maya: I would like to achieve the same but before diving into the answer and the docs, I'd like to ask if the solution is still working on modern browsers. Thanks for any input!Renettarenew
@Renettarenew This is still working on Edge and a 2-months old Chrome at the workplaceProthonotary
@Maya: Thanks for your reply! Is the Adobe Reader browser plugin being used? I would like to use an open reader and thus try to make things work in pdf.js but folks from pdf.js development told me that JS is not supported there and won't be (due to some ISO norm prohibiting JS usage in PDFs: en.wikipedia.org/wiki/PDF/A#Description)Renettarenew

© 2022 - 2024 — McMap. All rights reserved.