Posts in Category "Scripting"

Tracking Mouse Clicks

I just recently received another “comment from Zack”:http://blogs.adobe.com/formbuilder/2006/08/autolocalizing_your_forms.html#comment-18302. 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”:http://blogs.adobe.com/formbuilder/2006/06/acroform_objects.html). 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]”:http://blogs.adobe.com/formbuilder/samples/AcroFormObjects/TrackingMouseClicks.pdf

*Minimum Requirements:* Designer 7.1, Acrobat 7.0.5.

Continue reading…

Previewing as Dynamic PDF

Have you ever lived through the frustration of previewing a form on which you’ve written a simple little script to affect the presence of an object when a button is clicked and pulling your hair out because you keep clicking on the button and nothing happens (object doesn’t disappear, there’s no error message, etc.)? Or maybe you’ve been in a situation where you’ve added script to a button in order to “insert a new instance of a repeatable subform”:http://blogs.adobe.com/formbuilder/scripting/instance_manager and while clicking on the button doesn’t produce one, the submitted XML data file contains entries for each new instance that was added?

Even if you haven’t, it may happen someday so here’s the remedy for the case of the “Common (Static PDF) Flue”…

In Designer, there are two different locations containing settings which affect the type of temporary PDF file created when you click on the Preview tab:

# Under the “File Options” section within the “Document Handling” panel of the “Tools | Options” dialog, you can set the _Default File Type for New Forms_. This type is used on new forms which you preview *prior* to saving (because Designer doesn’t know which format you’ll use at the time of preview). This is set to a static PDF format by default.
# Even if you’ve specified a dynamic PDF format for the _Default File Type for New Forms_, this setting may be overridden by the _Preview Type_ and _XDP Preview Format_ properties in the “File | Form Properties” dialog in the “Defaults” panel once you’ve saved your form. The _Preview Type_ property, set to “Interactive” by default, determines whether the form will be previewed as an interactive (dynamic) form or as a print (static) form. This property supersedes the PDF format. The _XDP Preview Format_ property usually picks-up the _Default File Type for New Forms_ setting and determines what PDF format will be used to preview your form should it be saved as an XDP. (Note that if you’ve saved your form as a PDF file, then the _XDP Preview Format_ setting is ignored).

Now that we’ve covered the different properties which affect the PDF preview format, here’s how to kick that flue I was talking about earlier (so that you actually do preview in a dynamic PDF format and stop pulling your hair out):

# If you haven’t saved your form, make sure the _Preview Type_ is set to “Interactive” and that the _Default File Type for New Forms_ is set to a dynamic PDF format. You may also want to set the _XDP Preview Format_ to a dynamic PDF format while you’re at it.
# If you’ve saved your form as a _dynamic_ PDF, make sure the _Preview Type_ is set to “Interactive”.
# If you’ve saved your form as a _static_ PDF, none of these settings will help you. You must first save your form as a dynamic PDF.
# If you’ve saved your form as an XDP, make sure the _Preview Type_ is set to “Interactive” and the _XDP Preview Format_ is set to a dynamic PDF format.
# If you’re tired of running into these problems and want to avoid them in the future, just set your _Default File Type for New Forms_ to a dynamic PDF format.

I hope this tip improves your form design health. It did wonders for me!

====
~*Updated:* January 27, 2007~

Form Variable Tip

Form Variables can be useful because you can store string values into them that are persisted across object events as opposed to variables created locally (within scripted events) which are destroyed at the end of every event.

You can create Form Variables by going to the Variables tab within the Form Properties dialog, accessed via the main File menu.

The catch is in the way you get and set their values: If you’re writing a *FormCalc* script, then you can manipulate them just like any other variable. For example, let’s say you define one named “MyVar”. In your script, you can then write

bc. MyVar = “test”

to assign the value “test” to it and you can write

bc. xfa.host.messageBox(MyVar)

to display its value in a message box.

If you were then to change the script’s language to *JavaScript* and attempted to display the variable’s value in a message box as above, you would get the following error:

bc. GeneralError: Operation failed.
XFAObject.messageBox:1:XFA:form1[0].#subform[0].Button1[0]:click
Argument mismatch in property or function argument

This is because FormCalc helps you by doing things “under the hood” based on the context in order to get and set the value of a Form Variable whereas JavaScript doesn’t.

If you look at the XFA definition of the variable, it looks like this:

bc.
test

This means that the value of the “MyVar” Form Variable is actually contained within the MyVar element’s _content_ which must be accessed via the _value_ property. Therefore, in order to access a Form Variable’s value in JavaScript, you need to do this:

bc. MyVar.value = “test”; // set the value
xfa.host.messageBox(MyVar.value); // get the value

Just like being able to simply write a field’s name like this in a *FormCalc* script in order to access its value

bc. MyField

as opposed to having to write

bc. MyField.rawValue

in *JavaScript*, you need to specify the property you’re accessing on the object in JavaScript when accessing the value of a Form Variable (which is always the _value_ property).

Demystifying IM.AddInstance

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

bc. 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]”:http://blogs.adobe.com/formbuilder/samples/im/AddInstanceTrueFalse.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.

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

Process All Fields

A common requirement on the “Adobe Designer Forums”:http://www.adobeforums.com/cgi-bin/webx/.3bb7d189/ 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]”:http://blogs.adobe.com/formbuilder/samples/ProcessAllFields.js
“Download Sample [zip]”:http://blogs.adobe.com/formbuilder/samples/ProcessAllFields.zip

*Minimum Requirements:* Designer 7.0, Acrobat 7.0.

Continue reading…

Invalid Flashing Fields

So what’s the use of learning about new toys like “AcroForm Objects”:http://blogs.adobe.com/formbuilder/2006/06/acroform_objects.html and “AcroForm Field Name Generators”:http://blogs.adobe.com/formbuilder/2006/06/acroform_field_name_generator.html 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.

%{color:red} *Update:* Check-out the newer version on the new “Invalid Flashing Fields 2.0″:http://blogs.adobe.com/formbuilder/2006/08/invalid_flashing_fields_2.html post. %

“Download Sample [pdf]”:http://blogs.adobe.com/formbuilder/samples/AcroFormObjects/InvalidFlashingFields.pdf

*Minimum Requirements:* Designer 7.1, Acrobat 7.0.5.

*Note:* A basic understanding of “AcroForm Objects”:http://blogs.adobe.com/formbuilder/2006/06/acroform_objects.html is required for this sample.

Continue reading…

AcroForm Field Name Generator

So you’ve read my previous post about “AcroForm Objects”:http://blogs.adobe.com/formbuilder/2006/06/acroform_objects.html and now you’re wondering what you do with that stuff. Those more adventurous might even have tried to use the _event.target.getField_ method to do something cool.

If you’re going to do things on the application or the document without attempting to affect a specific field, it’s pretty straight-forward: You just call methods on the _app_ (Acrobat Application) or _event.target_ (Acrobat Document) objects. Getting an AcroForm Field object, however, isn’t as simple as you may think because of the naming conventions used when the Acrobat Form objects are created, based on the XFA Form objects.

Let’s say you have a field, named “MyField”, parented to the second page, named “Page2″, of your form, named “form1″. For some reason, you need to access that field’s pertaining AcroForm Field object. If you tried

bc. event.target.getField(“MyField”)

you wouldn’t get very far because the actual name of the field is:

bc. form1[0].Page2[0].MyField[0]

Basically, each AcroForm Field object is named with a _verbose_ form of the “XFA SOM Expression”:http://blogs.adobe.com/formbuilder/2006/06/som_expression_generator.html of its pertaining XFA Form object (also known as a *Fully-Qualified SOM Expression*).

Continue reading…

AcroForm Objects

Today I thought I would tackle the subject of AcroForm Objects — objects available via scripting in the Acrobat Form Object Model — because they offer unique possibilities for your forms *when they’re running in Acrobat in the PDF format*.

Just to be clear, AcroForms are *specific to Acrobat* and therefore this functionality doesn’t apply when rendering your forms to a target other than PDF (e.g. when using “LiveCycle Forms”:http://www.adobe.com/products/server/formserver to render your XFA Forms as HTML).

First, let’s explain what XFA (XML Forms Architecture — a “W3C Submission”:http://www.w3.org/1999/05/XFA/xfa-template) does: It lets you describe a form, using a defined set of rules that govern an XML structure, which can target many different clients (e.g. PDF, HTML, etc.) — as long these clients support the XFA format. Today, the Adobe LiveCycle Designer targets PDF out-of-the-box and, along with “LiveCycle Forms”:http://www.adobe.com/products/server/formserver, targets HTML.

The fact that XFA is always translated into a format which can be understood by a client with which a user interacts in order to fill a form and possibly submit its data to a receiver means that the scripts you write in your XFA forms get executed in the target client application (such as Acrobat or a web browser). If the target client also contains a Scripting Object Model — like Acrobat does — there may be ways that you can take advantage of specific functionality exposed by the client which is hosting your XFA forms.

This brings us to the topic at hand: “Acrobat’s Form (AcroForm) Object Scripting Model”:http://partners.adobe.com/public/developer/acrobat/sdk/index_doc.html#js. If you’re designing your form only to target PDF (or you add code to your form to detect when your form is being hosted by Acrobat using xfa.host.name, for example), you can get access to the Acrobat _app_, _Document_ and _Field_ objects, amongst others, and do some really cool things like have a “field with invalid data start flashing red”:http://blogs.adobe.com/formbuilder/2006/06/invalid_flashing_fields.html when the user attempts to submit the form’s data.

Continue reading…

XFA SOM Expression Generator

Have you ever had trouble figuring-out what the SOM expression is for a particular object which you’re trying to address within your script?

If so, here’s a tip that might come in handy the next time you’re stumped:

With the input focus (the “I” beam) set within the event you’re scripting on the Script Editor palette in Designer, hold-down the Control key and move your mouse over the canvas. Notice that as you hover over objects, the mouse pointer switches to a “V” cursor. If you click, the full SOM expression for the object you clicked will be automatically inserted into your script. But that’s not all! The generated SOM expression will be automatically formatted to work with your script’s language settings:

If you haven’t named the “page 1″ subform and you pick an object on it, you’ll get the following code if your script’s language is FormCalc:

bc. form1.#subform[0].myField

If your script’s language is JavaScript, you’ll get the following code (for the same object):

bc. xfa.resolveNode(“form1.#subform[0].myField”)

Note that if you click on the object on which you’re scripting the event, “$” will be inserted for a FormCalc script and “this” will be inserted for a JavaScript script.