在 IE9 对象元素中查看时如何 "postMessage" 从 pdf 中托管

How to "postMessage" to host from within pdf when viewed in IE9 object element

我正在尝试用 PDF 做一个小型 PoC,但 运行 遇到了一个问题。我正在寻找 post 发送给 PDF 的消息,并让 PDF post 发送给浏览器的消息。

DEETS:

我正在 IE9 中的 "object" 元素中查看 PDF。我正在使用 itextsharp 在服务器上预填充 pdf 模板,注入一些应用程序级别 javascript(post 消息和消息内容),然后通过 filestreamresult 将其提供给浏览器。我正在使用 Reader 10 在 IE9 中查看 PDF。

什么有效:

到目前为止,除了 PDF post向浏览器发送消息外,一切正常。我可以 post 从浏览器向 PDF 发送消息,没问题,所有字段都已根据需要预先填写。

什么不起作用:

当我尝试使用 this.hostContainer.postMessage(["something","somethingmore"]) 时,我得到一个 Acrobat Escript window,上面写着 "hostContainer is not defined"。我也尝试过使用 "event.target.hostContainer" 但我得到 "event.target is not defined"。我不知所措,任何见解都会非常有帮助。

参考链接:

  1. Acrobat Javascript API
  2. Whosebug How-To on this topic
  3. Original guide I used

代码:

我的表单视图:

<object id="pdfFrame" style="width:100%;height: 100%;" data="@Url.Action("LoadForm")">No luck :(</object>

我的自定义javascript字符串方法:

private static string GetCustomJavascript(string existingJavaScript)
    {
        const string newJs = 
        "this.disclosed = true; " +
        "if (this.external && this.hostContainer) { " +
            "function onMessageFunc( stringArray ) { " +
//                    "var name = this.myDoc.getField(personal.name); " +
//                    "var login = this.myDoc.getField(personal.loginname); " +
                    "try{" +
                        "app.alert(doc.xfa);" +
                        "console.println('Doc xfa value = ' + doc.xfa);" +
//                            "event.target.hostContainer.postMessage(['hello from pdf!']);" +
//                        "this.hostContainer.postMessage(['hello from pdf!']);"+
//                        "name.value = stringArray[0]; " +
//                        "login.value = stringArray[1]; " +
                    "} catch(e){ onErrorFunc(e); } " +
                "} " +
                "function onErrorFunc( e ) { " +
                    "console.show(); " +
                    "console.println(e.toString()); " +
                "} " +
                "try {" +
                    "if(!this.hostContainer.messageHandler) { " +
                        "this.hostContainer.messageHandler = new Object(); " +
                        "this.hostContainer.messageHandler.myDoc = this; " +
                        "this.hostContainer.messageHandler.onMessage = onMessageFunc; " +
                        "this.hostContainer.messageHandler.onError = onErrorFunc; " +
                        "this.hostContainer.messageHandler.onDisclose = function(){ return true; }; " +
                    "}" +
                "} catch(e){onErrorFunc(e);}" +
            "}";
            var jsToReturn = existingJavaScript + newJs;
            return jsToReturn;
        }

我的填写表单并发送到浏览器的方法:

public MemoryStream GetFilledRequestForm(string fileDirectory, User user, FormView formView)
        {
            var pdfStream = new MemoryStream();
            var templateFilePath = GetRequestTypeTemplateFilePath(fileDirectory, _requestModule.FormTemplateFileName);
            var pdfReader = new PdfReader(templateFilePath);
//            pdfReader.RemoveUsageRights();
            var stamper = new PdfStamper(pdfReader, pdfStream);
            var formFields = GetFormFields(user, formView, pdfReader);
            foreach (var field in formFields.Where(f => f.Value != null))
            {
                stamper.AcroFields.SetField(field.Name, field.Value);
            }
            stamper.FormFlattening = false;
            var newJs =  GetCustomJavascript(stamper.Reader.JavaScript);
            stamper.AddJavaScript("newJs", newJs);
            stamper.Close();
            byte[] byteInfo = pdfStream.ToArray();
            var outputStream = new MemoryStream();
            outputStream.Write(byteInfo, 0, byteInfo.Length);
            outputStream.Position = 0;
            return outputStream;
        }

好的,我已经解决了,当然是在一些帮助下。我在 this stack overflow post 找到了钥匙。在分配消息处理程序之前,我需要等待对象加载。此外,我需要 pdf javascript 中的全局变量才能 post 消息。

Html/Javascript:(这里的关键是loadListener()函数)

    @model WebModel.FormView
<object id="pdfFrame" style="width:100%;height: 100%;" data="@Url.Action("LoadForm")">No luck :(</object>
    <input id="buttonPost" type="button" value="post to pdf"/>
    <script type="text/javascript">
        var PDFObject = document.getElementById("pdfFrame");
        function loadListener() {
            if (typeof PDFObject.readyState === 'undefined') { // ready state only works for IE, which is good because we only need to do this for IE because IE sucks in the first place
                debugger;
                PDFObject.messageHandler = { onMessage: messageFunc };
                return;
            }
            if (PDFObject.readyState == 4) {
                debugger;
                PDFObject.messageHandler = { onMessage: messageFunc };
            } else {
                setTimeout(loadListener, 500);
            }
        }
        function messageFunc(data) {
            debugger;
            var messagedata = data;
            alert('finally!!');
        }

        function sendToPdf() {
            if(PDFObject!= null){
                PDFObject.postMessage(
                ["a", "b"]);
            }
        }

        $('#pdfFrame').ready(function() {
            loadListener();
            $('#buttonPost').on('click', function() {
                sendToPdf();
            });
        });

    </script>

我创建 javascript 的新函数:(这里的关键是 var appHostContainer)

private static string GetCustomJavascript(string existingJavaScript)
        {
            const string newJs = 
            "this.disclosed = true; " +
            "var appHostContainer = this.hostContainer;" + 
            "if (this.external && this.hostContainer) { " +
                "function onMessageFunc( stringArray ) { " +
//                    "var name = this.myDoc.getField(personal.name); " +
//                    "var login = this.myDoc.getField(personal.loginname); " +
                    "try{" +
                        "app.alert(stringArray);" +
                        "appHostContainer.postMessage(['hello from pdf!']);" +
//                        "name.value = stringArray[0]; " +
//                        "login.value = stringArray[1]; " +
                    "} catch(e){ onErrorFunc(e); } " +
                "} " +
                "function onErrorFunc( e ) { " +
                    "console.show(); " +
                    "console.println(e.toString()); " +
                "} " +
                "try {" +
                    "if(!this.hostContainer.messageHandler) { " +
                        "this.hostContainer.messageHandler = new Object(); " +
                        "this.hostContainer.messageHandler.myDoc = this; " +
                        "this.hostContainer.messageHandler.onMessage = onMessageFunc; " +
                        "this.hostContainer.messageHandler.onError = onErrorFunc; " +
                        "this.hostContainer.messageHandler.onDisclose = function(){ return true; }; " +
                    "}" +
                "} catch(e){onErrorFunc(e);}" +
            "}";
            var jsToReturn = existingJavaScript + newJs;
            return jsToReturn;
        }