Designer ES2 Macros

Hey, it has been a while since I posted.  Lots of stuff on my plate.  Occasionally they make me do real work around here. 

Have you installed ES2 Designer yet?  If you have, then there is a new experimental feature that you can play with.  Macros.  I want to tell you all about them.  But first the caveats:

  1. ES2 Designer macros are an experimental (prototype) feature
  2. ES2 Designer macros are not officially supported
  3. Macros developed for Designer ES2 are not guaranteed to work in the next release of Designer.

We figured out the architecture for this feature fairly late in the ES2 development cycle.  We think macros have lots of potential, but we didn’t have the resources to finish the job in ES2.  So we’ve put it out there as a prototype.  You get to kick the tires.  Tell us if you like it.  Let us know what enhancements are needed.

Overview

Design Macros provide an external plugin interface to Designer, so that 3rd parties like partners or customers can extend the functionality of Designer. Some examples:

  • Rename a field or subform and update all the script references
  • Add metadata to form objects (<extras> or <desc>)
  • Find all scripts that consist entirely of comments
  • Add an onEnter script to all fields

Macro Script

The macro itself consists of a JavaScript file.  The JavaScript in the macro has full access to the template model. (I have a previous blog post that talks about scripting to the template: Template Transformation ).  The basics are that the scripting knowledge  from coding your form script transfers nicely to the Designer environment.

In addition to the template DOM, there’s an object in the root namespace called "designer" that has methods that you can use to communicate directly with the Designer application.

Flash Dialogs

One of the methods on the designer object allows you to launch a flash dialog (.SWF)and allows you to exchange strings with the dialog.  This allows you to build a custom UI.

Installing a Plugin

To install a plugin:

  1. Create a folder named "scripts" in the Designer install directory.
  2. In the scripts folder, create a folder for your plugin, i.e. "MyPlugin"
  3. In the scripts \ MyPlugin folder, create a JavaScript file (this is the actual plugin), i.e. "MyPlugin.js"
  4. Place any SWF files used by the plugin in the same directory.

When Designer starts up, it searches its install directory for a folder called scripts. If this folder is found, Designer will then search each child folder of scripts looking for *.js files.

Every *.js file found (and there can be more than one in the same folder) will appear as a menu entry under the Tools | Scripts menu. This menu entry on the Tools menu appears only if the \scripts directory exists and there is at least one *.js file in a subdirectory of the \scripts folder.

To run the plugin, select the plugin you want to run from the Tools | Scripts menu.

The Designer API

Here follows a description of the methods that are available on the designer object.

/**
* Output a message to the log window in Designer.
* (Note that the log window in designer will not emit any
* duplicate strings)
* @param sMsg The text to push to the log window
*/
void designer.println(sMsg)


/**
* returns the object (or objects) currently selected
* on the canvas or in the hierarchy dialog. If nothing is
* currently selected, the list returned will be empty.
* @return a nodelist
*/
nodelist designer.getSelection()

 

/*
* Create a new modal dialog window from a provided
SWF.
*
* @param sSWF The name of a *.swf file to load.
* Note that the *.swf file must be in
* the same directory that the plugin is installed in. 
* The sSWF parameter should only contain a file name,
* no path information.
*
* @param nWidth The width of the Flex dialog
* @param nHeight The height of the Flex dialog
*
* @return a string that comes from the
* Flex application.  When the Flex application terminates, it
* can pass back a string. Commonly used to send back it’s
* closing status, e.g. "OK" or "Cancel"
*/
string designer.showFlexDialog(sSWF, nWidth, nHeight)

/*
* This method writes out a text file (showTextWindow.txt) to
* the system’s temporary directory with the content of sText
* then launches the system’s default *.txt file editor with
* that file as a parameter.
*
* This method allows a non-modal way of showing output.
* The Flex dialog and the alert dialog are both modal – this
* makes it impossible for a user to interact with the output
* of a plugin at the same time they interact with Designer.
*
* @param sText The text to show in the system’s default
* text editor.
*/
void designer.showTextWindow(sText)

/**
* This function creates an XDP data file from the 
* supplied data and will launch a PDF file with that data.
* This allows rich reporting from a plugin script.
* Note that this function looks for an installed version of
* Acrobat, and will not work with Reader.

* @param dataPacketString The XML data to be written out
* @param pdfName The base name of the PDF file to display,
* which must be in the plugin directory.
*/
void designer.showXDPinAcrobat(dataPacketString, pdfName);

/**
* This function is used to get data out of the Flex dialog
* invoked by designer.showFlexDialog(). The Flex dialog can
* send data to Designer by calling:
* ExternalInterface.call("setDialogString",
*                          "VariableName", "VariableValue");
*
* If the Flex dialog makes this external call to Designer, then
* once the dialog is dismissed, "VariableName" is available for
* inspection in the plugin through a call to:
* designer.getDialogString();
* In this particular example, the call would be:
* designer.getDialogString("VariableName");
* The return value would be "VariableValue".
*
* @param sFieldName The name of the field to inspect.  
* This field is available for inspection only if the Flex
* application made the appropriate ExternalInterface call.
*
@r
eturn The value of sFieldName or empty if the Flex
* application did not set that value.
*/
string designer.getDialogString(string sFieldName);

/**
* This method is used to push data into the Flex dialog before
* calling designer.showFlexDialog(). If the plugin wants to set
* data inside the Flex dialog, it needs to call
* designer.setDialogString();
* with the data before invoking designer.showFlexDialog().
*
The Flex application, in turn, needs to call
*
ExternalInterface.call("getDialogString", "sFieldName")
*
* @param sFieldName The name of the variable to set
*
@param sValue The value of sFieldName.
*/
void designer.setDialogString(sFieldName, sValue)

/**
* Show a message box in Designer with sMsg as the text.
* @param sMsg The message to display in the message box.
*/
void designer.alert(sMsg);

An Example

Over time I hope to share a bunch of sample macros.  But to get started, here is a fairly simple macro that should wet your appetite.

The macro refactor.js will rename a field object.  In addition to renaming the field, it will find all occurrences of that field in scripts and will rename it there as well. It uses refactor.swf as a ui to modify the scripts.

Step 1.

Install the macro.  Place the .js and .swf files below the Designer install.  On my system this looked like:

refactorScreen2

Step 2.

Open a PDF in Designer ES2.  I used this file to test.

Step 3.

Select the field to rename

Step 4.

Launch the macro:

refactorScreen1

Step 5.

When the flash dialog pops up, enter a new name for the field. Then use the buttons to find/replace the field name in scripts

refactorScreen3

When the dialog is dismissed, the form will be updated with all the changes.

Here is the rest of the collateral you’ll need (right click to download):

 

Whew.  That’s a lot to absorb.  I hope to offer some more samples soon.

26 Responses to Designer ES2 Macros

  1. Dimitri says:

    Cool stuff! So much you can do with this, and that people have wanted to do for a while. Thanks for posting this!Dimitri Munkirswww.pdfscripting.com

  2. Thanks John,This is a great start on the new macros feature. I am still trying to get my head around it, especially the swf interface for designers. Clearly most macros will require some interaction and the dialog will play an important part.I have downloaded Flex Builder 3 and I am trying to get to grips with it. It would be very helpful to get some direction/tips on creating a simple Flex dialog for these macros. Not so much “Flex to save the world!”, more like Flex for LC Designers.We could then start thinking about swf interface for users (apart from Form Guides).Thanks again,Niall

  3. Dick Wyman says:

    It would be great if the script could close the current XDP file, invoke an external function to modify the XDP, and then re-open it. Any chance of this capability?

  4. Niall:Yeah, there’s a bit of a start-up learning curve on the flex builder side. If I get a chance I’ll work through a simple example.John

  5. Dick:Having a macro close a file (or more generally have access to menu commands) is a very reasonable suggestion.Launching any kind of external app (in this case to modify the XDP) is less likely to be considered — in the security conscious world we live in we’re unlikely to expose hooks to launch external apps.It should be possible to run xslt on your template from within designer — but from what I know of your scenario I suspect xslt isn’t what you’re looking for…JohnJohn

  6. Ennis Ray Lynch, Jr. says:

    Is there a plan for making this feature official?Also, I noticed you mentioned some security consciousness regarding features; can the SWF files call web services or interact with the internet or are they run in a limited sandbox?

  7. Ennis:Unfortunately, even if I knew the answer to whether macros will be officially supported — I couldn’t answer. Our policy for blogging is pretty clear that we may not give specific information on product futures.But I encourage you to make your wishes known through whatever channels you have available.In the prototype version, I am not aware of any restrictions on the http requests made by the flash plugin. i.e. it’s not wired like flash-in-acrobat where the flash http requests go through the Reader network stack. As far as I know, Designer does not have the equivalent of a network stack.John

  8. Dick Wyman says:

    I’ve found plenty to like in this feature. Here are some issues:The designer.getSelection() method returns a nodeList, which is not an XFA object. The name of the method is misleading, because if I select text in a draw and invoke the designer.getSelection() method, it returns the draw with no way to determine what text has been selected. I would like to be able to replace the selected text, so access to the offset and length of the selection would be useful. It should also be possible to insert text at the current cursor location without having any text selected.There should be a method on the designer object that redraws the current document, much the way it can be redrawn if you modify the XFA in the XML view. This would be particularly important if the script modified the contentArea in some way, e.g. by modifying margins.Non-modal windows would be a significant improvement, particularly the ability to open more than one non-modal window.The TabNavigator and Accordion containers are apparently not supported. I can work around that, but they are pretty slick.Overall, though, I like the feature and hope it becomes a formal part of the product.–Dick

  9. Dick:Thanks for the comment and suggestions.I’ve highlighted these issues to the Designer product manager.John

  10. Tony says:

    Hi John,I have downloaded your AccessibilityChecker macro but is unable to get it working properly. I set it up according to the instructions (eg put the files in the Script folder, etc). I am able to call up the macro from Designer, but the report PDF is not displayed, and I am not able to find it anywhere.Can you point me in the right direction to fix this problem, please?ThanksTony

  11. Tony:Be sure you’ve placed the report PDF (AccessibilityReport.pdf) in the directory with the SWF and JS files. It should then be launched by the macro.John

  12. scott says:

    I just upgraded my acrobat Pro yesterday to the latest version and it looks like they moved the Livecycle Designer folder under the ‘Acrobat 9.0’ folder, that is, it’s no longer under the ‘Adobe’ folder. So I created a ‘scripts’ folder under the new ‘designer 8.2’ folder and this macro no longer works. It worked fine though before when it was under the ‘adobe folder. Do you know if they took this feature away?

    • Scott:
      Designer 8.2 does not support macros. Macros were introduced in Designer ES2 (a.k.a. Designer 9).
      The version numbers of Designer do not match the version numbers of Acrobat. They’re normally one number behind. e.g. Designer 8.2 ships with Acrobat 9. Designer 9 will ship with Acrobat X.

      John

      • scott says:

        Thanks John. So is Designer 8.2 lacking that many features than Designer 9.0, other than the macro capability? I find it confusing that they would have two versions of designer available.

        • John Brinkman says:

          Scott:
          Designer 9.0 can create PDFs targeting Reader 9.1, whereas Designer 8.2 can target Reader 9.0. If you search through my blog history you’ll find a list of the features shipped with 9.1.
          Given that Designer ships with both Acrobat Pro and with LiveCycle it isn’t uncommon to have more than one copy on a system.

          John

  13. Scott says:

    When you mentioned acrobat X previously, I was thinking you meant ‘some future version’ , not realizing that Version X was 10 and is out soon! :) I can’t wait, that’s great. Does anyone take suggestions for the next designer 9.1 or 10?

  14. Dick Wyman says:

    Is there a way to force a re-layout of the document at the end of a macro?

    xfa.layout.relayout();

    throws an exception “Invalid property get operation; xfa doesn’t have property ‘layout'”

    • Dick Wyman says:

      Sorry, I forgot I’d already asked about this back in March. My work-around is to use designer.alert to prompt the operator to save the document before proceeding. That seems to force a relayout.

  15. Hi,

    do you have information about the new API methods in ADEP Designer?
    Especially filterNodeTree(), show(), showHelp(), callExternalFunction().
    There are no remarks which describe the parameters.

    • Marcus:

      Glad to see you’ve got your hands on the new Designer already. And the macro capability is now officially a supported part of the product. And yes, I owe you a blog entry that describes the enhancements/changes to this feature. Hopefully will happen next week.

      John

  16. Thanks John!

    Btw: Can you confirm, that the macros do not support special characters in their js files (like äöü or ß or €)?
    I thought this might be a flaw only in Designer ES2 but the new one seems to have it too.
    So when I create a message (designer.alert) or a comment in german with those characters for example, the macro fails.

  17. Marcus:

    The bug has now been fixed and should be available in Service Pack 1

    John

  18. Good news John,

    you wouldn’t happen to know when and where the service pack will be available for download?

  19. Niall says:

    Thanks John!!!