Posts in Category "XFA"

Tables with Variable Numbers of Columns

Support for tables in Designer assumes you know in advance how many columns there will be in your table. Occasionally this will not be the case.  You might want a table that adapts to the number of columns that occur in your data.  In other words, you want a table with rows where a cell is represented by a repeating subform.  And while Designer doesn’t support creating such a table via the table UI, it is possible to create one using a bit of script

The technique involves leverages the fact that tables and rows are really just subforms with special attributes.  So when designing the form, we create:

  • A subform to represent the table.  Make it a subform where content flows top-to-bottom.
  • Inside the table subform create one or more row subforms.  Make the row subforms flow left-to-right.
  • Inside each row subform, create combinations of fields, text and subforms that will be treated as columns.
  • It’s best to make the cells growable in width and allow the layout engine to determine best fit.  If you want control over width, leave the columns growable and set the columnWidths attribute on the table subform (see script below)

And then to turn this into a table, add this initialization script to the table subform:

// mark this subform as a table
this.layout = "table";

/** 
* if needed, we could explicitly set the column widths * If left alone, the columns will be auto-sized */ //this.columnWidths = "1in 2in 2in 2in 1in";

And then for each row in the table, add this initialization script:

// mark this subform as a row
this.layout = "row";
if (this.instanceIndex === 0) {
    // mark the first row as a header
    this.assist.role="TH";
} else {
    // mark each subsequent row as a regular table row
    this.assist.role="TR";
}

Note that setting the role attribute is very important for accessibility — it allows the screen reader to use the table header cells to describe the contents of the table body cells. Here is a sample form that implements this technique — along with sample data for previewing.

Fix Layout Problems

This is the fourth of four exercises that were part of the LiveCycle best practices lab at MAX.

Fix Layout Problems using XFADebugger

The purpose of this exercise is to fix layout problems by analyzing their PDF with XFADebugger.pdf.

In Designer, open: EX4 LayoutProblem.pdf (with preview data file: afiList.xml)
In preview, notice that :

  • Content was pushed off the first page
  • The second page is truncated

Open XFADebugger.pdf in Acrobat. Use the “Load XFA/PDF file” to open EX4 LayoutProblem.pdf.

  • Explore the content in the debugger view. Expand the trees. Click on nodes.
  • Click the “Find Warnings” button several times to see various warnings reported.
  • Fix the warnings in Designer

Here is the file with the layout problems fixed: EX4 LayoutProblem (Solution).pdf

Moving code into a shared script object

This is the thrid of four exercises that were part of the LiveCycle best practices lab at MAX.

Create a shared script object fragment

Open the file: EX3 addressCopy.pdf in Designer

Preview the file with sample data and note the behavior when you check "same as billing".  The shipping address values are greyed out and the values are synchronized with the billing address.

The Exercise:

  • The logic to copy values and to change the appearance of the destination subform is implemented under the
    “Same as Billing” checkbox.
  • Take the script methods to copy subforms and “grey-out” data, centralize them in a script object
  • Create a re-usable fragment from the script object

Bonus 1:

  • Change the form properties so that script changes are not preserved:
    Form Properties/Run-time/Preserve scripting change… : Manually
  • Open the form in Acrobat, select “Same as Billing”, save, close and re-open the form
  • Notice the Shipping address is no longer read-only
  • Fix by applying the read-only setting in an initialization script

Bonus 2:

  • Both instances of the country field populate a list of provinces or states. Centralize/share this code.

Solution: EX3 addressCopy (Solution).pdf

Customize a Validation Experience

This is the second of four exercises that were part of the LiveCycle best practices lab at MAX

Implement Field Validation

Open EX2 Validation.pdf in Designer

  • Preview and click the “Submit by email” button to validate the form
  • Notice:
    • Errors are reported with message boxes. 
    • Selecting the error message in the listbox highlights the error field
    • Tabbing out of the listbox will set focus to the selected error field.
  • Change the form properties to customize error handling to: “Don’t show any message boxes”
  • Modify the (propagated) validationState event under the root subform:
    • On error: color fields and modify the toolTip value
    • Else: revert field color and toolTip
  • Bonus:
    • Add a change event to the phone number to restrict entry to digits

The solution file is: EX2 Validation (Solution).pdf

Reverting changes to fields:

To write re-usable code for changing values back to their original state, we should never hard-code the changes. E.g. we should never revert a color by writing: Field.fillColor = "255,255,255". The original color may not have been white.

Rather, after modifying an element, we can revert by removing the changed element. Removing an element forces the XFA processor to use the original value found in the form template.

E.g. Change the font color by modifying the font.fill.color element:
Field.font.fill.color.value = "255,0,0";

Revert the change by removing the color element:
Field.font.fill.nodes.remove(Field.font.fill.color);

Or by removing one of the ancestor properties:
Field.nodes.remove(Field.font);

Changing/filtering keystrokes

  • In the change event, xfa.event.change holds the contents of your key stroke (or paste buffer)
  • E.g. force all input to upper case:

    xfa.event.change = xfa.event.change.toUpperCase();

Script Performance Exercise

I enjoyed attending MAX last week. The best part was putting some faces to names of people who had previously been cyber-personalities.

We did a pre-conference lab on LiveCycle best practices. For the lab I prepared four exercises on various aspects of form design.  For those who weren’t able to attend, I’ll post those exercises as a series of blog entries.

Exercise #1: Measure and Improve JavaScript Performance

In this exercise we optimized a fairly simple script – a few lines in a loop. Depending on your machine, you should be able to improve the performance anywhere from a factor of three up to a factor of seven.

Open EX1 Performance Tests.pdf in Designer.

There are 50 subtotal values that need to be totaled. Each total has a test button that executes the Total script 500 times and measures the performance.

Note the 4 variations of the sum function:

  • Test 1: The original (slow) version of the calculation
  • Test 2: A copy of Test 1 that you will improve. 
    Look at the hints in the code comments in order to improve the script.
  • Test 3: The solution
  • Test4: Same calculation expressed in FormCalc

Understanding the solution:

  • Undeclared variables are very expensive to reference
  • Javascript variables are far less expensive to reference than XFA objects
  • Evaluate as few dots as possible. e.g. c.d is faster than a.b.c.d
  • Dots evaluated inside a resolveNode(s) expression are faster than dots evaluated in JavaScript objects. E.g. resolveNode("a.b.c") is faster than a.b.c

Why is FormCalc faster?

All references to XFA objects from JavaScript involve a round-trip from the script environment to the XFA processor and back. These round trips are expensive. 

FormCalc runs native in the XFA processor and there are no round-tripping costs.

Validate image size

Let’s talk about image size (again).  But this time in the context of data capture. We have this wonderful image field that allows your users to attach image files to their form.  This is great. but it’s also scary.  You likely don’t want to use this for the 10MB images that came straight from their digital camera.  Consider that these images will be base64-encoded and inserted with the rest of the form data — and stored in the PDF.  You want to limit them to images that are reasonably sized. 

Today’s sample has an image field with a validation script that checks the size of the loaded image.  For an image field, field.rawValue will return the base64 value of the embedded image. The length of that string will tell you how big the image is. My validation script does a rough conversion — image size is roughly 3/4 the size of the base64 string. If that size is greater than your threshold you can choose to either reject the image (set the field to null) or simply mark the field as invalid.

Other Blogs to Watch

There are a couple of other resources I should point you torward.  First of all, Niall O’Donovan has posted a nice blog entry describing new features in Designer 10:
http://www.adobe.com/devnet/livecycle/articles/top-10-adep-designer-features.html. You might recognize Niall as a regular contributor on the Designer forums.  He’ll be one of the experts you can meet at MAX next month where he will be doing a session on Designer.

Then, one of our own, Ragavendra, has a blog focused on the server side of forms and output:
http://blogs.adobe.com/foxes/ .  In particular, you might find this entry interesting:
http://blogs.adobe.com/foxes/2011/04/11/creating-bookmark-in-xfa-forms/

With the latest verson of ADEP, it is now possible to create bookmark references for your dynamic forms.

Enjoy.

More Macro Goodies

It’s been quiet here.  I have been mostly heads-down preparing for MAX.  I hope I’ll see many of you there.  If not, the content I’m working on will eventually find its way to this blog.

But today the focus is on some things to get you further ahead with macros.

Updated Samples

I’ve included a zip file with the following:

  • updated lint check macro
  • updated accessibility checker macro
  • updated form report macro
  • sample macro to use as a ‘starter’ for new macros

You can simply unzip this file under your Designer install directory and they should immediately work.

If you’re writing new macros, you should appreciate sample.js.  It includes:

  • A convenience method for emiting messages to Designer’s log panel
  • A convenience method for recursively iterating over the contents of your form
  • A ‘catch’ block that does a good job of reporting script errors in your macro.

Have a peek at the comments in the macro for more details.

In full disclosure, I admit that one of the reasons for updating these macros is that I found a couple issues where old macros didn’t work in the new version of Designer.  But not to worry, there are workarounds available and the new versions of these macros work even better than the old ones.

Dreamweaver

Not surprisingly, I use Dreamweaver to edit my macro javascript files. It is possible to extend the object assist/hinting mechanism of Dreamweaver.  Take this designer.xml and place it under the Dreamweaver/configuration/CodeHints directory.  Then, next time you start DW, you will have code hinting for the designer object.

I’d like to extend this to more of the XFA object model, but that’s a project for another day.

Macros in ADEP Designer 10.0

Well, here’s a poorly kept secret now made public.  The macro feature that we previewed in the ES2 Designer is now an officially supported feature.

You can find the online documentation here.

The good news is that the macros you wrote for ES2 should continue to work in the new Designer.  The only changes is that we’ve changed the directory name where they’re stored (now under "macros").  As well, each macro is described by a macro.xml file.

There are a couple items I should hightlight:

There is a method: designer.callExternalFunction() that allows you to call an arbitrary method in a .DLL. Here is your escape key for every integration problem you might conceive.

designer.filterNodeTree() is added to enhance performance.  Traversing the entire DOM searching for specific elements can ge slow on large forms.  For example,
designer.filterNodeTree(xfa.template, "className", "font")
will return all the <font> elements in the form. 
designer.filterNodeTree(xfa.template, "name", "price")
will return all the objects named "price".

If you produce .chm help files to document your macro, you can invoke them with designer.showHelp()

And, just to give you an excuse to try this out, I’ve written a new macro.  This one will append a floating field reference for an existing field to a text object.  Here are the macro.xml and javascript files. Usage: select the text and field objects, then invoke the macro.

 

See you at MAX?

I’m scheduled to be part of a group doing a preconference hands-on lab on October 2 at MAX.  Details here. It would be great to see some of you at that session.  Or if not that session, then at some other point during MAX.