Posts in Category "Debugging"

Tracing Function Arguments

Given that we don’t have a script debugger, I make extensive use of the Acrobat console object to dump script context information.  I’ve discovered that getting the right information out is a bit of an art form.  When you add a call to console.println() you want to make sure you include enough information so that you know the context of the output.  Your output needs to handle conditions such as empty strings, null values, variable numbers of parameters…  But who wants to spend time coding a really clever call to console.println() when you know full well that you’re just going to delete it five minutes later?

Given my lazy nature I went searching for an easier way.  The place where I most often add calls to console.println() is at the beginning of a function call.  For example, here’s how I might debug a method to convert a measurement to inches:

/**
* Convert a measurement to inches.
* @param measurement – a measurement property
*                 e.g. "49.3mm".  Input units can be mm, cm, pt, in
* @param digitsPecision – (optional) how many digits to preserve
*                          after the decimal place. Default is 3.
* @return the corresponding number of inches.
*/
function getInches(measurement, digitsPrecision)
{
  console.println("getInches: " + measurement + " " +
     
  ((digitsPrecision) ?  digitsPrecision : "undefined"));
  …
}

That console.println() method call didn’t exactly roll off the fingertips.  And no, I didn’t get it right first try. In my test form, the output dumped to the console was:

getInches: 9.525mm 4
getInches: 60.325mm undefined

Then I started looking at what I might be able to get for free by extracting information from the "arguments" object.  (If you’re not familiar with the arguments object, read chapter 8.2 of O’Reilly JavaScript The Definitive Guide.)

I wrote a utility function that dumps the contents of the arguments object.  My debug statement now looks like:

function getInches(measurement, digitsPrecision)

  dbg.trace(arguments);
  …
}

Far easier to code.  The output produced by the dbg.trace() call:

function getInches() :
  measurement: [9.525mm] (string)
  digitsPrecision: [4] (number)

function getInches() :
  measurement: [60.325mm] (string)
  digitsPrecision: undefined

You can look in the sample form to see the details on how the script extracts all this information.  The tricky part was extracting the function name and parameter names.  The script uses arguments.callee.toString() to get a string representation of the function syntax and then uses a regular expression to extract the function name and parameter names.

Other features of the dbg.trace() method:

  • handles variable numbers of parameters
  • If a parameter is an object, it will attempt to extract the className, name and rawValue properties (if defined).
  • If the form is running on the server, the trace output is dumped to the log object instead of the console.
  • There are a couple of global variables in the dbg script object to control whether trace output is enabled and to control the maximum number characters of data to dump for parameter values.

Have a look.  I’m sure you’ll find ways to customize the trace to suit your specific needs.

August 14 Update

As explained here, the trace function has been updated to handle parameters.  It is now also available as a downloadable fragment.

Debug merge and layout

It has been quiet for a while. That is because I took on a more ambitious task over the last couple weeks.  The result is a new XFA/PDF debugger tool.

In the past I’ve posted samples (tools) that help users debug their merge (form dom) and view their form layout. The new tool consolidates and extends those capabilities and implements the debugger in flash — a SWF embedded in a PDF. 

This tool will be useful to anyone having problems designing dynamic forms:

  • Subforms aren’t being created from data where you expected they would
  • Layout has a mysterious blank page
  • Garbled or overlapping layout
  • Layout did not appear in the order you expected
  • leaders and trailers aren’t being created
  • leaders and trailers are created too often
  • Content seems to be missing

If you’re encountering any of these symptoms then this tool could help.

Usage

You need to be running Acrobat (not Reader) to use the tool.  And you need to be using version 9. 

To start a debug session, populate your PDF form with data and save it.  Then open the PDF from the XFADebugger.pdf tool.  You will see a snapshot of the form represented in three vertical boxes:

  • Form DOM tree
  • Data DOM tree
  • Layout — page display (with content areas rendered as grey boxes)

From there on it is hopefully self-explanatory.  You can expand/collapse the trees.  Nodes in the trees are colour coded:

  • grey — node is not bound
  • black — node is bound once
  • blue — data node is bound to more than one form node
  • green — represents a subform leader/trailer that has been added by the layout process

Selecting a node in the form tree will:

  • if bound, highlight the corresponding node in the data tree
  • if not hidden, highlight the area on the page display where that node is rendered.
  • Display any interesting attributes/properties that impact merge and layout

Selecting a node in the data tree will (if bound)

  • select all the form node(s) that are bound to this data
  • display the attributes and highlight the corresponding form node(s)

Warnings

The tool reports on suspicious conditions on the form that could impact merge or layout.  Clicking on the "Find Warnings" button will cycle through any warnings found in the form.  For each warning, the corresponding nodes are highlighted and the the warning text appears in red.

These are the warning conditions detected:

Object extends outside its parent container
Just what it says.  When the offending form node is highlighted on the page layout in dark blue, it’s parent node is highlighted in pale blue.

leader/trailer subforms must not be flowed
Leader and trailer subforms must always have positioned content.  As you might imagine having a variable-sized leader/trailer would make it pretty difficult for the layout algorithm to reserve space for the leader/trailer subform.

Subform is splittable but cannot split because the parent is not splittable
Designer also warns about this condition.

Object is growable, but not-splittable.  With enough data, it could grow too large for its content area
If an object can grow vertically without any upper limit, it could eventually grow too big to be rendered inside a content area.

Object is growable but its parent is not.  With enough data, it could grow too large for its parent
If you place a growable object inside a subform with a fixed layout size, you could end up with an object that’s too big for its container.

Keep with previous’ conflicts with ‘break after’ on previous element
Conflicting break/keep directives. (By the way, the keep will trump the break — but this is condition is a leading cause of mysterious blank pages in your output)

‘Break before’ conflicts with ‘keep with next’ on previous element
Same as previous except the other way around.

Repeating subforms should not specify keep with next or keep with previous
Having a keep on a repeating subform will result in the entire group of subforms being un-splittable.

Subforms with repeating children should be splittable
If a subform has a repeating child, it is likely to require a split.

Multiple repeating form nodes are bound to the same data. This might cause a different merge result when the form is re-opened
This takes more explanation.  Consider this template definition:

<subform name="S0"><occur min=1 max=10/><bind ref="S[*]"/></subform>
<subform name="S1"><occur min=1 max=1/><bind match=once/></subform>

When this form is first opened without any data, we will create two instances of <S> in the data — one for S0 and one for S1. Then when we save/close/reopen, subform S0 will bind to both instances of <S> and subform S1 will create a new instance of <S>. i.e. after save/close/reopen there is one more subform than there was before.  This is a form design issue that crops up occasionally and can be very confusing for novice form authors.

Rows with more than one multi-line field might have difficulty splitting

If you have a splittable table row with more than one multi-line field, you might find that it does not split.  The algorithm for splitting rows requires finding a common font baseline between rows on the sibling cells.  For current shipping product, the check for the baseline is very exact.  If there is any difference between the fields that can cause the lines to be offset slightly, then the split algorithm will not find a split point.  Some of the attributes that affect the position of the baselines include: top margin, paragraph space before/space after, line spacing, vertical justification, typeface, font size, vertical scale… and probably a couple more I haven’t thought of.

 

As is the nature of warnings, not all warnings are problems that need to be fixed.  Your form might report warnings that are innocuous. 

Here is a sample of a very badly designed form that manages to have (at least) one instance of each warning.

How the Tool Works

The sample has two parts.  There is a base PDF with a document-level JavaScript defining:
function PDFLoader() that will:

  • Select and open an XFA-based PDF
  • Extract an XML snapshot representing the state of the form after it has opened

The form has a page-sized embedded SWF which holds the implementation of the debugger.  The SWF has a button that calls the document-level JavaScript using a call to ExternalInterface.call("PDFLoader").

Once the SWF has the XML snapshot of the form, it renders it and doesn’t communicate with the base PDF anymore.

Other Uses

Educational

Loading up a form and
seeing the form/data/layout graphically displayed can help to get insight on how the merge and layout processes work.

Quality Assurance

There are two ways that this tool can be used or adapted to maintain quality in your forms. 

1) loading and viewing your dynamic form in the debugger lets you verify that merge and layout are happening as designed.  Just because your form looks ok on screen doesn’t necessarily mean that your data merged correctly or that your layout is behaving as planned.  You might be surprised by what you see.  You should make it a habit to check for warnings.

2) Adapt the XML snapshot to produce ‘gold data’ for your form.  When you are satisfied that your form is working correctly, produce a snapshot of the form that you can save as a baseline.  Then if your form gets modified — perhaps some cosmetic changes — you can compare the new snapshot to the baseline and confirm that any changes are as expected.

Futures

There are undoubtedly more form design problems that could be flagged by this tool. If you have suggestions for other conditions to detect, please let me know.

The form DOM could include more objects — instance managers and draw elements.  For now I’ve left them out because they clutter the form tree too much.

Updates

June 1, 2009

  • Fixed bug where field splittable status was reported incorrectly
  • Increased the tolerance when checking for objects outside their extent
  • Added a new warning: "Rows with more than one multi-line field might have difficulty splitting"

Document Your Form Template

Many of us are creating forms with lots of script and complex logic.  The good side of this is that we are able to generate some pretty cool form fill experiences.  But how maintainable are the forms we create?  If another form developer inherited my form and was asked to make a few changes, would they be able to?  Or would they end up staring at a mass of objects and scripts in Designer and give up?  Unless your objective is to create built-in job security it would seem like a good idea to make your forms as maintainable as possible.  Toward this end, I have two suggestions: a) build good frameworks and b) (the topic of this post) provide great documentation.

Create Frameworks

If you are developing a series of forms and have logic that is re-usable, encapsulate that code in script objects.  Turn these script objects into fragments and reference them from your forms.  There are hopefully two outcomes from this exercise:

  • The framework itself can be heavily documented to facilitate easy usage and also proper maintenance
  • The amount of script logic that lives outside the framework will be minimized

If these are true, then editing forms becomes reasonable because the average form author does not need to know the internals of the framework — they just need to know how to use the framework.  They can modify forms with confidence because there isn’t much script and the script is easy to understand.

Document your Script

This area is harder.  The problem with documenting script is that it is fragmented throughout your form.  An individual script may be well documented, but where does it fit in the overall context?  When you open an unfamiliar form, there’s bound to be lots of routine, innocuous script, but then there are likely a small number of scripts that are key to how the form operates.  There is no easy way to get the big picture of how logic flows in your form.

My project for the last few days has been trying to figure out how we could make use of JavaDoc comments to build a documentation map for a form.   There are two sides to this problem. One is figuring out conventions for adding the comments.  The other aspect is figuring out how to harvest them and generate documentation. 

Not surprisingly, my first crack at a harvesting tool is… a form.  This sample form will load an XFA/PDF and generate a report from the script it finds inside (Be patient — loading a large form takes a long time).  Here is a sample report generated from the survey form I created for a previous blog entry.  (and here is the survey form with updated/improved internal documentation).  Going through the exercise of documenting a form, harvesting the documentation and generating a report forced me to deal with some issues that are unique to this environment.

Commenting on scripts vs. commenting on objects

Normally JavaDoc comments are used to describe classes, interfaces, functions and variables.  This makes sense for our script objects.  e.g. this  script fragment should work nicely with a harvesting tool:

/**
* function handleError(err) — return an error message and if
* in Acrobat, raise the console window with the error
* @param err – the error object thrown by the script engine
* @return – a human readable message extracted from the error object
* @author John Brinkman
http://blogs.adobe.com/formfeed/
*/

function handleError(err)
{

}

For this case I was able to fairly easily extract the comment and the function definition.  Just scan past the end of the comment up to the first "{" or ";" characters. (now you understand my fascination with complex regular expressions).  A good harvester tool could extract the function declaration even without the structured comment — just locate the function(){} syntax.

But how do we document a calculation? or a click event?  There’s no function/object that is the target for the documentation fragment.  There are also no parameters or return values to describe.  In this case, I chose to support a single JavaDoc comment for the script, and for the syntax portion emit the first 5 lines of script that follow the comment.  Instead of supporting @param, I added a custom tag called @reference where the script author can describe dependencies for a particular script. e.g.

Survey.DefineSurvey.Sections::initialize – (JavaScript, client)
/**
* Sections is the container subform that holds a series of survey
* section definitions. The initialization script makes this subform
* initially hidden.  It will be made visible as the user reaches
* this stage of survey definition.
* @reference _Section.count — If there are already section
* definitions, make this subform visible.
*/
this.presence = _Section.count == 0 ? "hidden" : "visible";

Harvesting Information outside the script

In the case of documenting forms, there is lots of information outside the actual JavaDoc that is relevant to the report. In our case, information about the context of the script is very important.   What form object is hosting the script? What event? Is it FormCalc?  All these pieces and more need to be pulled into the report.

Order of Report

When generating the report, I had to choose between two ways to order the report:

  1. Order the report by object (in document order).  E.g. list all the scripts for the first object encountered and then search for the next object with script.
  2. Order the report according to the (approximate) order in which script will execute.  Then a field’s initialize event will appear early in the report and its layout:ready event will appear much later in the report.

I chose to go with option 2.  My guess is that this order will be best for trying to decipher form logic.

Forms with no structured comments

You’re not likely to uncover many forms that have structured comments in them.  Yet we still ought to be able to generate a decent report.  We  harvest all the script context information and the report will contain the first 5 lines of each script.  For each script summary you can click on the "+" button to see the entire script.

Noise

There are many scripts that you do not want included in your report.  e.g. if your form has enter/exit scripts on every field, and the scripts are the same each time, we do not need to report on each and every script.  It just clutters the report.  I added an @ignore directive that allows the form author to exclude these scripts.

FormCalc

Unfortunately, structured comments are not legal syntax in FormCalc. For FC, the harvester looks for blocks of 2 or more lines that start with "///".  E.g.

Survey.DefineSurvey.Sections.Section.Questions.Question.QuestionNumber::calculate – (FormCalc, client)

///
/// Assign Question number based on subform index
///
Question.index+1

JavaDoc Completeness

The harvester supports only a fraction of the JavaDoc directives: @param, @return, @reference, @ignore, @author.  In the descriptive text you can use <br> and <p> elements to force line/paragraph breaks.

Resources

If you are new to the idea of JavaDocs, check out the JavaDoc tool home page.  I noticed that there is also a Google project to support JavaDocs for JavaScript here.

Futures

Unfortunately, documenting script is not really enough to make complete sense of the way a form works.  There are many other aspects that you might want to describe.  Maybe there is a clever data binding strategy.  Maybe you’d want to describe various inputs — the use of certain datasets.   Maybe there is complex binding that modifies form behaviour.  Maybe the form makes use of WSDL definitions.  To begin to describe all these things we need to be able to place comments in more places in the template.  One obvious place would be under the <desc> element of both <field> and <subform>.  But then we need a way in Designer for adding those comments.

Feedback

I’d be interested in hearing from people whether template documentation is a problem that interests them.  Is there more you’d like to do?  Ideas to build on what I’ve described here?  Let me know please.

Template Transformation

Today I am disclosing a trick that will allow you to apply a transformation to your template.  But first a disclaimer: this technique is not a product feature.  It is just a trick that takes advantage of some side effect behaviours.  Ok, ok, it’s a hack.  But it’s potentially a very useful hack.

Motivation

Have you ever wanted to do apply a global change to your template?  Change the fonts of your fields.  Set a colour scheme.  Add a script to all your fields.  You know by now that it can be very tedious to do these things. 

Transformation Techniques

What options do you have today?  For very simple changes, some people will go to their XML Source tab and do a global search/replace.  That’s a bit scary.  I do it when I rename anything that is referenced in script.  But it’s hard to use when you want to be selective in your changes — e.g. apply a font change to all numeric fields.  There is also XSLT.  We have some very technical customers who will save their form as an XDP and apply an XSLT script to make global changes.  These customers have my very humble respect.  XSLT is a very powerful tool, but a very difficult technology to master.

Script

There are a couple of ways I’d like to transform a template.  One choice would be some form of style sheet definition.  My other choice (today’s topic) would be to write JavaScript that updates the template.  We write tons of script that modifies the form DOM at runtime.  Wouldn’t it be great if we could write script that modified the template at design time?  Well, turns out you can.  But as I think I may have mentioned — it’s a bit of a hack.

I’ll explain how it works, but first some background to help you understand the technique.

PDF Generation Process

When you edit a dynamic template and save as a PDF, Designer gives you the illusion that PDF is the native format for the template.  In reality, the native format is XDP.  When Designer opens a dynamic PDF, it extracts the XDP stream stored inside and discards the PDF container.  Then when you save, Designer re-generates the PDF from the XDP.  That would explain the phrasing of the messages you see in the log tab of Designer when you save:

Generating PDF Document…
PDF generated successfully.

0 warnings/errors reported.

The PDF generation process that Designer goes through during save is almost exactly the same process LiveCycle Forms goes through when it generates a PDF from an XDP on the server.  Among the steps during PDF generation:

  1. Embed all required fonts
  2. Embed referenced images
  3. Generate XMP metadata
  4. Run server-side scripts

Hopefully #4 caught your attention.  When Designer saves a dynamic PDF, one of the things it does is execute script. 

Scripting the Template

When any script runs in an XFA form, the default context is the Form DOM.  The Form DOM is a transient DOM that gets created when you open the form and goes away when you close the form.  You can script against the Form DOM as much as you like.  However, in Reader you cannot modify the template DOM.  The template DOM is the source code.  It is what gets saved back in the XDP stream in the <template> element.   For security reasons, we don’t allow forms in Reader to modify their template.  But, this is a Reader-only restriction.  Forms running in the context of the server can modify their template.  This means that script run by Designer when it saves your dynamic PDF has full write-access to the template and any changes the script makes will be preserved in the generated PDF.

Setting up a save-time script

Take a simple example.  This script will update the author information metadata in my template (note that the script is set to run at server):

form1.#subform[0].updateMeta::initialize – (JavaScript, server)
updateMetaData("creator", "John Brinkman");
updateMetaData("contact", "
http://blogs.adobe.com/formfeed/");
updateMetaData("usage",   "No rights reserved");

function updateMetaData(vName, vValue)
{
    var vDesc = xfa.template.["#subform"].desc;
    if (vDesc.nodes.namedItem(vName) == null)
    {
        vDesc.nodes.append(xfa.template.createNode("text", vName));
        vDesc[vName].value = vValue;
    }
}

Now when I save the form and go look at the file/Form Properties/Info I’ll see… no change.  Oops.  The problem is that once Designer saves, it doesn’t re-open the PDF it saved.  It continues operating on the XDP it has in memory.  To see the change you need to save *and* close.  Then when you re-open and look at your file properties you will see the author and contact information updated. (You won’t see the "usage" element in this screen, but it does get embedded in the PDF metadata).

Debugging

For those of you who get their JavaScript right the first time, read no further.  Those like me who need to liberally sprinkle their code with console.println() messages will discover that the console API doesn’t work.  That’s because console is an Acrobat-only object. You can’t code against it on the server.  Instead, you will want to familiarize yourself with the xfa.log object.  To dump a message to the log file, you can code:

xfa.log.message(0, "your message here");

This message will show up in the log tab of designer.  A couple things you’ll want to know about using this command effectively:

  • The log file suppresses messages that have the same text as the previous message
  • For a message to appear with proper line breaks in the log tab, you need to insert carriage return/line feed combinations in your string.  i.e. instead of "line1\nline2" you need to code: "line1\r\nline2".
  • Before saving you should clear the log.

Cleanup

Once your transformation script has run, you don’t need it anymore, and it would be bad form to leave it around.  Add a couple lines to your script so that after it has done its work it will remove itself.

With a log message and cleanup, the sample above becomes:

updateMetaData("creator", "John Brinkman");
updateMetaData("contact", "
http://blogs.adobe.com/formfeed/");
updateMetaData("usage",   "No rights reserved");

// Insert a message in the Designer log tab
xfa.log.message(0, "updated form metadata");

// remove this script once it has run on-save
var vNode = xfa.template.resolveNode("$.." + this.name);
vNode.parent.nodes.remove(vNode);

function updateMetaData(vName, vValue)
{
    var vDesc = xfa.template.["#subform"].desc;
    if (vDesc.nodes.namedItem(vName) == null)
    {
        vDesc.nodes.append(xfa.template.createNode("text", vName));
        vDesc[vName].value = vValue;
    }
}

Of course, you’ll probably want to leave the cleanup code commented out until you have fully debugged your script :-).  It would be a good idea to make sure your imported subform has a visual appearance so that you won’t forget to deal with it.

Once it is working, the updateMeta subform can be added to your fragment library.  When you want to update your metadata, you follow these steps:

  • import the updateMeta subform fragment
  • save
  • close
  • re-open

And if that’s less effort than re-typing the metadata, then you’re in a happy space.

I have attached a sample that does a couple of interesting things:

  • Update all the field widget borders to be .01in thick, solid and blue.
  • Add enter and exit scripts to each field to highlight the border while the field is active.

To use the sample:

  • Open the form in Designer
  • Modify the first line of the script and change it from if (false) to if (true)
  • Save
  • Close
  • Open

When re-opened you’ll see that the subform hosting the update script is gone.  The borders are now solid blue and when you preview and tab through the fields you’ll see that the border changes colour when the field is active.  You’ll also notice that in the sample I use a slightly updated version of the scMessage scripts to display the server message — fixing the carriage return/line feed issue.

Futures

I have been saying that this technique applies to Dynamic XFA-based PDFs.  In fact it works with static as well.  But it does not work for artwork PDFs.  It also does not work when you save as .XDP.  For those environments there is no solution yet.

The technique described here is admittedly awkward, but it does point toward some exciting possible enhancement areas for Designer.  Notably style sheets and Design-time macros.  Nobody is making any commitments, but these are areas of interest to us as we move forward.

JavaScript Regular Expression Tester

I have been working on a couple samples recently where I have become obsessed with the power of regular expressions.  There are plenty of areas in forms development where regular expressions can come in handy.  Maybe you want to validate that the user entered a syntactically-correct email address.  Maybe you want to change "LastName, FirstName" into "FirstName LastName".  The more I look at regular expressions, the more uses I find for them.  However, there are a couple of problems with my obsession (besides the danger that I’m on a path to OCD):

  1. Regular expressions easily become complex.  You start out doing a simple search/replace and it seems seductively easy.  A basic regular expression used in String.replace() means you can do in one line of code what would have otherwise required 20 lines of fragile script.  Then next thing you know you you’re processing HTML blocks.  You’re struggling to capture a repeating group — it *almost* works — "just another five minutes and I’ll get it"…
  2. Good news: There is plenty of online documentation and plenty of online tools to test regular expressions and feed your habit.  There are also plenty of forums populated with questions from regular expression addicts.  Bad News: There is a frustrating lack of uniformity in the regular expression functionality in various development environments — whether it’s Perl, JavaScript, Java, grep, Python, Flex …

Eventually my frustration/obsession grew to the point where I built my own RegEx testing form.  That way I could be certain that the expressions I tested would work with the version of JavaScript found in the version of Reader I was targeting.

The form tests regular expressions in two contexts: RegExp.exec() and String.replace().

I won’t try to explain the usefulness of both these methods, since any modest JavaScript reference would do a much better job.  The test form has an input fields where you enter the source string, regular expression and (optional) replacement string.  There are check boxes to control the RegExp attributes.  When you click the "find" button, the expression is evaluated (RexExp.exec()) and the results are dumped into a series of repeating subforms.  If you choose the replace option, the script uses the regular expression with String.replace().

Enjoy.  But proceed with caution.  I’m not responsible for any social disorders you develop along the way.  However, I might be forming a support group…

Debug Your Form Layout

Today I want to share with you a work-in-progress of a tool that you can use to debug your form layout.  The sample builds on some concepts from previous blog entries:

  • The form dom debugger that used script access to graphically display the form and data doms
  • The reporter form that loaded/opened a PDF and generated a summary of the contents.
  • The form demonstrating how to calculate layout positions

The motivation for the debugger form is simply that once you step outside the simple layout scenarios, form layout can be a complex area to debug.

The layout debugger form loads and opens an XFA/PDF and will graphically display the form dom and the page layout.  To get a feel for how it works, save this sample form to disk and then open it from the layout debugger form.  Some notes to guide you:

  • Before you opened the form there was a checkbox: "show boilerplate".  This allows you to include/exclude the static text/images/lines/rectangles etc. that occur on your form.  Often these have no impact on layout problems and there is less noise if we do not include them.
  • The left hand side of the page displays the form dom in much the same way that the form dom debugger did.  As before, you can expand/collapse the hierarchy and use the arrow buttons to scroll up or down half a page at a time.
  • The right hand side of the form shows a graphical display of the pages.  Each page is numbered and scaled proportionately.  Each page has its content area(s) drawn in a dashed line.
  • When you mouse into a field in the hierarchy, the pages are highlighted with the extent(s) of the corresponding object.  If the object has split across multiple content areas, it will display as multiple rectangular areas.  You’ll note that when you select the root of the form dom that it spans all pages.
  • There are a set of XFA properties that impact layout.  Things like: presence, layout, break, keep, overflow, etc. Each object in the form dom hierarchy displays the names of any layout properties that do not correspond to their default values.  When you mouse into the hierarchy field, the expanded property values are displayed in the top right corner of the page.
  • The hierarchy is colour coded.  Grey entries are not-splittable.  Green entries are splittable, yellow entries are overflow leader/trailer subforms that were added  by the layout process.  If you scroll to the bottom of the form hierarchy you will see a couple of "hdr" subforms that layout added.  Note that near the top of the hierarchy the first occurrence  of "hdr" appears because of its place in the form dom — not because layout added it.
  • While you are scrolled to the bottom, click on the "Date" field under page 1.  You will see it appear with a yellow warning icon.  This is because it was positioned off the page.  Adding warnings is an area where I need to do much more work.  It should be possible to detect more conditions that frequently cause layout problems.
  • When you click on a hierarchy object that is hidden, nothing in the page display gets highlighted.  That is because hidden objects are excluded from layout.

As I said, this is a work in progress.  But I felt it was far enough along to share.  I have more plans for it.  If you have specific ideas of how to improve it, please let me know.

June Update

There is a follow-up debugger effort that supercedes the sample in this entry. Please have a look here.

Tool for Summarizing Form Content

I am often asked to take a look at forms that arrive from a variety of sources — customers, quality assurance, sales engineers etc.  Often one of the first things I do is have a look at some summary information about the template.   Having a unix background, I often save the form as an XDP and poke around with some grep commands e.g.: grep "<field" form.xdp | wc -l to find out how many fields are in the form.  But certain types of information are a little difficult to coax out with unix shell commands, so I set out to do something more user friendly.

Since the template definition, is completely accessible to JavaScript, I decided to design a form that would summarize the contents of another form. The result is today’s sample.  The form uses the Acrobat APIs to load and launch a file.  Once launched, we simply iterate over the contents of the template and generate a report from what we find.  The report consists of:

  • meta data about the form: File Name, Creator, Template Version, Compatible Version, Strict Scoping setting, Static/Dynamic setting
  • Enumerate the referenced fonts (including references found inside rich text fragments)
  • List all linked and embedded images (for embedded images, indicate their base64-encoded size)
  • Count instances of plain text vs. rich text
  • Enumerate scripts, indicating which language (FormCalc or JavaScript) along with what context (event) and how many lines long
  • Binding properties — summarize what kinds of data binding are in use
  • Picture Formats – enumerate all the picture formats found in the form
  • All other properties.  For example, if you want to see how many captions are on the form, note how many times the <caption> element appears.

To use the form, you need to be running Acrobat (not Reader).  Simply press the button, select a form and wait for the report.  Note that for large forms, this can take a few seconds (sometimes more than a few :-).  I’ve attached another sample that has enough of each kind of content to generate an interesting report.  Save this form to disk and select it from the reporter form.  You’ll see each category of the report populated with data.

I have also attached a report generated from a customer form with which I have enjoyed some quality time.

The script in this form is pretty complex.  But if you’re a good JavaScript programmer you could probably extend the script to capture other information that you find interesting.

Handling JavaScript Exceptions

I have previously apologized for not being the most sophisticated JavaScript programmer on the block.  But one of the advantages of learning while I blog is that occasionally I discover things that a smart JavaScript programmer would already know, but is interesting to people who are climbing the same learning curve as me.

Today I learned more about JavaScript exceptions.  Or more specifically, the JavaScript exceptions thrown by script errors in XFA.

I’ve written lots of code that handles exceptions this way:

try
{
    xfa.template.foo = "bar";
} catch (err)
{
    app.alert(err.toString());
}

As it turns out, this is not a very satisfying way to report exceptions.  The error object that gets thrown by the script engine does not provide helpful information from the toString() method.  Typically it returns something like: "GeneralError: Operation failed.".  Thanks a lot.

Then it dawned on me that just maybe there was useful information locked up inside the exception object that the toString() method does not report.  I wrote some code (ok, I shamelessly copied some code from O’Reilly’s: JavaScript the Definitive Guide) to examine the contents of the object in my catch block.

I dumped the results out to a field on the form:

try
{
    doInit();
} catch(err)
{
    var vDebug = "";
    for (var prop in err)
    { 
       vDebug += "property: "+ prop+ " value: ["+ err[prop]+ "]\n";
    }
    vDebug += "toString(): " + " value: [" + err.toString() + "]";
    status.rawValue = vDebug;
}

function doInit()
{
    foo.ForceError();
}

The results of this dump show up as:

property: name value: [GeneralError]
property: message value: [Operation failed.]
property: fileName value: [XFA:form1[0]:page1[0]:Subform1[0]:initialize]
property: lineNumber value: [7]
property: extMessage value: [GeneralError: Operation failed.
XFAObject.bar:7:XFA:form1[0]:page1[0]:Subform1[0]:initialize
Invalid property set operation; template doesn’t have property ‘bar’

]
property: number value: [14]
property: stack value: [Error()@:0
nestedFunction()@2:7
ForceError()@2:3
ForceError()@:0
doInit()@XFA:form1[0]:page1[0]:Subform1[0]:initialize:17
@XFA:form1[0]:page1[0]:Subform1[0]:initialize:3
]
toString():  value: [GeneralError: Operation failed.]

Turns out there’s lots of great information available.  The exception we catch comes populated with properties: name, message, filename, lineNumber, extMessage, number and stack.  The toString() method on this object ignores the most useful information and simply concatenates the name and message properties.  The extMessage property is what normally gets dumped to the JavaScript console.

With this knowledge, I can write an exception object formatter that turns the exception message into something both useful and human readable:

Invalid property set operation; template doesn’t have property ‘bar’
Stack:
line: 7 of nestedFunction()
line: 3 of ForceError()
line: 10 of doInit() in the initialize event of: page1.Subform2
line: 3 in the initialize event of: page1.Subform2

The code that produces that output can be found in the attached sample.

Server Side

You might not be aware that our JavaScript processor on the server is different from the one embedded in Acrobat/Reader.  Fortunately, in spite of being different processors, the compatibility between the two is very good.  However the exception object that gets thrown on the server has a different set of properties from the exception object thrown on the client.  The function I wrote to format an exception has conditional code that produces a different result for the server, based on the properties available there:

Invalid property set operation; template doesn’t have property ‘bar’
at line: 8 of script:
1:
2: function ForceError()
3: {
4:     nestedFunction();
5: }
6: function nestedFunction()
7: {
8:     xfa.template.bar = "bar";
9: }
10:
11: this.ForceError = ForceError; this.nestedFunction = nestedFunction;

Why Bother?

If you’ve been debugging JavaScript for some time, then you might wonder why I went to all this trouble, since most of the useful information from a JavaScript error is dumped to the console anyway.  Three reasons:

  1. Some form authors make a practise of wrapping all their JavaScript code in try/catch blocks.
  2. The stack trace information is not part of the information dumped in the JavaScript console
  3. I found a bug where under certain conditions, JavaScript exceptions are *not* reported in the console.

The bug happens when an initialization script creates an instance of a subform.  If that new subform also has an initialization script, its errors go unreported in the console.  This condition (a nested initialization) is probably a bit unlikely for most forms, but has happened to me at least a couple of times.  My workaround is to wrap the initialization script in a try block and dump exception information to the console in the catch block.  And now that I have better tools for dumping exceptions I’m a happier form developer.

The Deep End

Server Side Debugging

When writing code for forms destined for the server, it is important to be able to dump information from your scripts so you can debug them.  In Reader/Acrobat using console.println() is invaluable.  But the console object is specific to Acrobat.  We need something for the server as well.  I use xfa.log.message().

A script to dump an error message then looks like:


catch (err)
{
    var vMsg = scMessage.prettyMessage(err) ;

    // client code
    if (xfa.host.name == "Acrobat")
        console.println(vMsg);

    // LiveCycle server
    if (xfa.host.name == "XFAPresentationAgent")
 &#16
0;      xfa.log.message(0, vMsg);

}

Modified Script

You might have noticed up above that the dump of the exception for the server had a line of code that did not appear in the form:

this.ForceError = ForceError; this.nestedFunction = nestedFunction;

This line gets added to the script by the XFA processor so that for a named script object we can support the syntax: foo.ForceError() and foo.nestedFunction().

Other Kinds of Exceptions

If you write JavaScript code that throws an exception, then the exception object will be whatever you throw.  For example you could do this:

throw "Bad date format";

In this case, the object caught in a catch block will be a string — not the exception object that XFA scripts throw.

March 19 Update

After using the sample code for a few days, I added a couple of improvements to the sample:

It turns out that the contents of the exception in Reader varies depending on the nature of the exception.  The code I wrote handled exceptions thrown by the XFA engine.  Regular JavaScript language exceptions did not populate an "extMessage" member of the exception class.  I updated the pretty printing of the exception accordingly, and added an example of this kind of exception to the form.

Since most of the time we want to display exceptions in the console or server log file, I added a handleError() method that does just that.  In addition, to logging to the console, it calls console.show() in order to make sure the form author sees the exception when they’re debugging.

August 14 Update

Improved the handling of message emitted in Designer.  Added support for thrown string objects.  These changes are explained here.  Download this fragment for the latest version of this script.

Form DOM Debugging Tool

One area where a novice form designer often needs help is in figuring out how to bind their form to data.  Ok, scratch that.  Advanced form designers often need help in this area as well.  There is lots of reading you can do in the XFA specification to learn how the template DOM gets merged with the data DOM to produce the form DOM.  Designer does a great job of generating binding SOM expressions for you.  But even still, when you are dealing with a complex schema, it can be hard to figure out where things went wrong.

A good way to debug this problem is to visualize the resulting DOMs.  Since we have full scripting access to the form DOM and to the data DOM, we can add a visual display of the DOMs to our form.  That’s the approach that today’s sample takes.  I took a work-in-progress purchase order form and added a "debugging subform" (domDump) at the end of the form in order to display the DOMs.  When you open the form and look at the last page you will see two side-by-side subforms.  The left side shows a tree view of the form DOM, the right side shows a tree view of the data DOM.  Some of the things you should note:

  • Entries in the tree are color-coded depending on their bind status
  • The display is cut off at one page.  To see more, use the scroll buttons at the top
  • Collapse and expand sections of the trees using the +/- buttons on the rows
  • Set focus in a field on either side of the tree and the display will highlight that entry and the corresponding entry(s) in the other DOM in red.
  • Set focus on a row in the form DOM, and some binding information is displayed in the top right of the display
  • Shift+click on a row in the form DOM will set focus to the corresponding field on the form.
  • By default we display the current state of the form at the docReady event.  If you want to refresh/rebuild the tree views, click the refresh button.

To try this out on your own forms, take the domDump subform and add it to your object library in Designer.  When you want to debug a form, drag the domDump subform onto your form.  (The subform needs to be displayed on a new master page with a content area that is at least 8×10.5 inches.) After debugging, when you are happy with your form, remove domDump.

There are some restrictions on the usage of this tool:

  • It works only on interactive forms
  • It works only on dynamic forms
  • Because of the extensive use of JavaScript objects, it does not work on forms with version 8.1 strict-scoping turned on

There is code in the script to check that these conditions have been met.

I won’t go into an in-depth description of the JavaScript that makes this debugger work.  It’s complicated :-) The intent is that form designers can use it without understanding the internals.  The one area where users might be tempted to tweak the script is to customize the information that gets displayed when a row in the form DOM is highlighted.  If that interests you, look for the script function: debugDisplay().

For interest sake, I’ve included one of my previous samples with the debugging subform added.  When I first added the dompDump subform I had to press the "refresh" button in order to see the completed DOMs.  That’s because the transpromo content and the debugging content are both populated from the docReady event — and the transpromo happens last.

Futures

  1. Admittedly, displaying tree views using dynamic subforms is non-trivial and a bit clunky.  One possible enhancement would be that rather than display the tree view on the form, we could export all the data for the tree views.  Then we could write a cool flash app to load the data give a proper rich user experience.  The only drawbacks with that approach is that a) it becomes a multi-step process and b) you lose the ability to "shift+click" to the corresponding form field.
  2. It would be great to have a similar debugging capability for WSDL connections.

March 19 Update

After using the form DOM debugger with several forms, I’m hooked.  I couldn’t resist making a couple improvements to it.  I’ve lifted most of the restrictions as to what flavour of forms it can be used in.  It now works with a broader range of template versions and strict scoping variations.  It also works for non-interactive documents.  For non-interactive, the tree display will spill over multiple pages and give a full dump — rather than windowing the content on a single page.  The only remaining restriction is that it works only with dynamic forms.

June Update

There is a follow-up debugger effort that supercedes the sample in this entry. Please have a look here.