# pdftex and javascript forms with automatic calculations

I would like to create a PDF document in TeX with a form. Some of the fields in the form will be calculated based on the values of other fields.

Here is a MWE, thanks to Victor Ivrii on the pdftex mailing list back in 2005:

\documentclass{article}
\usepackage[pdftex]{hyperref}
\begin{document}
\begin{Form}

\TextField[maxlen=40,keystroke={AFNumber_Keystroke(2, 0, 1, 2,
true);},align=2,height=10pt,width=45pt,name=alpha]{Alpha}

\bigskip
\TextField[maxlen=40,keystroke={AFNumber_Keystroke(2, 0, 1, 2,
true);},align=2,height=10pt,width=45pt,name=beta]{Beta}

\bigskip
\TextField[maxlen=40,keystroke={AFNumber_Keystroke(2, 0, 1, 2, true);},
calculate={AFSimple_Calculate("SUM" , new Array ( "alpha" , "beta" )
;)},  align=2,height=10pt,width=45pt,name=gamma,readonly=true]{Gamma}
\end{Form}
\end{document}


The resulting PDF has three fields, and the third is supposed to automatically update to be the sum of the first two. If I compile the document and open in Acrobat, I can edit the first two fields (alpha and beta) but the third (gamma) does not update. No JavaScript errors are thrown.

If I examine the properties of the field gamma in Acrobat, I can see that its calculate property is set to be the sum of the to fields alpha and beta.

If I select "Pick...", I'm shown a dialog with the three fields, and alpha and beta are selected. If I deselect and reselect those fields and accept, the form now works as desired (Acrobat-altered document at scribd). The diff command tells me the PDF file has changed but not how.

I have found some discussion about this on the pdftex mailing list, in the above referenced thread and again here. Ralf Uterman apparently posted a patch as a result of the second thread, but as far as I can tell the issue persists. I have tried the eforms package from the AcroTeX bundle as well, but the author writes in the manual that "Calculate works correctly when drivers dvips, dvipsone, or dvipdfm are used." (pdftex is not listed).

Yet I cannot get this to work under any driver. If I use the dvips driver to compile to DVI, then dvips to convert to PostScript, then convert to PDF using either Acrobat Distiller, I get the same non-functioning form as with pdftex. If I use the dvipdf driver, then dvipdf to convert to PDF, all the form elements are unrecognized and ignored.

This document is going to be stamped over a scanned PDF so I really need no other output except the form and some basic marks. So I'm flexible as to engine, driver, etc., but so far I'm not getting anything to work without manual intervention via Acrobat. I'm aware of the related question “ hyperref: how to format text in a forms text-field ” but I can't get the calculations to work in the accepted answer there, either.

-
Can you give a link to a correct PDF file (after modification by Acrobat)? –  Paul Gaborit Oct 11 '12 at 13:32
@PaulGaborit: Sure. scribd.com/doc/109720332/Ivrii-Fixed (also added to question) –  Matthew Leingang Oct 11 '12 at 15:35
Sorry, I can't get your file: scribd.com requires registration to allow download! But it does not matter since you have a good answer below. –  Paul Gaborit Oct 11 '12 at 16:42
@Paul: sorry, I didn't think about that. –  Matthew Leingang Oct 11 '12 at 16:50

## 2 Answers

Package hyperref 2012/10/12 v6.83i now implements the missing calculation order array in the /Form dictionary for the three driver classes that support PDF forms (pdftex, dvipdfm/xetex, pdfmark/dvips). If a field element contains calculation code, then this field element is automatically added to the calculation order array. Currently only document order is supported.

\documentclass{article}
\usepackage{hyperref}[2012/10/12]

\begin{document}
\begin{Form}

\TextField[maxlen=40,align=2,height=10pt,width=45pt,name=alpha]{Alpha}

\bigskip
\TextField[maxlen=40,align=2,height=10pt,width=45pt,name=beta]{Beta}

\bigskip
\TextField[
maxlen=40,
calculate={%
var f_alpha = this.getField("alpha");
var f_beta = this.getField("beta");
event.value = f_alpha.value + f_beta.value;
},
align=2,height=10pt,width=45pt,name=gamma,readonly=true]{Gamma}
\end{Form}
\end{document}


## Update

Since hyperref 2012/10/13 v6.83j the calculation order can be specified, if pdfTeX is used, from README:

## Field option calculatesortkey

Fields with calculated values are calculated in document order by default. If calculated field values depend on other calculated fields that appear later in the document, then the correct calculation order can be specified with option calculatesortkey. Its value is used as key to lexicographically sort the calculated fields. The sort key do not need to be unique. Fields that share the same key are sorted in document order.

Currently the field option calculatesortkey is only supported by
the driver for pdfTeX.

-
Updating packages just for answering questions and get the rep is cheating. ;-) I'm very happy that you're able to support so many features. –  egreg Oct 13 '12 at 13:05
TeX.SeX really helps the TeX grow quickly. –  Please don't touch Oct 14 '12 at 3:28

The PDF specification requires that every form field that should be recalculated must be registered in the calculation order entry of the interactive form dicitionary (cf. pp. 416, 431). hyperref doesn't do this automatically though, so your JavaScript isn't taken into account by the viewer. The patch you mentioned should take up this job, but it doesn't seem to work any more, probably because the hyperref implementation has changed: With the current version, the default form dictionary without the calculation order is used instead of the "correct" one as created by the patch.

This solution adds form fields with a non-empty calculate value to the calculation order (automatically). The implementation is very similar to the creation of the list of all form fields as done by hyperref:

\documentclass{article}
\usepackage[pdftex]{hyperref}

\usepackage{etoolbox}
\makeatletter
\let\HyField@calcorder\ltx@empty
\Hy@AtBeginDocument{%
\if@filesw
\immediate\write\@mainaux{%
\string\providecommand\string\HyField@AuxAddToCalculationOrder[1]{}%
}%
\fi
\def\HyField@AuxAddToCalculationOrder#1{%
\xdef\HyField@calcorder{%
\ifx\HyField@calcorder\@empty
\else
\HyField@calcorder
\space
\fi
#1 0 R%
}%
}%
}
\def\HyField@@AddToFields#1{%
\HyField@AfterAuxOpen{%
\if@filesw
\write\@mainaux{%
\string\HyField@AuxAddToFields{#1}%
}%
\ifx\Fld@calculate@code\@empty
\else
\write\@mainaux{%
\string\HyField@AuxAddToCalculationOrder{#1}%
}%
\fi
\fi
}%
}%
\patchcmd{\@Form}{/Fields[\HyField@afields]}{/CO[\HyField@calcorder]/Fields[\HyField@afields]}{}{}
\makeatother

\begin{document}
\begin{Form}

\TextField[maxlen=40,keystroke={AFNumber_Keystroke(2, 0, 1, 2,
true);},align=2,height=10pt,width=45pt,name=alpha]{Alpha}

\bigskip
\TextField[maxlen=40,keystroke={AFNumber_Keystroke(2, 0, 1, 2,
true);},align=2,height=10pt,width=45pt,name=beta]{Beta}

\bigskip
\TextField[maxlen=40,keystroke={AFNumber_Keystroke(2, 0, 1, 2, true);},
calculate={AFSimple_Calculate("SUM" , new Array ( "alpha" , "beta" )
);},  align=2,height=10pt,width=45pt,name=gamma,readonly=true]{Gamma}
\end{Form}
\end{document}


BTW: In your MWE, the ; in the calculate expression was misplaced, this is corrected in the above code.

The eforms package requires hyperref, but it implements the creation of the form fields differently, so the above patch won't work. However, it can be adapted by patching the text field macro of eforms to call the auxiliary hyperref command necessary for generating the calculation order. This code should work for text fields created both by hyperref and eforms.

\documentclass{article}
\usepackage[pdftex]{eforms}

\usepackage{etoolbox}
\makeatletter
\let\HyField@calcorder\ltx@empty
\Hy@AtBeginDocument{
\if@filesw
\immediate\write\@mainaux{%
\string\providecommand\string\HyField@AuxAddToCalculationOrder[1]{}%
}%
\fi
\def\HyField@AuxAddToCalculationOrder#1{%
\xdef\HyField@calcorder{%
\ifx\HyField@calcorder\@empty
\else
\HyField@calcorder
\space
\fi
#1 0 R%
}%
}%
}
\def\HyField@@AddToFields#1{%
\HyField@AfterAuxOpen{%
\if@filesw
\write\@mainaux{%
\string\HyField@AuxAddToFields{#1}%
}%
\ifx\Fld@calculate@code\@empty
\ifisCalculate
\write\@mainaux{%
\string\HyField@AuxAddToCalculationOrder{#1}%
}%
\fi
\else
\write\@mainaux{%
\string\HyField@AuxAddToCalculationOrder{#1}%
}%
\fi
\fi
}%
}%
\patchcmd{\@Form}{/Fields[\HyField@afields]}{/CO[\HyField@calcorder]/Fields[\HyField@afields]}{}{}
\patchcmd{\eq@TextField}{\hbox{\pdfstartlink user{\common@TextFieldCode}%
\lower\eqcenterWidget\ef@Bbox{\eq@rectW}{\eq@rectH}\pdfendlink}}{\hbox{\pdfstartlink user{\common@TextFieldCode}%
\lower\eqcenterWidget\ef@Bbox{\eq@rectW}{\eq@rectH}\pdfendlink}\HyField@AddToFields}{}{}
\makeatother

\begin{document}
\begin{tabular}{@{\hspace{20pt}}rl}
Number 1: & \textField[\AA{%
\AAKeystroke{AFNumber_Keystroke(1,1,0,0,"",true)}
\AAFormat{AFNumber_Format(1,1,0,0,"",true)}}]{num.1}{1in}{11bp} \\[6pt]
%
Number 2: & \textField[\AA{%
\AAKeystroke{AFNumber_Keystroke(1,1,0,0,"",true)}
\AAFormat{AFNumber_Format(1,1,0,0,"",true)}}]{num.2}{1in}{11bp}\\[6pt]
%
Total:    & \textField[\AA{%
\AAKeystroke{AFNumber_Keystroke(1,1,0,0,"",true)}
\AAFormat{AFNumber_Format(1,1,0,0,"",true)}
\AACalculate{AFSimple_Calculate("SUM", new Array("num"))}
}]{totalNum}{1in}{11bp}
\end{tabular}
\end{document}


-
Works for the example! I'll have to check if it works in my more complicated case. But I hope its as simple as this. –  Matthew Leingang Oct 11 '12 at 16:53
Nuts. Doesn't work in my actual use case. –  Matthew Leingang Oct 11 '12 at 17:18
@MatthewLeingang I've updated my answer to add only the form fields to the calculation order that should actually be recalculated - maybe this can solve your problem? –  diabonas Oct 11 '12 at 17:22
it might be the eforms package that is undoing the work of your patch. So far it works with each of my trials that uses hyperref only, and none of the ones that use eforms. Thanks for working on this. I'll keep digging. –  Matthew Leingang Oct 12 '12 at 16:40
@MatthewLeingang eforms generates the forms field differently, so the patched commands weren't used for form fields generated with the eforms-specific macros. I've enhanced the patch in order to (hopefully) support eforms. –  diabonas Oct 12 '12 at 21:02