Recently in Product Feature Category

Actions and JavaScript

| 1 Comment

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

| No Comments

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

Can We Offer Some Assistance?

| No Comments

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

| No Comments

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

| 1 Comment

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...

About this Archive

This page is an archive of recent entries in the Product Feature category.

General is the previous category.

Find recent content on the main index or look in the archives to find all content.

Categories

Pages

Powered by Movable Type 4.261