I occasionally see questions about adding javascript to existing pdf's. There are (of course) some great examples on the iText site. I thought this CF translation of the AddJavaScriptToForm example might be helpful. If you review the code and comments, it actually simpler than it looks. There are some minor differences to compensate for the older iText jars in CF9 and CF8. As well as some name changes to avoid reserved word conflicts.
Source: http://1t3xt.info/examples/browse/?page=example&id=438
Javascript Code (CF8 + CF9)
<cfsavecontent variable="jsCode">
function setReadOnly(readonly) {
var partner = this.getField('partner');
if(readonly) {
partner.value = '';
}
partner.readonly = readonly;
}
function validate() {
var married = this.getField('married');
var partner = this.getField('partner');
if (married.value == 'yes' && partner.value == '') {
app.alert('please enter the name of your partner');
}
else {
var prop = new Object();
prop.cURL = "http://1t3xt.info/examples/request.php";
prop.cSubmitAs = "HTML";
this.submitForm( {
cURL: "http://1t3xt.info/examples/request.php",
cSubmitAs: "HTML"
}
);
}
}
</cfsavecontent>
1) Create a Form (CF9 + CF8)
Note: CF8 does not support "finally". So for compatibility, just change the try/finally clause to a try/catch.
<cfscript>
outputPath = ExpandPath("form_without_js.pdf");
document = createObject("java", "com.lowagie.text.Document").init();
try {
stream = createObject("java", "java.io.FileOutputStream").init( outputPath );
writer = createObject("java", "com.lowagie.text.pdf.PdfWriter").getInstance(document, stream);
document.open();
Element = createObject("java", "com.lowagie.text.Element");
BaseFont = createObject("java", "com.lowagie.text.pdf.BaseFont");
//Note: CF8 + CF9 iText versions do not have a createFont() method with zero params
bf = BaseFont.createFont( BaseFont.HELVETICA, BaseFont.WINANSI, false );
directcontent = writer.getDirectContent();
directcontent.beginText();
directcontent.setFontAndSize(bf, 12);
directcontent.showTextAligned( Element.ALIGN_LEFT, "Married?", 36, 770, 0 );
directcontent.showTextAligned( Element.ALIGN_LEFT, "YES", 58, 750, 0);
directcontent.showTextAligned( Element.ALIGN_LEFT, "NO", 102, 750, 0);
directcontent.showTextAligned( Element.ALIGN_LEFT, "Name partner?", 36, 730, 0 );
directcontent.endText();
// initialize reusable objects
Rectangle = createObject("java", "com.lowagie.text.Rectangle");
PdfFormField = createObject("java", "com.lowagie.text.pdf.PdfFormField");
RadioCheckField = createObject("java", "com.lowagie.text.pdf.RadioCheckField");
TextField = createObject("java", "com.lowagie.text.pdf.TextField");
Color = createObject("java", "java.awt.Color");
married = PdfFormField.createRadioButton(writer, true);
married.setFieldName("married");
writer.addAnnotation( married );
// Note: Field names changed to avoid CF reserved word conflicts (ie "yes", "no")
married.setValueAsName("yes");
rectYes = Rectangle.init( 40, 766, 56, 744 );
yesField = RadioCheckField.init(writer, rectYes, javacast("null", ""), "yes");
yesField.setChecked(true);
married.addKid( yesField.getRadioField() );
rectNo = Rectangle.init( 84, 766, 100, 744 );
noField = RadioCheckField.init(writer, rectNo, javacast("null", ""), "no");
noField.setChecked(false);
married.addKid( noField.getRadioField() );
writer.addAnnotation( married );
rect = Rectangle.init( 40, 710, 200, 726 );
partner = TextField.init( writer, rect, "partner" );
partner.setBorderColor( Color.BLACK );
partner.setBorderWidth( 0.5 );
writer.addAnnotation( partner.getTextField() );
document.close();
WriteOutput("File created! "& outputPath &"<hr>");
}
// cleanup
finally {
if (isDefined("document")) {
document.close();
}
if (isDefined("stream")) {
stream.close();
}
}
</cfscript>
2) Add the Javascript (CF9 Only)
<cfscript>
inputPath = ExpandPath("form_without_js.pdf");
outputPath = ExpandPath("form_plus_js.pdf");
document = createObject("java", "com.lowagie.text.Document").init();
try {
// read in the pdf form
reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( inputPath );
stream = createObject("java", "java.io.FileOutputStream").init( outputPath );
stamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init( reader, stream );
// add javascript functions to the document
stamper.getWriter().addJavaScript( jsCode );
// create reference objects
PdfName = createObject("java", "com.lowagie.text.pdf.PdfName");
PdfAction = createObject("java", "com.lowagie.text.pdf.PdfAction");
PdfDictionary = createObject("java", "com.lowagie.text.pdf.PdfDictionary");
PushbuttonField = createObject("java", "com.lowagie.text.pdf.PushbuttonField");
// extract the parent option from the form
formObj = stamper.getAcroFields();
fd = formObj.getFieldItem("married");
// retrieve the dictionaries for "yes" radio button
// note: CF9 iText version does not have the getWidgetRef(index) method
dictYes = reader.getPdfObject( fd.widget_refs.get(0) );
yesAction = dictYes.getAsDict( PdfName.AA );
if (not IsDefined("yesAction")) {
yesAction = PdfDictionary.init();
}
// add an onFocus event to this field
yesAction.put( PdfName.init("Fo"), PdfAction.javaScript("setReadOnly(false);", stamper.getWriter()));
dictYes.put( PdfName.AA, yesAction );
// retrieve the dictionaries for "no" radio button
dictNo = reader.getPdfObject( fd.widget_refs.get(1));
noAction = dictNo.getAsDict( PdfName.AA );
if (not IsDefined("noAction")) {
noAction = PdfDictionary.init();
}
// add an onFocus event to this field
noAction.put( PdfName.init("Fo"), PdfAction.javaScript("setReadOnly(true);", stamper.getWriter()));
dictNo.put(PdfName.AA, noAction);
// create a submit button
writer = stamper.getWriter();
button = PushbuttonField.init( writer, Rectangle.init(40, 690, 200, 710), "submit" );
button.setText( "validate and submit" );
button.setOptions( PushbuttonField.VISIBLE_BUT_DOES_NOT_PRINT );
validateAndSubmit = button.getField();
// this will call the validate function when the button is clicked
validateAndSubmit.setAction( PdfAction.javaScript("validate();", stamper.getWriter()) );
// add the button to page 1
stamper.addAnnotation(validateAndSubmit, 1);
WriteOutput("File created! "& outputPath &"<hr>");
}
finally {
// cleanup
if (isDefined("stamper")) {
stamper.close();
}
if (isDefined("stream")) {
stream.close();
}
}
</cfscript>
2) Add the Javascript (CF8 Only)
<cfscript>
inputPath = ExpandPath("form_without_js.pdf");
outputPath = ExpandPath("form_plus_js.pdf");
document = createObject("java", "com.lowagie.text.Document").init();
try {
// read in the pdf form
reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( inputPath );
stream = createObject("java", "java.io.FileOutputStream").init( outputPath );
stamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init( reader, stream );
// add javascript functions to the document
stamper.getWriter().addJavaScript( jsCode );
// create reference objects
PdfName = createObject("java", "com.lowagie.text.pdf.PdfName");
PdfAction = createObject("java", "com.lowagie.text.pdf.PdfAction");
PdfDictionary = createObject("java", "com.lowagie.text.pdf.PdfDictionary");
PushbuttonField = createObject("java", "com.lowagie.text.pdf.PushbuttonField");
// prepare to extract form field objects
formObj = stamper.getAcroFields();
// get parent option
fd = formObj.getFieldItem("married");
// retrieve the dictionaries for "yes" radio button
// note: CF8 iText version does not have the getWidgetRef(index) method or getDirectObject()
dictYes = reader.getPdfObject( fd.widget_refs.get(0) );
yesAction = reader.getPdfObject(dictYes.get(PdfName.AA));
if (not IsDefined("yesAction") or not yesAction.isDictionary()) {
yesAction = PdfDictionary.init();
}
// add an onFocus event to this field
yesAction.put( PdfName.init("Fo"), PdfAction.javaScript("setReadOnly(false);", stamper.getWriter()));
dictYes.put( PdfName.AA, yesAction );
// retrieve the dictionaries for "no" radio button
dictNo = reader.getPdfObject( fd.widget_refs.get(1));
noAction = reader.getPdfObject( dictNo.get(PdfName.AA) );
if (not IsDefined("noAction") or not noAction.isDictionary()) {
noAction = PdfDictionary.init();
}
// add an onFocus event to this field
noAction.put( PdfName.init("Fo"), PdfAction.javaScript("setReadOnly(true);", stamper.getWriter()));
dictNo.put(PdfName.AA, noAction);
// create a submit button
writer = stamper.getWriter();
button = PushbuttonField.init( writer,
Rectangle.init(40, 690, 200, 710),
"submit"
);
button.setText( "validate and submit" );
button.setOptions( PushbuttonField.VISIBLE_BUT_DOES_NOT_PRINT );
validateAndSubmit = button.getField();
// this will cal the validate function when the button is clicked
validateAndSubmit.setAction( PdfAction.javaScript("validate();", stamper.getWriter()) );
// add the button to page 1
stamper.addAnnotation(validateAndSubmit, 1);
WriteOutput("File created! "& outputPath &"<hr>");
}
catch(Any e) {
WriteOutput("ERROR: "& e.message);
}
if (isDefined("stamper")) {
stamper.close();
}
if (isDefined("stream")) {
stream.close();
}
</cfscript>
...Read More