[Widgets] Any good examples for developing JS-enabled PDFs that calculate?
Hi everyone, My goal is to have a PDF that - allows users to input numeric information in various fields, - makes calculations on the data in those fields, - ...and reports that information somewhere in the PDF. It seems that the widget support could handle this, but I'm struggling to understand how the pieces go together; does anyone have an example of this use case I could puzzle over? Many thanks! -Paul
On 11/7/19 8:28 PM, Paul Mazaitis wrote:
Hi everyone,
My goal is to have a PDF that
- allows users to input numeric information in various fields, - makes calculations on the data in those fields, - ...and reports that information somewhere in the PDF.
It seems that the widget support could handle this, but I'm struggling to understand how the pieces go together; does anyone have an example of this use case I could puzzle over?
Hi Paul, I wonder whether tex/texmf-context/doc/context/examples/calculator/calculator.tex from the ConTeXt Suite might be what you look for. Just in case it helps, Pablo -- http://www.ousia.tk
Hi everyone, First: apologies for the long email; this got a little complicated. Summary: there may be a bug in setting up calculate field for widgets? Parts: - calculator.tex - A M(N)WE - The MWE Only Sort of Works # calculator.tex On 13 Nov 2019, at 10:26, Pablo Rodriguez wrote:
Hi Paul,
I wonder whether tex/texmf-context/doc/context/examples/calculator/calculator.tex from the ConTeXt Suite might be what you look for.
Just in case it helps,
It does (and is quite something!); it's not quite what I need, though. I'd like to take advantage of the internal _calculate_ event when a field updates - the calculator.tex PDF appears to be entirely programmatically event driven? (Which could certainly work for my application, but I want to try to keep this as simple for the user as possible.)
Pablo
# A M(N)WE Here's a Minimal Working Example, with some caveats: --- begin MWE --- \usemodule[fields] \starttext \setupinteraction [state=start] \startJScode{tallyUp} var a_fld = this.getField("A"); var b_fld = this.getField("B"); event.value = a_fld.value + b_fld.value; \stopJScode \setupfield[numField][reset,horizontal] [height=2pc,rulethickness=1pt,framecolor=lightgrey] \setupfield[totalField][reset,horizontal] [ height=2pc, rulethickness=1pt, framecolor=lightgrey, option=readonly, calculate=JS(tallyUp), ] \definefield[A][line][numField][] \definefield[B][line][numField][] \definefield[Total][line][totalField][] A: \field[A] B: \field[B] \blank[big] Total: \field[Total] \stoptext --- end MWE --- The idea here is that the resulting PDF will have three fields: A, B, and Total. Whenever a value is placed in A and/or B, on blur the value in Total will get updated automatically. # The MWE Only Sort of Works Things that are working: - I can put values in A and B - I can't directly manipulate Total (read-only seems to be working fine) Thing that doesn't work: - Total does not get automatically updated (for _any_ of the JS-enabled/tolerant PDF viewers I have.) Upon closer inspection of the resulting PDF with PDF Studio 2019 (I don't have Acrobat Pro at the moment), I can confirm some things: - The appropriate JavaScript is placed in the form, as a custom calculation script for the Total field. (This leads me to believe that the calculate= key in \setupfield is working.) - If I try to check the calculation order of the PDF, PDF Studio 2019 gives me the warning: "There are no fields with calculations." (So maybe there's a magic bit that needs to get flipped somewhere?) - If I use PDF Studio 2019 to change the calculate attribute on the field Total to something else, save, and then revert the calculate attribute _back_ to the custom script as supplied from the .tex file and save, the Total field starts working as expected, and I can see the field in the calculation ordering. If I can get the PDF to work in PDF Studio 2019, I can confirm that it also works in all of the other JS-enabled/tolerant PDF viewers I have. # Summary It looks like the appropriate JavaScript script is getting attached to the field for a calculate event, but is not being run? Or something? Anyway, that's as far as I've gotten. Any insight or assistance is appreciated; I'll see if I can make more progress. Thanks! -Paul
On 11/17/2019 9:13 PM, Paul Mazaitis wrote:
Hi everyone,
First: apologies for the long email; this got a little complicated.
Summary: there may be a bug in setting up calculate field for widgets?
it's more that javascript in pdf is kind of unreliable and can interfere in all kind of ways with settings in the viewer so, what you need to do it - play safe (only use actions that don't relate to something clever in the viewer, and calculat eis one of them) - be redundant (hook into several actions) - disable the spell checker - enable javascript - disable some security stuff - use the debugger (which can be erratic but at least you can see something; in my older acrobat doesn't seem to work with field related scripts) - put code in functions (easier to debug) and - cross your fingers Here's something to play with ... note the Number conversion! \usemodule[fields] \starttext \setupinteraction [state=start] \startJSpreamble {whatever} used now function recalculate() { var a_fld = this.getField("A"); var b_fld = this.getField("B"); var t_fld = this.getField("T"); var a_val = Number(a_fld.value); var b_val = Number(b_fld.value); var t_val = a_val + b_val; t_fld.value = String(t_val); console.clear ; console.println("A: "+a_val) ; console.println("B: "+b_val) ; console.println("T: "+t_val) ; console.println("?: "+t_fld.value) ; this.dirty = true; } \stopJSpreamble \setupfield [numField] [reset,horizontal] [height=2pc, rulethickness=1pt, afterkey=JS(recalculate{}), focusout=JS(recalculate{}), framecolor=lightgrey] \setupfield [totalField] [reset,horizontal] [height=2pc, rulethickness=1pt, option=readonly, framecolor=lightgrey] \definefield[A][line][numField] [0] \definefield[B][line][numField] [0] \definefield[T][line][totalField][0] A: \field[A]\par B: \field[B]\par T: \field[T]\par \stoptext ----------------------------------------------------------------- Hans Hagen | PRAGMA ADE Ridderstraat 27 | 8061 GH Hasselt | The Netherlands tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl -----------------------------------------------------------------
On 18 Nov 2019, at 3:48, Hans Hagen wrote:
Here's something to play with ... note the Number conversion!
A ha! Many thanks (for some reason I didn't get this email until just now); I'll try to tackle it this way and see what I can make work.
\usemodule[fields]
\starttext [...] \stoptext
-Paul
Hi, I didn’t check your example, but I remember that JScode did only work if there’s also a JSpreamble. Also the "used now" keyword (see Hans’ message) is essential. HTH. Sorry, no time for further investigation. Hraban
Am 2019-11-17 um 21:13 schrieb Paul Mazaitis
: Hi everyone,
First: apologies for the long email; this got a little complicated.
Summary: there may be a bug in setting up calculate field for widgets?
Parts:
- calculator.tex - A M(N)WE - The MWE Only Sort of Works
# calculator.tex
On 13 Nov 2019, at 10:26, Pablo Rodriguez wrote:
Hi Paul,
I wonder whether tex/texmf-context/doc/context/examples/calculator/calculator.tex from the ConTeXt Suite might be what you look for.
Just in case it helps,
It does (and is quite something!); it's not quite what I need, though. I'd like to take advantage of the internal _calculate_ event when a field updates - the calculator.tex PDF appears to be entirely programmatically event driven?
(Which could certainly work for my application, but I want to try to keep this as simple for the user as possible.)
Pablo
# A M(N)WE
Here's a Minimal Working Example, with some caveats:
--- begin MWE ---
\usemodule[fields]
\starttext
\setupinteraction [state=start]
\startJScode{tallyUp} var a_fld = this.getField("A"); var b_fld = this.getField("B"); event.value = a_fld.value + b_fld.value; \stopJScode
\setupfield[numField][reset,horizontal] [height=2pc,rulethickness=1pt,framecolor=lightgrey]
\setupfield[totalField][reset,horizontal] [ height=2pc, rulethickness=1pt, framecolor=lightgrey, option=readonly, calculate=JS(tallyUp), ]
\definefield[A][line][numField][] \definefield[B][line][numField][]
\definefield[Total][line][totalField][]
A: \field[A]
B: \field[B]
\blank[big]
Total: \field[Total]
\stoptext
--- end MWE ---
On 11/18/2019 4:15 PM, Henning Hraban Ramm wrote:
Hi, I didn’t check your example, but I remember that JScode did only work if there’s also a JSpreamble. Also the "used now" keyword (see Hans’ message) is essential.
i don't think so, the code is in the file and one can see that arobat sees it too but using a preamble and functions is more efficienty (reuse) and easier to trace the problem with calculate is that there are also settings related to it (plus some built-in addition stuff, at least that's what i see in the viewer preferences and such, which is likely to interfere) (and calculate doens't seem to be called at all)
HTH. Sorry, no time for further investigation.
Hraban
Am 2019-11-17 um 21:13 schrieb Paul Mazaitis
: Hi everyone,
First: apologies for the long email; this got a little complicated.
Summary: there may be a bug in setting up calculate field for widgets?
Parts:
- calculator.tex - A M(N)WE - The MWE Only Sort of Works
# calculator.tex
On 13 Nov 2019, at 10:26, Pablo Rodriguez wrote:
Hi Paul,
I wonder whether tex/texmf-context/doc/context/examples/calculator/calculator.tex from the ConTeXt Suite might be what you look for.
Just in case it helps,
It does (and is quite something!); it's not quite what I need, though. I'd like to take advantage of the internal _calculate_ event when a field updates - the calculator.tex PDF appears to be entirely programmatically event driven?
(Which could certainly work for my application, but I want to try to keep this as simple for the user as possible.)
Pablo
# A M(N)WE
Here's a Minimal Working Example, with some caveats:
--- begin MWE ---
\usemodule[fields]
\starttext
\setupinteraction [state=start]
\startJScode{tallyUp} var a_fld = this.getField("A"); var b_fld = this.getField("B"); event.value = a_fld.value + b_fld.value; \stopJScode
\setupfield[numField][reset,horizontal] [height=2pc,rulethickness=1pt,framecolor=lightgrey]
\setupfield[totalField][reset,horizontal] [ height=2pc, rulethickness=1pt, framecolor=lightgrey, option=readonly, calculate=JS(tallyUp), ]
\definefield[A][line][numField][] \definefield[B][line][numField][]
\definefield[Total][line][totalField][]
A: \field[A]
B: \field[B]
\blank[big]
Total: \field[Total]
\stoptext
--- end MWE ---
___________________________________________________________________________________ If your question is of interest to others as well, please add an entry to the Wiki!
maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context webpage : http://www.pragma-ade.nl / http://context.aanhet.net archive : https://bitbucket.org/phg/context-mirror/commits/ wiki : http://contextgarden.net ___________________________________________________________________________________
-- ----------------------------------------------------------------- Hans Hagen | PRAGMA ADE Ridderstraat 27 | 8061 GH Hasselt | The Netherlands tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl -----------------------------------------------------------------
Some further progress! On 18 Nov 2019, at 13:56, Hans Hagen wrote:
the problem with calculate is that there are also settings related to it (plus some built-in addition stuff, at least that's what i see in the viewer preferences and such, which is likely to interfere)
From what I've been able to gather, there are three ways to get JavaScript into a PDF using Acrobat (or other software that uses the Acrobat way of doing things): - Predefined Calculations (use a UI to build a simple recipe) - Calculations built with Simplified Field Notation (operators and field names - I don't understand this one too well) - Custom Calculation Script (Acrobat JavaScript) I _think_ these are relatively exclusive: I don't believe there's anything about the first two systems that interferes with the third (and I'm not sure how the UI would work for the first two in an LMTX context, anyway?).
(and calculate doens't seem to be called at all)
After digging around in the spec and comparing output, it looks like adding the CO (Calculation Order, PDF Spec 12.7.2) key and an array: /CO [15 0 R] ...to the AcroForm object is enough for the indicated field(s) to react to the internal calculation event. The way I tested this is I inserted the above stanza (with the appropriate object ID) into the uncompressed LMTX PDF, and that was all it took for the calculate JS to start working for the total field. (I likely wrecked the xref table in the process, but the PDF was still functional...) I then built a form with a chained calculation (a second field that doubled the total field) and ended up with a CO entry like this: /CO [13 0 R 19 0 R] ...and I believe that the order of the objects in this array is how the calculation precedence is determined. So! This is bigger than just adding the CO array to enable calculations; there needs to be enough of an interface to also indicate calculation order somehow in the .tex file. I'd love to have this as a feature, but I will cheerfully defer if this has become ridiculous... -Paul
participants (4)
-
Hans Hagen
-
Henning Hraban Ramm
-
Pablo Rodriguez
-
Paul Mazaitis