在 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"。我不知所措,任何见解都会非常有帮助。
参考链接:
- Acrobat Javascript API
- Whosebug How-To on this topic
- 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;
}
我正在尝试用 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"。我不知所措,任何见解都会非常有帮助。
参考链接:
- Acrobat Javascript API
- Whosebug How-To on this topic
- 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;
}