Skip to main content
May 4, 2011

Early ExtendScript Experiences

FrameScript has long been our go-to tool for FrameMaker automation. When our clients have needed additional functionality in their FrameMaker environment, we have suggested that they buy FrameScript. Using it we can make writers’ tasks easier, we can add automation to FrameMaker processes, or even implement unattended operation of lengthy tasks. Unfortunately, as inexpensive as FrameScript is, the added software cost has been just a bit too much for some clients.

Now in FrameMaker 10 the ExtendScript scripting environment is build into the product. ExtendScript allows automation of most FrameMaker tasks and, through the ExtendScript Toolkit, allows scripts to use other ExtendScript or ActionScript objects. If our clients were going to be asking for tools that use ExtendScript, I thought I’d take a look at it.

Before going any further, I need to “fess up.” I’ve got a lot of experience using FrameScript and I have a good understanding of the FrameMaker document model…from the FrameScript perspective. However (confession time), I haven’t spent a great deal of time programming in the FDK. Not that I haven’t wanted to. As a result, I’m not as familiar with the intricacies of FDK programming as I would like to be.  A bit longer with ExtendScript and I suspect that will change. If some of my scribblings here sound a bit babe-in-the-woods, so be it. On the other hand, if you, like me, are approaching ExtendScript with a FrameScript background (or with no FDK experience at all), you may find this post helpful.

Scripting language

The FrameScript language has always been somewhat quirky. The fundamental syntax of the language is similar to BASIC. Beyond the basic control structures, FrameScript allows you to access FrameMaker’s object model. It then adds some really cool functionality with ESLObjects, including forms objects (which can create sophisticated dialog boxes), access to ActiveX objects, access to databases, and so on. Because FrameScript grew up with the FDK in mind, it provides constructs such as Loop ForEach, which allows you to access many common FrameMaker document objects in sequence. FrameScript also contains a number of commands that provide FrameMaker functionality directly (Copy, Cut, and Paste, for instance).

Those of us who have written FrameScripts for a while have become used to some of the “convenience” functions provided in FrameScript. They have provided shelter from the details of FDK programming.

ExtendScript is essentially JavaScript that uses additional objects that allow access to the Windows environment (the ExtendScript toolkit CS5) and the FrameMaker object model. Syntactically speaking, it’s quite clean. If you’ve had any experience with JavaScript, the ExtendScript syntax should come naturally.

Unfortunately, the documentation provided by Adobe on ExtendScript is woefully lacking (more on that later). There have been a handful of blog posts, which introduce some very basic ideas of ExtendScript. Unfortunately, there was little in these posts that I hadn’t figured out already. What was missing were some hints that I could use to begin to replicate my FrameScript experience in ExtendScript.

What is missing or different?

The first question that came to my mind was “how can I write something to the FrameMaker console, such as a ‘Hello World.’ string, just to see that I’m doing things right?”

After some digging (and playing with the JavaScript alert() function), I found the Err() method, which allows scripts to write to the console.

Err('Hello World.n');

Note that unlike the FrameScript write console command, the Err() method requires a newline (“n”) at the end of each line.

Actually, Err is one of many methods associated with the Globals object. At this point, it’s worth pointing out the Object Model Viewer. To find out about any of the classes, properties, and objects in ExtendScript, go to Help > Object Model Viewer in the ExtendScript Toolkit application. Then under the word “Browser,” click the drop-down and choose “Adobe FrameMaker-10 Object Model.”

When you scroll through the various objects in ExendScript Object Model Viewer, you may not initially notice the Globals object. Look for it, because it contains a number of useful methods for interacting with the FrameMaker user interface, through the FDK. These include methods to modify the FrameMaker menus, get font information, push and pop the clipboard contents, display alerts, and print debugging information, among others.

My second big question was how to access the current FrameMaker session. In FrameScript there are two very useful properties, ActiveDoc and ActiveBook, which you use to find the FrameMaker file or book that is currently active. Quite often this is how you address the current document. Although FrameScript lets you write simply “ActiveDoc” or “ActiveBook”, these are both properties of the session object, so the full syntax should be “session.ActiveDoc” and “session.ActiveBook”. In ExtendScript, you use the app object to locate session information.

var vDoc = app.ActiveDoc;
Err('ActiveDoc name is: '+vDoc.Name+'n');

Finding the app object in the Object Model Viewer is somewhat problematic. The app object is the only object that begins with a lowercase letter. A sorting quirk in the Object Model Viewer puts “app” at the end of the object list, AFTER all other objects (after “XRefFmt”).

Question three was how to get only the text out of a FrameMaker object (without markers, propery changes, conditions, and so on). FrameScript provides a property (text) that returns only the text of a paragraph. In much of my FrameScripting work I use the text property much more frequently than the Get TextList command, which returns the full content of the paragraph. Once I have the raw text I can perform many other tasks, such as search it for a substring, report it to the user, manipulate it, or use it to build a new paragraph somewhere else.

From what I can see, ExtendScript doesn’t offer anything like the text property. If you want only the text, you have to create a function like this:

function getText(vPgf) {
var vText = '';
var vTextItem;
var vTList = vPgf.GetText(Constants.FTI_String);
for (var i=0; i < vTList.length; i++) {
vTextItem = vTList[i];
vText += vTextItem.sdata;
}
return vText;
}

The last of my big questions went unanswered: How do I list the properties of an object?

When writing and debugging FrameScripts, I have found the properties property to be extremely useful. Seeing all the properties of an object can bring an error into sharp focus.

write console vPara.properties;

The ExtendScript methods getProps() and PrintPropVals() are only marginally useful. The PrintPropVals() method does not convert the PropVal identifiers into strings, which makes the output very hard to read. At least PrintPropVals() expands the property value information and indicates the value type along with the value.

At this point, I cannot find anything in ExtendScript that is as useful as the FrameScript properties property. Because I typically use it during debugging, it’s not worth creating a massive table to associate the identifier values with strings. If anyone has a suggestion for this shortcoming, I’d love to hear it.

Some Caveats

In my dabbling I found a few FrameScript habits that got me into trouble in ExtendScript.

Case matters

In FrameScript, case does not matter for properties, keywords, and variables. In ExtendScript, it does. Thus, to get the name of a document, vDoc.name does not work, but vDoc.Name does.

Null objects vs. empty objects

In FrameScript, you create a variable to hold an object (for example a table). If the object is null, the value of the variable is null. In ExtendScript, variables are JavaScript objects. JavaScript objects contains a number of properties in addition to the actual value. Thus, even if the object you store in the variable is null, the object variable itself is not null. A common FrameScript trick is to loop through a set of objects until the null object is encountered:

Set vTable = ActiveDoc.FirstTblInDoc;
Loop While(vTable)
// Do some stuff
// Get the next table
Set vTable = vTable.NextTblInDoc;
EndLoop

Using “While(vTable)” will not work in ExtendScript. Instead, you use the .ObjectValid() method to check if the object is valid or not (you can also check the value of the .id property).

var vTable = app.ActiveDoc.FirstTblInDoc;
while (vTable.ObjectValid()) {
// Do some stuff
// Get the next table
vTable = vTable.NextTblInDoc;
}

Documentation issues

My greatest disappointment with the Framemaker 10 ExtendScript implementation is with the documentation. I can work around just about all the other differences I’ve described thus far (even the lack of the properties property), but the lack of documentation is truly unfortunate.

The ExtendScript documentation itself predates FrameMaker 10, and thus has nothing about working in the FrameMaker object model. That is understandable. But it would have been good to have a FrameMaker supplement to the ExtendScript documentation.

When I first opened the ExtendScript Toolkit and found the Object Model Viewer I thought I had found what I was looking for: descriptions of the FrameMaker 10 classes, properties, and methods.

To my great disappointment and annoyance, the definitions contain no text; they list the FrameMaker 10 objects and their relationships to other classes, properties, and methods. But there is NO (none, bupkis, zilch) documentation about what each class, property, or method does. I was able to recognize many objects from my familiarity with the FrameMaker object model. But many others remained fairly obscure. For these, I was able to use the FDK reference documentation to determine what these objects do. The FDK is not part of the downloaded ExtendScript package, but is essential nonetheless. The omission of any descriptive text from the object model data is serious shortcoming, which I hope Adobe will remedy SOON (please?).

Note that this is a FrameMaker-specific issue: the Object Model Viewer has quite complete documentation for the JavaScript and ScriptUI classes.

In summary…

ExtendScript has the potential to be a useful addition to FrameMaker. Although the cost of upgrading to FrameMaker 10 must be kept in mind, once you have upgraded, the only additional cost for creating scripts will be the time spent developing, testing, and debugging. However, given it’s immaturity and poor documentation this could be significant. On the other hand, FrameScript is a mature product with many convenience functions, extended capabilities, usable (and useful) documentation, and an experienced base of script developers. The lower cost of FrameScript development could easily make up for the cost of FrameScript licenses.

Have you experimented with ExtendScript in FrameMaker 10? What has your experience been?