Posts in Category "Product Feature"

Actions and JavaScript

If you’ve checked out Steve’s post that introduces Actions and the Action Builder, you should have a basic idea of what Actions is about. In this post, I intend to dive a bit deeper into the guts of how Actions work “under the hood” as it were and explain what happens to your form when you use Actions.

I’ll start by expanding on Steve’s simple “When Button1 is clicked, go to a web page” example.

This is the simple button click example in the Action Builder dialog:

ActionsBtnClick.png

If you press the “OK” button and preview your form in Acrobat, when you press the button, a web browser will open to the website provided. It’s like magic!

And now I will sadly make the experience much less magical: I’m going to explain what’s really happening behind the curtain to get this to work.

When an Action is created, Designer is actually generating JavaScript code for you, under the hood. Given the conditions you provide and the results you want to achieve, we figure out what event should trigger the code to run, and what JavaScript needs to be placed in that event to achieve the result desired.

How It Really Works

What really happens is that Designer generates scripts and puts them in the right events of the form for you. Each Action generates one or more script blocks (which we call “script snippets” or just “snippets”.) A script block generated by Designer has a standard format:


[1] //+ The header ID line, which is also the "managed script" open line
[0-*] //+ Action parameter lines
[1-*] Lines of Javascript
[1] //- The managed script closing line

Everything between the first //+ and the //- line is a “managed script”, i.e. a script that Designer created, rather than one that was created manually by you, the form author. Designer keeps track of all the managed scripts through the header blocks (all the lines that start with //+).

After creating the simple “When Button1 is clicked…” Action, if you check the Script Editor, you will see that the Button1::click event contains some script:

ActionsBtnClkScript.png

At this point, there are two very important technical details about managed script that I would like to review:

The first point is that the header block is the important data of a managed script. The actual JavaScript is incidental, from Designer’s point of view. For Actions to work properly, all the information Designer needs is what is in the header block. In point of fact, the JavaScript between the //+ and the //- is routinely thrown away and regenerated by Designer.

The second point is that the Action Builder and Actions UI depend on the scripts that Designer generates not being tampered with to work correctly: if a managed script has been edited manually, it is an extremely difficult problem for Designer to figure out what has changed, and whether the changes are valid. Since it’s so difficult, we don’t even try: if any changes are made to a managed script, we un-manage that script. In essence, you lose your Action. This means that when the Script Editor next refreshes, the Action header block will be gone, and the script will look just like regular script you typed in manually. Also, if you open the Action Builder, the Action that was modified will no longer be there.

This isn’t as bad as it may seem. In fact, we designed this entire feature with the idea that people would eventually want to deliberately un-manage scripts: maybe you just want to use the Action Builder to get you started, but you want to do more complicated script on your own: so you create a “starter” Action and then go manually edit the action to make it do more complex things. So it’s not necessarily a bad thing to un-manage your Action – you should just be sure you know what you’re doing and don’t un-manage scripts accidentally.

I guess I’ll leave off here on the introduction to the innards of Actions. I have another post planned where I’ll explain the Action header block in more detail.

An Intro to Actions

Check out Steve’s blog post about the Action Builder.

Can We Offer Some Assistance?

Improving the scripting experience has been a major theme for the next release of Designer. While the core focus of development work on improving the scripting experience has been around the action builder and the validation functionality, I happily was able to find a bit of time to improve the Object Assist functionality in the Script Editor. I thought I would share some of the improvements that you can look forward to in the next version of Designer.

This is the current Object Assist experience:
ObjectAssist-Old.bmp

This is the new & improved Object Assist window:
ObjectAssist-New.bmp

I’ll outline the major changes below.

New Icons

The Object Assist dialog now displays icons next to each entry. There are four possible icons:

ObjectAssist-Icons.bmp

The first icon is used to denote methods.
The second icon is used to denote attributes.
The third icon represents a deprecated method.
The fourth icon is used for deprecated attributes.

This functionality is useful to tell “at a glance” what the various items in the list mean.

Note that we no longer italicize any of the entries in the listbox. The italics were meant to denote methods and attributes that are XFA Plugin (i.e. HTML) compatible. That information has now moved into the help text for each entry.

Improved Help

The help box that used to be gray and contain very brief descriptions of the various APIs has had a huge facelift. The help box is now a rich text control and can therefore be used to show information in a richer way. The box is also bigger, since we now have much more information to display.

I hadn’t realized how cumbersome it must be to get the API information for the XFA scripting model… Internally, we have a Flex application that acts as an XFA API reference. It’s pretty cool, and fairly easy to use. While not as practical as inline help, the Flex XFA API tool is quite an acceptable way to get API help easily. However, when I did a bit of research, I discovered that we don’t publicly release that tool (it was built by one of our great coop students.) I was horrified to think that everyone has to go to the script reference PDF every time they want to know more about an API call! As a programmer myself, I can imagine how inconvenient that must be.

It turns out that the Flex API application hooks into the same code that the Object Assist does to query the API data. So all the information was there, we just had to pull it out and format it correctly. So that’s what we did. Here’s a description of the information the improved Object Assist will be showing:

For all entries:

  • The description text of the entry (this is all that we used to show).
  • The version of XFA for which the entry is supported (i.e. 2.1, 2.6, etc.)
  • The availability of the entry (Core XFA, Acrobat, XFA Subset (HTML), XFAF, Dynamic Documents or deprecated.) Note that the availability can be a combination of options.

For attributes:

ObjectAssist-Attribute.bmp

  • The attribute type (string, int, object, bool, etc.)
  • The attribute access (get, set or get and set).

For methods:

ObjectAssist-Method.bmp

  • The complete method signature
  • Description text for each parameter
  • Description text for the return value
  • Noting of optional parameters

Function Completion

We’ve also added functionality that will auto-insert the parameter brackets and parameter arguments into the Script Editor when you choose a method from the list. Our Function button already does this, so it’s not very different from how some stuff already works.

For example, choosing “deleteItem” from the Object Assist list will insert deleteItem(n1) into the editor.

Choosing “assignNode” will insert assignNode(s1[, s2][, n3]).

The parameter names are actually type abbreviations. We use “s” for string, “n” for int, “d” for double, “b” for bool, “e” for exception and “o” for object. In the examples above, deleteItem expects an integer, and assignNode expects a string and optionally a second string and an integer.

If you absolutely hate this functionality, and want the old way back, we’ve added a checkbox to Tools | Options | Worskpace called “Add Statement Completion Method Signatures”. Just uncheck that box, and the signatures will not be auto-inserted.

ObjectAssist-Options.bmp

Improved Usability

We’ve essentially re-written the keyboard and mouse handling for the Object Assist from scratch. Note that the Object Assist no longer has an edit control:

ObjectAssist-WithEdit.bmp

ObjectAssist-WithoutEdit.bmp

The edit control was complicating the keyboard handling and generally impeding the implementation of several more “natural” or “usable” keyboard shortcuts.

We’ve also made lots of little changes to the how various keys (like HOME, END, PAGE_DOWN, PAGE_UP, etc.) behave and improved the functionality for “searching” in the function list while typing.

Dot Leaders Feature

If you haven’t had the chance, go check out the video explaining the new “Dot Leaders” feature on Adobe’s Developer Connection site:

http://www.adobe.com/devnet/livecycle/articles/dot_leader.html

Sharing Custom Objects Through the Object Library

On top of all my top-secret work on Designer “Next”, this week I also had to track down the history of a feature change from Designer 7.1 to Designer 8.0 which was causing grief for a customer. After tracking down the change, I also looked into potential workarounds and re-discovered a feature in Designer that I had completely forgotten about (hey – in a tool as big and advanced as Designer, there’s lots and lots of features – it’s not that hard to lose track of the littler ones.) It was an interesting case and I thought I’d share it on this blog.

Our story starts with an email from a customer (that came to R&D through the Technical Account Manager and our internal eTech group) saying that when they upgraded from Designer 7.1 to Designer 8.2, a feature that they depended on for their workflow was no longer available. Here’s an extract of the email:

They are looking to create 3 different types of Object Libraries:

  1. Libraries accessed by the entire office
  2. Team-specific libraries
  3. Individual libraries

They just recently moved to LiveCycle Designer 8.2 and when an end user removed a category from the Object Library palette, it actually deleted the files from the drive (folder) it was located in, which then caused everyone to lose access to the library. A particular example, the end user added the Administration category to her Object Library palette for a specific project. Once she was done with that project, she removed the category from her Object Library palette as she didn’t want to see it or need it anymore. At this point, everyone lost access to the Administration category when she removed it from her Designer client because it deleted the objects from their team’s shared folder (M: drive). They want to be able to add and remove categories without affecting other users as their team work on different projects. With Designer 7 we could do this as they would chose the Remove the group option as shown below:

OriginalDialog.bmp

In Designer 8.0 and above, you now get the following pop-up. The end user had instinctively clicked on the first entry which subsequently removed the group and all its objects as it states. :)

NewDialog.bmp

Anyone know why this behavior changed and what if any other alternatives they have going forward?

This is an interesting scenario. Anyway, the first order of business was to try to track down that particular change, to find clues as to why we would have removed the original “Remove [but don't delete] Group” option. A quick search through our source code repository found the history of this change, which I will share for people who are interested in the gory details of development work:

CL #xxxxxxxx
12/1/2005 4:01:29 PM

- Defect #yyyyyyyyy – Very Difficult to Recover Barcode Library if Removed

I believe that when the “Restore Standard Objects” feature was implemented, we only had one “factory installed” library tab. We now have three (standard, barcodes and custom; four if you count the potential SAP.) The restore standard objects did not really work correctly anymore, as it has not been updated in a long time and the library itself has changed a lot in that time.

In order to make the restore objects feature more universal and more easily maintainable I have put in place the following changes:

- The application now considers the object libraries installed in the app folder (taking language into account of course) to be the “factory installed default” objects. The application now takes these libraries as being default and will restore the objects in any one of them. In the past, the mechanism was to embed the object files into our resources and query there for the defaults. The old method required a lot more maintanance (which I note has not been done in the intervening time), requires more complex code for managing and does not really offer any more benefit than using the installed files.

- When removing groups, there are now 2 options instead of three: delete and move & delete. The deletion now removes the underlying data directory from the file system. (Leaving the directory there was causing problems with the file restore algorithm.)

I bolded the last paragraph, because it contains the key information about why this change was made in the first place: just removing the group but leaving a directory there was breaking the “restore defaults” functionality.

After first reading this, then thinking about the above customer problem, I thought “Uh-oh. We goofed and unthinkingly destroyed a customer workflow without providing an alternative.” However, this didn’t feel right to me off the bat – the development team is usually very hesitant to remove any features/options/commands from Designer for exactly this type of reason – once it’s in place, odds are someone, somewhere depends on the feature and will be unhappy with the change.

I’m the person who made the change described in the change list text above: when I started nosing around the code, lots of the details came back to me and I remembered more about the whole “Object Library Group Management” feature. And it turns out that there’s a specific feature to manage the scenario this customer is describing. The feature isn’t as fully-developed as I would like, but even without full UI support, it’s the way you are supposed to use shared Object Libraries.

So the Object Library has two kinds of groups: “Groups” and “Shared Library Locations”.

ContextMenu.bmp

This is the Object Library’s menu. The options we care about here are “Add Group…” and “Shared Library Location…”

In this customer’s scenario, individual libraries should be created and managed by “Add Group”; shared libraries should use the “Shared Library Location”. Some notes about the “Shared Library”: the shared library is configured by one XML file; you can have lots of shared “groups” but they’re all managed by one library. Also you can’t, in Designer, remove just one shared group – you’ll disconnect the whole library if you try (although you won’t delete it or the files – just disconnect).

Here’s what you have to do:

The shared library file should have exactly the same format as the LocalLibrary.xml file which can be found in the user’s Designer data directory (i.e. c:\users\youruserid\Appdata\…\Adobe\Designer\9.0\EN\Objects)

Here’s what you could create:

SharedLibrary.xml – save it somewhere (reliable and safe – like \My Documents) on your system:


<?xml version="1.0" encoding="UTF-8"?>
<objectLibraryTabSet>
<tab name="Shared Accounting Objects" directory="M:\SomeDirectory\Objects" permission="adm"/>
<tab name="Shared Form Team Objects" directory="\\SomeSharedComputer\Designer\objects" permission="adm"/>
</objectLibraryTabSet>

This file can contain as many <tab> entries as required. The <tab> entries should be changed to reflect the location/names of shared object resources on the network. The directory can point to relative paths, absolute paths, absolute paths to mapped drives (like the shared “M:” drive in the example above), and network paths.

To access the shared objects, choose “Shared Library Location…” and navigate to the SharedLibrary.xml file and press OK. There should now be tabs that have a special icon denoting their “shared” status in the object library:

SharedLibrary.bmp

To get back to the example above: in this scenario, what you want is that each user has their own SharedLibrary.xml file on their own computer. Each person would add <tab> entries to their own file: one entry per shared object location they need to access. So you would have a bunch of entries for enterprise level objects and a bunch of entries for team level objects. Your own personal objects would continue to use the “Group” option, not the “Shared Library” option. If you no longer want certain groups (say you’ve changed teams), then you would edit SharedLibrary.xml and remove all the <tab> entries that you don’t want anymore.

You could also have one SharedLibrary.xml file that everyone has to use on a shared drive somewhere. That has the benefit that only one person would need to manage the ShareLibrary.xml file, but the drawback is that each user does not have a customized set of shared objects – it’s all or nothing.

I don’t know how widespread the use of shared object library resources is: if it’s very common and lots of people were relying on the same functionality as the customers in the email above, it could be worth it for us to add more UI and functionality to manage shared object libraries…

Advanced Typography Options

We’ve added some new typographical options to Designer for 8.2. We now support kerning, horizontal and vertical font scaling and letter spacing.

FontInspector.png

Kerning

Kerning is used to reduce the spacing between glyphs to make text more visually appealing. Designer supports pair kerning, a kerning algorithm that looks at pairs of glyphs and figures out whether the glyphs can be drawn closer together. Certain glyph pairs are highly prone to kerning (like “AV” where the space between the two letters is highly symmetrical) whereas other glyph pairs are not good candidates for kerning. There is no user control over which glyph pairs will be kerned – the kerning is applied based on font metrics and kerning information embedded in the font as well as other algorithmic operations undertaken by Designer.

You can choose to apply kerning to an entire object or to a selection of text – again, whether anything gets kerned is up to Designer, but it will attempt to kern the given text.

If you apply kerning to a selection of text, or if you multi-select objects that have different kerning values, the “Auto Kern” checkbox will display a square rather than a check: this indicates varying kerning states in the current selection.

Font Scaling

Font scaling is used to independently change either the horizontal or vertical sizing of glyphs. Setting the horizontal and vertical scale to the same amount is equivalent to changing the point size (i.e. for a 10pt font, setting the horizontal and vertical scale to 200% is equivalent to doubling the point size. So the result would be identical to setting the font to be 20pt in size.)

Scaling can be applied to an entire object, or to a text selection within the object.

Letter Spacing

Letter spacing is used to force glyphs to render closer together (sort of squishing the letters) or to force letters to render further apart (expanding the text). Unlike kerning, which is applied selectively to certain glyphs that are considered good candidates, letter spacing is applied uniformly to all text.

In order to make letters render closer together, a negative value should be entered. To force the text to expand, enter a positive value.

Like the other properties, letter spacing can be applied to an entire object, or to a selection of text.

The typographical options are fairly straightforward and work like other existing typographical options. Please feel free to post any comments or questions in the comments section.

Hyphenation Under the Hood (HUH)

Designer now supports automatic hyphenation of text on a form. We anticipate that this feature is going to be very popular with some clients (especially with German clients – from what I understand, German is a language that benefits a lot from auto-hyphenation.) In this post, I’ll be providing a summary of how the hyphenation feature works in Designer, along with some “under the hood” descriptions of what’s really going on when hyphenation is used.

The Nuts and Bolts

At it’s base, hyphenation instructions are really an XFA tag <hyphenation> that is a child of the <para> tag. According to the XFA grammar, any <para> tag in the whole form can have a <hyphenation> child and set specific hyphenation settings for that <para> element.

However, we did not choose to expose hyphenation in Designer as a per-<para> property. Instead, hyphenation is implemented on a per-form basis, with each individual text object either having hyphenation on or off.

The way hyphenation works is that the five different variables that control hyphenation are set at the form level and get applied to any object that has hyphenation turned on. The way we chose to implement the form level hyphenation is through the XFA <protos> mechanism. A <proto> is like a snippet of re-usable XFA; you can declare it once and then have any element “use” that proto.

We have one proto definition for a hyphenation node:


<proto>
<field name="designer__defaultHyphenation">
<para>
<hyphenation hyphenate="1" wordCharacterCount="3" remainCharacterCount="2" pushCharacterCount="2"/>
</para>
</field>
</proto>

Then, every object for which hyphenation is turned on gets a <hyphenation> entry on it’s <para> element that uses that proto node:


<para vAlign="middle">
<hyphenation use="designer__defaultHyphenation.para.hyphenation"/>
</para>

How Designer Implements Form-Level Hyphenation Settings

There are actually two mechanisms that come into play when setting form-level hyphenation. The first mechanism is the application level hyphenation settings. These settings can be found under Tools | Options | Formatting. These settings control hyphenation options for new forms. So every new form created in Designer will have these hyphenation settings a a default. The goal of this menu is to allow users to customize hyphenation behavior for all forms they create, so they don’t have to constantly update the Form Properties of every new form.

Tools.png

The second mechanism that comes into play is to change settings on a per-form basis, in File | Form Properties | Formatting. Changing the settings here only affects the current form; new forms will still inherit the settings from the Tools | Options | Formatting menu. Changing the form-level hyphenation properties has an immediate effect on the current form: once the dialog is dismissed, all hyphenated text in the form should change to reflect the new hyphenation settings. This dialog also contains two buttons that are shortcuts for removing all hyphenation from the form and adding hyphenation to all the elements of the form. Note that these buttons have an instantaneous result – you don’t have to press “ok” on the dialog for the action to take place.

Form.png

The proto hyphenation node will only be present if it is needed (i.e. some real node, somewhere in the document, is hyphenated and thus needs to use the proto.) In certain cases, if there is no proto node, but the form has hyphenation settings that differ from the default, then a Hyphenation processing instruction (PI) will be added to the document in order to save the form’s hyphenation settings.

How to Use Hyphenation in a Form

When you are actually working with your form, hyphenation is really simple to use. It’s one checkbox control on the Paragraph Inspector.

Inspector1.png

A couple of “gotchas” with hyphenation on the form:

  • By default, allowing hyphenation of field captions and static text is disabled. This means that the hyphenation checkbox control will be disabled on the dialog if a static text control is selected. It also means that on a control that has both caption and value text (i.e. a TextField), when the hyphenation checkbox is checked, it will fill with a square rather than a check, indicating a dual-state check (where half the control is hyphenated and the other half is not.) In order to change this behavior, enable the “Allow Hyphenation in Text and Field Captions” option in Tools | Options | Formatting (for all new forms) or in File | Form Properties | Formatting (for the current form).
  • Another situation where the checkbox may fill with a square rather than a check is if multiple objects are selected and some of them have hyphenation enabled and others have it disabled. The checkbox will show the “mixed” square indicator in this situation as well.

Comments on Compatibility

Hyphenation works with XFAF. However, hyphenation cannot be applied to background content.

Using hyphenation can result in target version warnings, since not all versions of Acrobat support all types of hyphenation. For the most part, hyphenation in value text is not supported in earlier versions of Acrobat (< 9.0). Hyphenation in boilerplate text is supported in older version of Acrobat for static forms. If the form is dynamic, then hyphenation of boilerplate will not be supported in older versions of Acrobat (< 9.0).

One last note on compatibility: there is a risk that using hyphenation could cause text shifting in newer versions of Acrobat. Hyphenation depends on hyphenation dictionaries to figure out where to hyphenate text. Hyphenation dictionaries can change over time: it is conceivable that new dictionaries could be introduced that would change where hyphenation points occur, leading to changes in text layout for hyphenated text. These changes would probably be very minor, but it could lead to a difference of adding/losing a line of text. The risk is fairly small, but it does exist. We strongly urge customers who have forms that are sensitive to text shifting not to make use of hyphenation.

Hyphenation and Fragments

(The following is straight from the functional specification for hyphenation:)

Hyphenation in fragments works in the same way as hyphenation in regular forms. That is, any object that is hyphenated in a fragment will have a <hyphenation use=“designer__defaultHyphenation.para.hyphenation”/> child defined under the appropriate <para> element.

When a fragment is created in a separate XDP file, if any object in the fragment contains hyphenation instructions then the fragment will be created with a <proto> element on the root subform that contains a <hyphenation> child inside a named field that is a copy of the <hyphenation> definition from the original form. The use attribute does not need to be updated, since the SOM of the hyphenation proto is the same in the fragment as it was in the original document.

If a fragment is defined within an existing XDP, nothing changes in regards to hyphenation; the <hyphenation use=“designer__defaultHyphenation.para.hyphenation”/> elements are still valid, and continue to point to the root subform’s <proto> <hyphenation> element.

In both of the cases above, when a fragment is referenced from another form, it (potentially) has different hyphenation settings than the form that is referencing the fragment. The fragment’s hyphenation settings are self-contained within the fragment and separate from the referencing form’s fragment settings.

When a referenced fragment is embedded within a form, it loses its unique hyphenation settings; any <hyphenation use=“designer__defaultHyphenation.para.hyphenation”/> elements will be changed so that the use attribute points to the SOM of the root subform’s <proto> hyphenation node. Or, in other words, the fragment will now inherit the form’s hyphenation settings, rather than having different hyphenation settings that are defined in the fragment. This could potentially lead to a change in appearance and layout when a fragment is embedded.

If a hyphenated fragment is embedded within a form that does not have any hyphenation, then the fragment’s hyphenation will be lost (i.e. it still inherits the form’s hyphenation settings, namely “no hyphenation”).

To Conclude

This was an overview of the Hyphenation feature from an “under the hood” perspective. For details on how the feature works from a functional point of view, please read Designer’s Help documentation.