Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

'AcroForm Objects' Category Archive

LiveDocs JavaScript API for Acrobat 9

If you’re like me, you’re still waiting for the PDF version to be posted since Acrobat 9 shipped last Summer (seems strange to say “last Summer” already!). In the mean time, I found the LiveDocs version online (once the page loads, click on “JavaScript > JavaScript for Acrobat API Reference > JavaScript API” in the table of contents on the left hand side). It’s not as “rich” as the PDF version but it’ll do for now.


Posted by Stefan Cameron on September 29th, 2008
Filed under AcroForm Objects, Acrobat, Scripting

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.

The trick to all this is obtaining the URL that was used to access the PDF form. This can easily be achieved by accessing the Acrobat Document Object associated with the form and then obtaining the value of its URL property. This is done in JavaScript via the “Message” text field’s Initialize event:

event.target.URL

This property will give you the following string (from the second sample URL I provided earlier):

//URLRequests.pdf?message=Think%20of%20the%20possibilities...&color=0%2C255%2C0 

From there, it’s just simple JavaScript code to extract the request

?message=Think%20of%20the%20possibilities...&color=0%2C255%2C0

and then parse the key/value pairs

message=Think%20of%20the%20possibilities...
color=0%2C255%2C0

Finally, since we’re passing-in a string that may contain spaces which will have been URI-encoded (that’s use of “%20” instead of spaces and “%2C” instead of commas in the request string), we need to decode it back to a normal string using JavaScript’s built-in “decodeURI” and “decodeURIComponent” functions:

decodeURI(decodeURIComponent(string))

If you want to have fun submitting different strings to show in the message box, I found a little tool online which converts regular strings into URI-encoded strings.


Posted by Stefan Cameron on October 20th, 2006
Filed under AcroForm Objects, Scripting, Tutorials

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.


Posted by Stefan Cameron on August 15th, 2006
Filed under AcroForm Objects, Scripting, Tutorials

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.

The first challenge was getting an instance of the Acrobat Field object which represents the button using the

event.target.getField

method. That was easily accomplished by using the script I provided on my AcroForm Field Name Generator article.

The next problem to be solved was the fact that the default behaviour, in Acrobat, for a button when it’s clicked is to invert its content area. Since I was trying to hide the button, I needed a way to suppress the inversion so that clicking on the button would give no visual feedback to the user. That way, it would give the impression that the user was actually clicking on some sort of hyperlink on the image itself. That was easily solved by using the highlight property of the Acrobat Field object representing the XFA button in its Enter event (had to be Enter and not Initialize because Initialize is too early in the form’s initialization process for the association between the XFA button and it’s Acrobat Field counterpart to be established):

event.target.getField(ScriptObject.GetFQSOMExp(this)).highlight =
  highlight.n;

The last problem was with respect to calculating the coordinates of the hot spots on the button that would trigger a reaction (in this sample, I was just going to set the value of a text field somewhere else on the form to reflect the area that was clicked). The problem there was that while I had the mouse location and the button’s dimensions all in the same coordinate space (Acrobat Document), the coordinates were specified with (0,0) set to the document’s lower left corner.

While this may not seem like a big deal to some of you, it really messes me up when (0,0) isn’t at the top left corner (with the maximum (x,y) set to the bottom right corner). I guess that’s a result of years of writing code for Windows where an MFC CWnd’s coordinate space places (0,0) at the top left corner. Anyway, after lots of hair pulling, I finally figured-out how to properly calculate the hot spots in this strange — no, alien — coordinate system.

Zack, if you have any other questions, please post a comment.


Posted by Stefan Cameron on August 4th, 2006
Filed under AcroForm Objects, Scripting, Tutorials

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.

The sample form works like this: When the user clicks on the Submit button, there’s a script which looks at all fields on the form and validates them for valid content. In this particular form, the only requirement is for the fields to be filled (i.e. have non-null values). If all fields are filled, the form is them submitted however, if there’s at least one field which isn’t filled, the first-found non-filled field is set to flash red until the user has filled it.

Since XFA doesn’t natively support flashing fields, this is all done using the Acrobat app, Document and Field objects, discussed in greater detail in my previous post on AcroForm Objects, as well as my AcroForm Field Name Generator code.

When a non-filled field is found, the Submit button’s script will get the AcroForm Field object name for the invalid field and use it to generate a small script which will run every time an Acrobat Timer object expires. This timer is created in the following block of code:

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);

In this block of code, the Acrobat app object’s setInterval method is used to create a timer which will continously expire at a specific interval (in this case, every 500 milliseconds, or 0.5 seconds) and every time it expires, it’ll execute the code specified in the first parameter. Since the timer’s code will execute within the context of the document from which the setInterval method was called, the this keyword will represent Acrobat Document object pertaining to the form. The GetAcroFormFieldName method can then be used to get the AcroForm Field object name pertaining to the invalid field (oField) which is then passed to the Acrobat Document object’s getField method. From there, the AcroForm Field’s fill color is compared to red: If it’s already red, it’s set to a light gray color; otherwise, it’s set to red.

It’s important to note that the setInterval method returns an Acrobat Interval object which can subsequently be used to cancel the interval timer in order to get the field to stop flashing red once the user has filled it with a value. This object is also required in order to ensure the timer is stopped when the form is closed if the user ever decides to close the form while an invalid field is flashing (see the code in the root subform’s (form1) DocClose event).

Updated: August 15, 2006


Posted by Stefan Cameron on June 18th, 2006
Filed under AcroForm Objects, Scripting, Tutorials