Main

March 24, 2007

Where did that border come from?

Have you ever wondered to yourself, "where did that border come from?", when you simply wanted to set a field's fill color? I know I did for a while until I learned about how the quirkiness of borders in XFA.

For example, if I wanted to set a field's background (fill) color to green in a button's Click event, the first thing I would do is:

this.fillColor = "0,255,0";

or

this.border.fill.color.value = "0,255,0";

Both methods amount to the same result which is the following:

Notice the black edge that appears around the perimeter of the field. What is that doing there? All I wanted to do was set the background color to highlight the field!

What I really wanted was this:

Is that too much to ask? All I did was set the fill color; I never messed with the edge, honestly!

In order to understand where that black edge came from and how to make it go away, we'll need a better understanding of how borders are specified in XFA.

XFA Borders

First of all, the term "border" signifies all elements that compose the rectangular area that surrounds the entire field or the field's value (two distinct borders). That means it's made-up of corner, edge and fill properties, amongst others. In Designer, the field's border is edited via the Border palette and the field value's border is edited via the Appearance property on the Object palette's Field tab.

Next is the fact that unlike most other XFA elements, the mere presence of the <border> element, and of some of its child elements such a <fill>, determine what the field's border will look like. For instance, if no <border> element is specified, the field does not have a border even if the <border> element has a presence attribute with a default value of "visible". Likewise, if the <fill> element isn't specified, the border has a transparent fill (i.e. no fill) even though it, too, has a presence attribute with a default value of "visible".

For example, the following field definition has no border:

<field></field>

If the <border> element is specified, then you also get the default <edge> element which is a thin black line and since specifying only a single <edge> element affects all sides of the border, you end-up with a black edge surrounding the border -- just like in the first image above (without the green fill).

In this case, the field's definition is simply this:

<field><border/></field>

When you use the script I proposed earlier for setting a field's background (fill) color to green, this is what you get in the XFA syntax which describes the field:

<field>     <border>         <fill>             <color value="0,255,0"/>         </fill>     </border> </field>

As you can see, the <border> element has been specified and therefore the border gets the default thin black edge (even though an <edge> element wasn't explicitly specified since an edge is implied when not explicitly specified).

Finally, edges and corners are a little tricky because there can be as little as none or as many as 4 <edge> and <corner> elements specified. What you need to remember is that they're defined in clockwise order:

  • No <edge> element is the same as a single <edge> element which defines all edges at once (all 4 edges are identical).
  • Two <edge> elements define the top/bottom (edge 0) and left/right (edge 1) edges.
  • Three <edge> elements define the top (edge 0), left/right (edge 1) and bottom (edge 2) edges.
  • Four <edge> elements define the top (edge 0), right (edge 1), bottom (edge 2) and left (edge 3) edges.

The same goes for the <corner> element.

The Solution

So just how is it that we get rid of that edge? Well, given that the edge is implied (as mentioned earlier), all we have to do is hide it! It's quite simple, in the end, yet quite frustrating if you don't understand how borders work in XFA.

The <edge> element has a presence property which you can set to "hidden" in order to hide it. Therefore, the following script would set the field's background (fill) color to green and ensure that the default black edge doesn't appear along with it:

this.fillColor = "0,255,0"; border.edge.presence = "hidden";

That JavaScript, on a button's Click event, will yield the border as I intended it to be (in the second image mentioned earlier).

Fun With Borders

In order to demonstrate a few things that can be done with borders using script (you may use similar scripts to show/hide borders on fields or field values for all kinds of purposes), I've provided this sample form. I encourage you to open it up in Designer and look at the script in order to get an idea for how you might implement your own border solution.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

February 01, 2007

New List Object Properties and Methods

Some of you may recall my tutorial on sorting lists at runtime which I posted last June. Oh how I wish I had waited until the release of Designer and Acrobat 8.0 in order to write it! With the new release of these two products comes a new API for list objects that would've significantly simplified things: Rather than having to know details about how list object items are represented in XFA (using an <items> node for item text values and an <items save="1"> node for item data values) and manipulating these nodes in script, I could've used methods such as getDisplayItem and getSaveItem.

New Properties

  • length: Returns the number of items in the list object. This property is read-only.
  • selectedIndex: Returns the zero-based index of the first-found item which is selected or -1 if the list has no selection. You may set this property in order to set a new selection in the list or set it to -1 in order to remove the selection entirely. Note that setting this property will first de-select any currently-selected items prior to applying the new selection.

New Methods

  • bool getItemState(int index): Returns true (1 in FormCalc) if the list item specified by the zero-based index parameter is currently selected in the list.
  • setItemState(int index, bool state): Add or remove a list item from the selection by specifying its zero-based index and true to select or false to de-select it (1 or 0, respectively, in FormCalc). Note that if the list object does not support multiple selection (drop down lists typically don't), using this method will have the same effect as setting the selectedIndex property.
  • string getDisplayItem(int index): Returns a list item's text value (this pertains to the list's <items> element in XFA) based on a zero-based index into the list.
  • string getSaveItem(int index): Returns a list item's data value (this pertains to the list's <items save="1"> element in XFA) based on a zero-based index into the list.
  • bool deleteItem(int index): Deletes the list item specified by a zero-based index and returns true (1 in FormCalc) to indicate that the item was effectively deleted.

Demo Form

In order to show-off this cool new API (available in both JavaScript and FormCalc), I designed a little form that uses all the new properties and methods. Play with it in Acrobat 8.0 and check out the script in Designer 8.0. I'm certain it'll make your life a whole lot easier when it comes to scripting list boxes and drop down lists.

Download Sample [pdf]

Minimum Requirements: Designer 8.0, Acrobat 8.0.

Note that you must click away from the "List Box" object after you've set a selection since the list is set to commit its selection on exit (as is recommended when supporting multiple selection). You can specify this by setting the "Commit On" property on the Object palette's Field tab to "Exit".

January 24, 2007

Barcoded Forms (PDF417) Primer

Lee Sutton has posted a what looks like a really good introduction to LiveCycle Barcoded Forms along with some tips and best practices for using 2D barcodes (PDF417 in particular) on your forms and in your workflows.

December 18, 2006

Databases: Inserting, Updating and Deleting Records

Since all of the previous tutorials I've posted with regards to data connections have dealt with searching for records and displaying the results, I thought I should post a little tutorial on how to use data connections for inserting, updating and deleting records as well.

You may recall that the tutorial on connecting a form to a database did demonstrate one method of inserting, updating and deleting records from a database. The problem with using bindings to fields in order to modify records in a data connection is that you must set those fields to the values for the current record and then you have to use the data connection object scripting methods like "addNew()", "update()" or "delete()". This can get really awkward if all you're wanting to do is insert a new record, for instance, and just doesn't cut it if you want to avoid having to load-in data when the form is opened (the only purpose for the data connection may be such that new records can be inserted or existing ones can be deleted yet displaying existing records is not required).

This small tutorial uses a basic ODBC data connection defined in the form and then modifies it, via script, in order to be able to execute SQL statements which either insert, update or delete records from any table in the database for which the data connection was setup to work with. It then uses a separate data connection to the same database for query purposes only since there's no sense complicating things with an all-purpose data connection -- especially when it comes to running "select" SQL statements in order to iterate through records returned by the query.

Key Concept

The key concept with this tutorial is the fact that the <query> node inside an ODBC data connection (as we saw in the tutorial on selecting specific database records) can be used to execute all sorts of SQL statements -- not just "select" queries. This means that if you set the <select> node (inside the <query> node) to be an "insert" SQL statement and open the data connection, the result will be a new record in the database as per the insert statement's parameters (and the same goes for "update" and "delete" SQL statements). In fact, the XFA 2.4 Specification states, on page 772, that "despite the name [of the <query> node], this element can also be used to delete, insert, and update records."

BOF and EOF Actions

One very important thing to note is that the "Beginning of File" and "End of File" actions on the <query> node's <recordSet> child node (which describes how records in the data connection are navigated) must be set to "stayBOF" and "stayEOF", respectively, otherwise you may run into serious problems. That is, the result of reaching the beginning or end of the record set when opening the data connection must be to "stay" where you (the record set navigator) are when the SQL statement is one or more of "insert", "update" and "delete".

See the script in the "Database" script object in the sample form for more details on how to specify this. Use the Hierarchy palette to locate it under the root subform.

Sample Form

I've designed a form that should put this all into perspective for you as well as give you a very useful script object which you can place in your Custom Library tab and re-use in other forms.

In short, these are the steps I followed to design this form:

  1. I created the "RunSQLDataConnection" ODBC data connection to my "FormBuilder" database, specifying a short SQL query to the new "movie_comments" table (although any other table would've been just fine).
  2. I created the second "ListComments" ODBC data connection to my "FormBuilder" database, specifying an SQL query that exposes the "username", "title" (movie title obtained from a join on the movie table) and "comment" columns.
  3. I inserted the various buttons and fields and wrote the scripts.

I've included lots of comments through the scripts to detail what's going on at each stage as well as why certain things are being done so please have look at the sample (note that you don't have to have the data connections setup in order to open the form and look at the script) and let me know if you have any questions.

Download Sample [pdf]

Download FormBuilder Database Definition [sql]

Minimum Requirements: Designer 8.0, Acrobat Pro/Std 8.0

December 07, 2006

Better Form Design with XFA 2.5

You may have noticed that the new version of Designer and Acrobat that Adobe recently released uses a new version of XFA (2.5 to be exact). While the language has many new features in and of its own, the version of the language (2.5 vs 2.4 or older) also dictates how your forms will behave in Acrobat 8+ with respect to certification (digital signatures) and ubiquitization (Reader-enablement).

Background

Since this new behaviour, which is geared to encourage better form design going forward, will ultimately change the way you write certain scripts, I believe it's important to start with some basic knowledge of XFA forms, see what happens when they get certified/ubiquitized, examine how each used to behave in Acrobat 7 and then how they'll behave in Acrobat 8+.

XFA Primer

Simply said, an XFA form is described inside an XDP file. When it's saved as a PDF file, the XDP is actually embedded into the PDF so that it can be processed by Acrobat.

If you look at the XDP (via Designer's XML Source view), you'll see that it's simply a collection of packets that describe the form's various components. For example, <template> describes the form's layout and behaviour while <sourceSet> contains a collection of data connection descriptions you've defined using the Data View palette. When the form is loaded as a PDF into Acrobat, each packet is loaded into its own in-memory (temporary) model and that's what you actually reference in your scripts. For example, you access the sourceSet packet via the sourceSet model with "xfa.sourceSet". Changes to these models are reflected directly into their pertaining packets.

Form Certification/Ubiquitization

Without going into more details than are necessary, once a form is either certified and/or ubiquitized, modifications to any of the protected content (the various models) should be prevented. Modifying the form's protected content post-certification/ubiquitization would invalidate the certification/ubiquitization status. Such modifications mean that the document is no longer in the state in which it was when it was digitally signed and therefore can no longer be trusted by the recipient as being authentic. Even though the modification may have been caused by authored script in the form, no distinction is made between those kinds of modifications and malicious attacks by an unknown party to, for instance, cause form data to be submitted to an alternate server.

Acrobat 7 and XFA 2.4

Acrobat 7 supported XFA forms up to XFA 2.4 (which Designer 7.1 would author). Once an XFA 2.4 form would be either certified and/or ubiquitized, Acrobat 7 would detect modifications to the form's protected content and would invalidate its certification/ubiquitization status if such modifications occurred. It didn't, however, prevent the sourceSet model from being modified post-certification/ubiquitization even though the <sourceSet> packet was included as part of the certification/ubiquitization process.

The inherent danger in this was that while any form that would do common things like display all the records in a database or select specific records in a database (filter records) -- which required the modification of data connection nodes contained within the sourceSet model -- would function happily at first, problems would ensue later on when a form's certification/ubiquitization status would be inadvertently invalidated, for example, because of an unauthorized modification to a certified/ubiquitized model (sourceSet).

Acrobat 8 and XFA 2.4

In order to address the problem of inadvertent modifications (by form scripts) to certified/ubiquitized XFA 2.4 forms, Acrobat 8 was designed to prevent the sourceSet model (and any other certified and/or ubiquitized content) from being modified post-certification/ubiquitization. This means that if an XFA 2.4 form, loaded in Acrobat 8+, becomes certified and/or ubiquitized, any attempt by a form script to modify the sourceSet model (as in the two examples I mentioned earlier) will result in a security exception:

GeneralError: Operation failed.
XFAObject.setAttribute:25:XFA:form1[0]:initialize
This operation violates your permissions configuration.

One could argue, of course, that this change effectively "breaks" XFA 2.4 forms in Acrobat 8+ but in the end, inadvertently invalidating a form's certification/ubiquitization status is likely just as bad as a security failure in a form's script (because it attempted to modify a now-protected model) from a user experience point-of-view. As I mentioned earlier, Acrobat makes no distinction between authored scripts and malicious attacks when certified/ubiquitized content is modified -- and neither does the user (in their minds, the content simply can't be trusted any longer)!

Acrobat 8 and XFA 2.5

With a new version of Acrobat and XFA, there was an opportunity to further improve on the user experience of both certified/ubiquitized and non-certified/ubiquitized forms going forward. It was done simply by ensuring that modifications to any model that becomes protected post-certification/ubiquitization are now prevented from the start (whether the form is certified and/or ubiquitized or not) and by using XFA 2.5 as Acrobat 8+'s "trigger" for imposing the new behaviour.

The result is that we're now forced to think about security from the very beginning of the form design process by opting to work with copies of the in-memory models (which is achieved by cloning models) rather than with the base models such that our forms don't fail regardless of their certified/ubiquitized state. With XFA 2.5's support for "on-the-fly" certification/ubiquitization, a form may become secured and locked-down at any point in its "live cycle" which makes it imperative to use scripting techniques which won't fail post-certification/ubiquitization.

Legacy Mode

New forms authored in Designer 8.0 will be XFA 2.5 forms by default and you'll need to use the new cloning technique described later in this article. That being said, if you need things to be back the way they were, there is a way that you can still use Designer 8.0 to design XFA 2.4 forms and that's by using what's called the Legacy Mode processing instruction.

Put simply, switch to the XML Source view for an XFA 2.5 form in Designer 8.0 and insert the following processing instruction under the <template> node (as a child element):

<?originalXFAVersion http://www.xfa.org/schema/xfa-template/2.4/?>

The result will be that Acrobat 8.0 will run your form as though it was an XFA 2.4 form -- but be aware that this will also prevent you from using any of the new language extensions and APIs that come with XFA 2.5 (more on those in later posts).

(By the way, when you load an older form -- earlier than XFA 2.5 -- into Designer 8.0, even though the form's version is upgraded to XFA 2.5, the Legacy Mode processing instruction specifying the form's original XFA version is automatically added so that your form continues to work properly with respect to the XFA version is was originally designed for.)

Modifying sourceSet in XFA 2.5+ Forms

In order to avoid unexpected security exceptions in your forms after they get certified and/or ubiquitized and to handle the fact that you may not necessarily know for sure at which point in the form's workflow that it'll happen (if ever), you need to make sure that when you're working with the sourceSet model, you're actually using a cloned in-memory copy of the original sourceSet model rather than using the original sourceSet model directly.

Cloning Form Nodes

Don't worry: You don't have to be a scientist to use this simple technique. Using the

clone(deep)

method on the node that defines the particular data connection you're wanting to modify within the SourceSet model and making sure your script keeps using the clone instead of the actual definition will do the trick. This method accepts a boolean parameter which, when set to 1 (or true), will clone the node and all its children (which is definitely what you want to do or else you will only get a shell instead of the full data connection) and return a reference to the in-memory copy.

As an example, let's consider the following script taken from the Data Drop Down List object (found in the Library palette's Custom tab):

...
var oDB = xfa.sourceSet.nodes.item(nIndex);
...
// Search node with the class name "command"
var nDBIndex = 0;
while(oDB.nodes.item(nDBIndex).className != "command")
  nDBIndex++;

oDB.nodes.item(nDBIndex).query.recordSet.setAttribute("stayBOF", "bofAction");
oDB.nodes.item(nDBIndex).query.recordSet.setAttribute("stayEOF", "eofAction");

Notice that the script first obtains a reference to a data connection node found within the original sourceSet model and then goes on to modify some of its properties. In an XFA 2.4 form loaded in Acrobat 8+, prior to certification/ubiquitization, this will function properly although it'll stop functioning if the form ever gets certified/ubiquitized. In an XFA 2.5 form, however, it'll immediately fail with a security exception simply because Acrobat 8+ determines that the sourceSet model may eventually become protected and protects it from the start.

Applying the cloning technique to this script is trivial. All you need to do is change the line which accesses the sourceSet model to this:

var oDB = xfa.sourceSet.nodes.item(nIndex).clone(1);

Notice the clone(1) method appended to the end of the statement. At that point, "oDB" now receives a reference to a copy of the original sourceSet model which it's free to modify regardless of the form's certification/ubiquitization status. The rest of the script doesn't need to be modified at all!

Note that you could just as easily store the cloned data connection node into a Form Variable or a variable defined in a Script Object in order to reference it again at a later time if you make modifications to it that you would like to persist while the form is running in Acrobat.

Updated Library Objects

If you had already installed Designer 8.0 and tried using the Data List Box and Data Drop Down List objects under the Custom tab in the Library palette, you more than likely ran into the security exception I described earlier. That's because those custom objects managed to miss the ever so important update which they required in order to function properly in XFA 2.5+ forms with Acrobat 8+ (as we saw in the previous section).

For your convenience, I've posted updated versions of both the Data Drop Down List and Data List Box custom Library objects which you can save to your local system and add to your personal (or shared) Library in Designer 8.0.


Updated: December 11, 2006

October 31, 2006

Expanding to Fit the Entire Value

A while ago, I posted an article detailing a trick to make the value of a field be displayed entirely within the field's content area. Essentially, by setting the value font size to zero, this tells Acrobat to shrink the field's content area (value) font at will to make the entire value entered fit horizontally. This can certainly be useful but there's one significant drawback: the value font may shrink such that it becomes too small for anyone to read depending on how much data the user enters into the field.

Fortunately, there's an alternative method to making a value fit within a field's content area when you don't know how long the value will be: Making the field's width and/or height expandable!

The advantage of this solution is that the value font's size remains constant (the same as which you specified it to be when you designed the form). When a field is make expandable, its "w" (width) and/or "h" (height) attributes are replaced by "minW" (minimum width) and/or "minH" (minimum height) attributes, respectively. These attributes define the initial and minimum size of the entire field (that is, its caption and content areas combined). When the width is extended, however, only the field's content area is increased in width. Its caption area remains the same width. On the other hand, causing the height of a field's content area to be extended will also cause the caption area's height to be extended.

Making a Field Expandable

Specifying that a field's width and/or height is to expand to fit its content is quite simple: You just need to check the "Expand to fit" check box that pertains to the width and/or height property on the Layout palette.

Getting a Tight Fit

So far, you've learned how to make a field's width and/or height expandable, essentially by specify a minimum width and/or height instead of a set width and/or height. Now what if you wanted to ensure that the field's width and/or height was always just wide enough to contain whatever value was entered? For example, you don't want a whole bunch of empty space if you set a minimum width of 2 inches to have a nice initial size to enter a value into the field but the user only entered a value that required 1 inch to be entirely displayed.

In that case, you could simply set the minimum width to zero when the user leaves the field, if they've entered a value. This is done by scripting the field's Exit event (shown here in FormCalc):

$.minW = "0"

Look-out for Long Values!

One thing you have to look-out for is extra long values -- especially if you haven't specified a maximum length for the field. If the user enters too much data, the field might simply run off the page.

If you don't want to set a maximum data length for the field but you don't want it to expand beyond a certain width, you can set a maximum width and/or height. Since Designer's UI doesn't let you set this property directly, you can use the field's Initialize script to set it (shown here in JavaScript):

this.maxW = "4.5in"; // max width of 4.5 inches

Note, however, that if the user enters more data than can fit within the specified maximum dimensions, the value will be cut-off and won't print so you may consider setting a maximum data length or resorting to the previous solution (setting the font size to zero).

Sample

This sample form implements the solution I've described in this post.

Download Sample [pdf]

Minimum Requirements: Designer 7.x, Acrobat 7.x.

October 28, 2006

Scripting Table Columns

A few days ago, Sergio, one of my regular commenters, posted a question about programmatically adding new columns to a table. My reply to his comment quickly turned into something that I thought should be promoted to a blog post so here it is.

This question required some investigation because it led me to the discovery of a bug related to adding/removing instances of a table column in a form viewed in a version of Acrobat prior to 8.0. More on that later in this post.

The short answer to Sergio's question is that yes, in fact, you can modify the set of columns in a table programmatically at runtime. You can do this by either using the presence attribute -- although this isn't recommended because it can lead to data merging problems -- or you can use Instance Managers to do it, which is the recommended method to use.

Here's a sample form that contains a table with a "repeatable column". Using the add and remove buttons that are provided, you can add and remove instances of the 3rd column.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Continue reading "Scripting Table Columns" »

October 20, 2006

Using URL Requests in PDF Forms

Here’s a sample in response to Ernest’s question on passing values to PDF forms via URL. His intent is to use it to provide a key to a PDF form such that it can be used to filter records from an ODBC Data Connection in order to pre-populate the form with data.

I love these kinds of questions because they challenge me to find answers!

Of course, this is quite specific but there are many other uses for this. In fact, you could have a whole lot of fun with it too! You could even use this to alter the appearance of your form: Say you had one form that you were using for multiple departments in your company and every department had its own header. You could place each header in a subform, make them all hidden and then, based on the URL request which would include a department code, decide which one to show — no XML Data file, database connection or web service needed!

Beware, however, that URL request strings are not secure because they get posted in plain text for anyone to read so be careful of the information you pass-in to your form this way.

This sample form looks for a “message” and a “color” key in the URL request in order to show a message in a text field and change the text field content area’s color (an RGB value). For example:

Download Sample [pdf]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

Continue reading "Using URL Requests in PDF Forms" »

October 12, 2006

Displaying All Records from an ODBC Data Connection

So far, I’ve covered two ways of connecting forms to ODBC data sources:

  1. Connecting a Form to a Database — explains how to design a form which lets the user iterate through each record one at a time; and
  2. Selecting Specific Database Records — takes the first tutorial one step further by providing a means to specify which record(s) to view.

This time, in response to Y. Gautham’s recent comments, I’ve decided to post a little tutorial on displaying all records from an ODBC data connection for reporting purposes (as opposed to editing).

Continue reading "Displaying All Records from an ODBC Data Connection" »

September 29, 2006

Selecting Specific Database Records

Every now and then, someone posts a comment with a question on how to do something and the answer requires more than just a quick response. In this case, it was Ricardo’s question on how to select a specific record from a data connection to a database for editing in a form.

If you read my previous post on Connecting a Form to a Database, you might’ve realized that the result was a single live data connection to the entire set of records in a database. This is great if you want to iterate through all records one at a time and update them on an individual basis. You might’ve also realized that you could narrow the scope of the data connection by specifying a more specific SQL statement (with a WHERE clause, for example). But what if you wanted the form to filter, on the spot, the data loaded from the data connection? For example, you might want to let the user pick from the different movie categories (action, comedy or drama) and then let them iterate through only that subset of the Movie Database.

If you’ve been scratching your elbow, pinching your nose and blinking your eyes in hopes that this might “just work”, well, it’s actually scratch your nose, pinch your elbow and roll your eyes — ok, just kidding…

Continue reading "Selecting Specific Database Records" »

September 18, 2006

Connecting a Form to a Database

In response to Lala and malik’s questions on connecting a form to a database (whether it’s Microsoft Access, MySQL, etc. doesn’t really matter), I decided to write a little tutorial on how to do it.

Even if you already know how to do it, I encourage you to pay special attention to the section on Auto-Incremented Table Columns because it might help you understand and resolve some of the issues you may have already run into.

Continue reading "Connecting a Form to a Database" »

September 04, 2006

Making a Table of Contents

One of the hottest topics on the Designer Forums these days seems to be methods by which one can add a table of contents to their form. Since there are many different ways to achieve this, I thought I would post a little sample to demonstrate how this can be done.

Of primary concern when adding a table of contents to your form is ensuring that the links provided to the form’s various pages/sections remain valid at all times. Static forms whose page set never changes don’t really need to worry about this but dynamic forms do. That is, regardless of whether content pages are added, re-ordered or even deleted from your dynamic form, you need to ensure that when a TOC link is clicked, the user is taken to the correct page pertaining to the topic they selected.

The best way of ensuring that TOC links don’t get broken as a result of changes to the form’s pages is by using layout information provided by the XFA Layout Model. This model provides information such as an object’s actual dimensions (width/height), the page on which it is located as well as a few other interesting pieces of information.

By using the

xfa.layout.absPage

we’re able to get the page number on which an object is currently located, taking into account the various pages which may have been inserted or removed in-between the TOC page and the page in question. Taking that page number and assigning it to the

xfa.host.currentPage

property then sets the current page to the one on which is located the object in quetsion.

Download Sample [pdf]

Minimum Requirements: Designer 7.x, Acrobat 7.x.

Continue reading "Making a Table of Contents" »

August 15, 2006

Invalid Flashing Fields 2.0

A colleague of mine here at Adobe pointed-out today that the use of the AcroForm Document object’s getField method wasn’t necessary in the script I used for my original Invalid Flashing Fields sample.

There’s an alternative which uses xfa.form.resolveNode in the app.setInterval script. xfa.form.resolveNode takes a SOM Expression and returns a reference to an XFA node. What’s more is that this API call can be made from within the context of the AcroForm Scripting Object Model.

The app.setInterval script therefore changes from this:

moFlashTimerID = app.setInterval(
  "var f =  this.getField('" +
    GetAcroFormFieldName(oField) + "');  " +
  "if (color.equal(f.fillColor, color.red))" +
    "{ f.fillColor = [" + moAcroFieldFillColor.toString() + "]; }" +
  "else" +
    "{ f.fillColor = color.red; }",
500);

to this:

moFlashTimerID = app.setInterval(
  "var f =  xfa.form.resolveNode('" +
    oField.somExpression + "');  " +
  "if (f.ui.oneOfChild.border.fill.color.value == '255,0,0')" +
    "{ f.ui.oneOfChild.border.fill.color.value = '232,232,232'; }" +
  "else" +
    "{ f.ui.oneOfChild.border.fill.color.value = '255,0,0'; }",
500);

Also note the changes in the way the color values are compared and assigned (whereby the newer version uses more familiar XFA script rather than the AcroForm script from the first version).

Since the use of the AcroForm Scripting Object Model should always be secondary to using the XFA Scripting Object Model (because AcroForm objects are, after all, in a separate Object Model which may change separately from the XFA Scripting Object Model), I wanted to highlight this alternative which makes more extensive use of the XFA Scripting Object Model than the first version did.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

August 04, 2006

Tracking Mouse Clicks

I just recently received another comment from Zack. This time, he was wondering about how one would go about tracking mouse clicks on an image field.

I had never attempted to do that so I took it on as a challenge and thought I would share the results in this post.

I knew from the start that XFA alone wasn’t going to be able to handle this simply because (to my knowledge) it doesn’t provide any information as to the position of the mouse pointer when an event occurs. The most logical place I thought would’ve provided the information — the Event Pseudo Model (the xfa.event object available in all XFA events) — didn’t live up to my expectations. Thankfully, XFA at least provides a Click event so that I could know when the image got clicked.

The next logical place to look was in Acrobat’s Scripting Object Model (in the AcroForm Objects). In the Acrobat Document object, I found what I was looking for: the mouseX and mouseY properties which provided the location of the mouse with respect to the document window.

The last thing I needed was information about the dimensions and location (within the Acrobat Document Object’s coordinate space) of the image field and the Acrobat Field object’s rect property would give me just that.

The combination of the XFA Click event, the Acrobat Document object’s mouseX and mouseY properties and the Field object’s rect property was just what I needed to get this to work.

Of course, I soon discovered that I had another problem to figure-out: The behaviour of an image field in a PDF form running in Acrobat is that when clicked, it opens a browse dialog that lets you pick the content for the field. Unfortunately, there isn’t any way to suppress that dialog other than making the image field read-only or by using a static image object but then both alternatives prevent the Click event from firing. So I needed some clever way to capture a mouse click over an image (whether it was a field or a static object) and I decided to use a button with a transparent fill and no border (so it was essentially transparent). Since buttons are fields just like image fields, the mouseX, mouseY and rect properties would still be available for the button and if I sized the button to fit the image and placed it over-top, I would essentially end-up with an HTML <map>.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Continue reading "Tracking Mouse Clicks" »

August 02, 2006

Auto-Localizing Your Forms

A few days ago, I posted about Designer 7.1’s new Dynamic Properties feature. In that post, I explained how this feature could be used to automatically populate a list box or drop down list field with data from a data connection without having to write any script.

Today, I thought I would highlight one of the main advantages to using this feature: localization of your forms!

By using the Dynamic Properties feature to bind the caption of form fields to data nodes in a data connection, you can easily localize your forms without having to write any script!

To illustrate how this would work, I’ve designed a simple little form which has an address block on it (taken from the “Address Block” custom object that ships with Designer, found under the Custom tab in the Library palette). Each field in the address block (which excludes the “Locale” field at the top that’s just there for informational purposes) has its Caption property bound to a specific data node in the data connection I’ve defined, based on some different localized XML Data files. To localize the form at run-time (e.g. in Acrobat), just open the form and then load the XML Data file pertaining to the locale you want to use.

Download Sample [zip]

Minimum Requirements: Designer 7.1, Acrobat Pro 7.0.5.

Note: If you open the form in Acrobat, don’t forget to load a data file into it by using the options under the “File | Form Data” menu.

Continue reading "Auto-Localizing Your Forms" »

July 29, 2006

Dynamic Properties

Did you know that as of Designer 7.1, there’s way to automatically populate certain field properties with data without having to write any script? This is what the new Dynamic Properties feature is designed to do.

First, you have to enable it because it’s disabled by default. You can do this by going to the Data Binding panel in the “Tools | Options” dialog. There, you’ll find a check box labeled, “Show Dynamic Properties”. Check the box and press OK. After doing so, put a list box (for example) on the form and take note of the changes in the Object palette’s Field, Value and Binding tabs.

You’ll notice that some property labels have now changed color (default is green) and are underlined. You can now click these property labels to make the properties they pertain to dynamic (i.e. to automatically push values into them when data is loaded into the form via a certain data connection that you specify). For instance, the Field tab now has dynamic Caption and List Items properties.

If you click on the List Items label, you’ll get the following dialog (this screen shot shows the properties already configured for this sample):

Using the Dynamic Property dialog (above), you can then specify the data connection from which the data will be loaded and also the data node(s) that will contain the data (in this case, for a list field, you can bind data nodes to the text and value items of the list).

Download Sample [zip]

Minimum Requirements: Designer 7.1, Acrobat Pro 7.0.5

Note: If you open the form in Acrobat, don’t forget to import the data into it using the “File | Form Data” menu.

Continue reading "Dynamic Properties" »

July 08, 2006

Demystifying IM.AddInstance

The definition for the Instance Manager’s addInstance method is as follows:

addInstance( [BOOLEAN param] )

Personally, I find the word param a little vague. I think it should be called merge instead because that would give a clearer indication as to what it stands for: Essentially, if the data you’ve merged into your form has a repeating section that you’ve bound to a repeating (dynamic) subform and not all instances of this repeating data section have been merged into the form’s layout, you can control whether the new instance of the dynamic subform pertaining to that repeating data section will get merged with the next section or not by specifying true (merge — the default) or false (don’t merge — show empty instance) as the parameter value.

Usually, this doesn’t make a difference because you typically merge all instances of a repeating data section into your form and once there are no more data instances to merge, addInstance(true) will yield the same results as addInstance(false): an new empty (no data merged-in) instance.

Consider, however, the case where your form is a report and you’d like to show only a glimpse of the data instead of loading all 2000 instances of a repeating section. If your data was sorted from the most important to the least important, you could significantly improve the performance of your report (with respect to load time) by limiting the number of instances of that repeating data section that are initially merged into your form. Once your form is loaded, it could provide ways for the reader to get more instances if they wish to do so.

This can be achieved by using the Max property on the dynamic subform’s Binding tab in the Object palette along with addInstance(true).

Here’s a sample which has a data connection to an XML Data File that lists movies. There are 16 movies in total but the form limits the number of movies initially displayed to 10 and provides a Show More button. When this button is pressed, the movie dynamic subform’s Max count property, initially set to 10, is incremented by 1 and a new movie instance is added using true as the parameter.

Download Sample [zip]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

Note: If you open the form in Acrobat, don’t forget to import the data into it using the “File | Form Data” menu.

June 29, 2006

Sorting Lists at Runtime

Have you ever needed to sort the content of a list box or drop down list at runtime (e.g. in a form loaded in PDF with Acrobat or HTML with a browser)?

Unfortunately, neither the XFA nor the AcroForm Object Models give you either properties or methods to achieve this functionality. The only thing available are Sort Ascending and Sort Descending buttons on the list of items you define in the Object palette’s Field tab in Designer — not very useful at runtime! Say you were loading data from an XML Data File into your form and this was populating a list with values that needed to be sorted: There wouldn’t be a built-in way for you to do that.

The only solution I’m aware of at this time is to flex your scripting muscles and write some functions that’ll get you sorting lists (from either list boxes or drop down lists) and that’s exactly what I did today while replying to a post on Adobe’s Designer Forums:

Download Sample [pdf]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

Update: It looks like Acrobat 8.0 broke something that prevents my sample form from working correctly. It has to do with the call to

resolveNodes("#items[*]")

Fortunately, the bug will be fixed in Acrobat's next release.

As a workaround, I would encourage you to have a look at the new list object properties and methods now available in Acrobat 8.0. You should be able to use a combination of those new properties/methods along with some of the original script in this sample in order to come-up with an update solution that works.

All the code is located in the script object appropriately named, “ScriptObject”.

The idea was to make use of the JavaScript Array object’s built-in sorting function, sort, by giving it a custom sorting function that was able to sort pairs of text and value items. Remember that for XFA choiceList fields, there’s always one <items save=”1”> node but there may be a second <items> node if text and value items are defined.

From Designer’s UI, you define value items by default by entering items in the list on the Object palette’s Field tab. This defines an <items save=”1”> node. If you then go to the Bindings tab and specify values, the items you specified on the Field tab become the “text” items, defined in the second <items> node, and the values are set in the <items save=”1”> node.

When sorting the list, it’s important to maintain the association between text and value item pairs and that’s why the script is a little complex — not to mention the fact that getting items out of an XFA choiceList field (list box or drop down list) isn’t as easy as 1-2-3 either!

So the script attempts to find text and/or value items, create ListItem objects for each pair, sort them using the custom sort function __SortFunction and then replaces the current items in the list with the ones in the sorted order.


Updated: April 11, 2007

June 26, 2006

Process All Fields

A common requirement on the Adobe Designer Forums is to find all fields on a form and do something specific with them.

For instance, you may want all mandatory fields to be automatically highlighted when a user attempts to submit a form electronically before having filled all mandatory fields. While Acrobat provides a button to toggle mandatory field highlighting on/off (via the Highlight required fields check box in the yellow Form Field toolbar), Acrobat’s Scripting Object Model doesn’t provide a function to do the same. Therefore, you’re left having to write some script to achieve the same functionality.

Since this is requested so often, I thought I would try to put together some canned script that you can copy and paste into your form in order to instantly have the ability to make changes on everything that’s considered a field on your form.

Download Script [js]
Download Sample [zip]

Minimum Requirements: Designer 7.0, Acrobat 7.0.

Continue reading "Process All Fields" »

June 18, 2006

Invalid Flashing Fields

So what’s the use of learning about new toys like AcroForm Objects and AcroForm Field Name Generators if you don’t take the time to play with them? Today felt like the right day to do just that and I came-up with a sample form where invalid fields flash red until the user has entered valid values into them. Only once all fields are valid can the form be submitted.

Update: Check-out the newer version on the new Invalid Flashing Fields 2.0 post.

Download Sample [pdf]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Note: A basic understanding of AcroForm Objects is required for this sample.

Continue reading "Invalid Flashing Fields" »

May 20, 2006

Add, Recalculate

Here’s a little something that very important to know when working with dynamic subforms and using their Instance Managers (IMs) to add instances of them to a form: New subform instances aren’t automatically incorporated into the form’s calculations!

You would immediately notice this problem if you had a form which calculated a total based on line items which can be added or removed from the form. When you add a new line item using the IM’s addInstance(bool) method, the grand total of, say, the cost of all line items isn’t updated to reflect the data you enter into the new line item. This is because the new line item hasn’t been made part of the form’s set of calculation dependencies and is therefore not accounted for by your “grand total” calculation. As a matter of fact, until a call to xfa.form.recalculate() is made, none of the new instances added will be included in the form’s calculations.

To demonstrate this, I’ve created a sample form which has a “line item” section to which line items can be added. As line items are added and their costs changed, the grand total fields at the bottom calculate the total cost of the order: One grand total field performs its calculation using the FormCalc SUM function and a SOM Expression identifying the collection of fields to total while the other uses the LineItem dynamic subform’s IM object to calculate the grand total. Finally, there’s a check box at the top of the repeating “line item” section which, when checked, will cause the “Add Item” button to execute the xfa.form.recalculate(true) statement after adding a new line item. To see the difference, play around with the form by adding line items with the check box both checked and unchecked.

Download Sample [zip]

Minimum Requirements: Designer 7.x, Acrobat 7.x.

May 10, 2006

Data-Nominated Subforms

I thought I would post a little sample on data-nominated subforms tonight. This is a new feature, introduced in Designer 7.1, which can be a very powerful tool.

Since the feature essentially lets you define expressions against values from data being loaded into a form in order to control which subform, from a specified set (subform set containing subforms), will be used for the record currently being loaded into the form, you can do very interesting things. For example, you might have a table which lists data. Maybe you would like to use a row which has a yellow background to identify data which is not important, one with an orange background for data that’s important and one with a red background for data that’s very important. This can be easily achieved using Data-Nominated Subforms.

I’ve created a little sample based on the movie data I used for the Conditional Breaks Sample I posted a few days ago. In this sample, I have a subform set which contains 3 subforms, each capable of binding to a movie record. The twist is that I want to use the green subform for comedies, the red one for action movies and the blue one for dramas.

Download Sample [zip]

Minimum Requirements: Designer 7.1, Acrobat Pro 7.0.5.

Note: A basic understanding of Data Binding is required for this sample.

Continue reading "Data-Nominated Subforms" »

May 06, 2006

Conditional Breaks

Some of you have requested a sample of the new Conditional Breaks feature in Designer 7.1.

This feature allows you to set conditions, based on imported data, which determine when breaks should occur.

For example, you may have data that you want to list by category and every time the category changes, you’d like to start the new category on a new page. Or, you may have a separator that you want to insert in between sets of data on your form.

I’ve created a little sample which demonstrates the Conditional Breaks feature by listing some movie data where each time the category changes, a new page starts. Don’t forget to import the data.xml file into the form when you open it in Acrobat.

Download Sample [zip]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Note: A basic understanding of Data Binding is required for this sample.

Continue reading "Conditional Breaks" »

Samples! Give Me Samples!

One of the best places to look for Designer samples is on the LiveCycle Designer Samples Site. There, you’ll find lots of samples demonstrating various Designer techniques and features.

Although new samples are constantly be posted to the Designer Samples Site, they can’t always cover all topics or address all of our customer’s questions/issues. As such, I’ll be posting some of my own samples to my blog. Look for them under the Samples category.