Custom scripting in the DITA-FMx book-build process

One of the popular features in DITA-FMx is its ability to generate a PDF-ready FrameMaker book and files from a DITA map. The idea is that these files are actually PDF-ready .. one click to build the book, quick review (optional), then save to PDF. Because you can define all of the setup and publishing properties in a book-build INI (ditafmx-bookbuild.ini to be precise) that is saved with each book file, you’re able to reliably and accurately regenerate the FM files for each DITA map without worrying about getting the settings right each time. This saves time and ensures accuracy and consistency.

One feature of the book-build process is the option to include custom processing in the publishing process. DITA-FMx provides many useful publishing features, but there’s always the need to perform some additional processing to achieve formatting that is specific to your needs.

The Run Custom Script option provides the ability to run one or more FDK client (plugin) command, ExtendScript, or FrameScript, at the end of the default book-build process so you can perform whatever additional processing you need. This eliminates the need to make any manual tweaks to the generated files and ensures that your output always looks the same.

If you want the same script to run for all book-builds, you can set this option through the DITA-FMx > DITA Options dialog. In the Options dialog choose the Book Builds button and on the Book Build Settings dialog you’ll see the Run Custom Script option.

fmx-custom-script

If you’re running an ExtendScript, enter “ScriptingSupport” in the Client field, and the full path (using the forward slash as directory delimiter) to the script file name in the Args field (for FrameScript, use “fsl” in the Client field).

Yes .. that’s the easy part. I suppose you want to know how to create a script?

Here’s an example of an ExtendScript that applies a background color to all elements in your files that have the @status attribute set to “changed” or “new”. You might not want to use this for the final PDF, but it’s a nice way to flag new and changed content for your reviewers.

Just copy this code to a new file named tag-changes.jsx (or whatever you’d like), and place that file in a known location on your file system. It doesn’t really matter where you put it, you just need the full path and file name  for the “Args” field in the Run Custom Script settings. (You can download the file from here .. tag-changes.jsx.)

/* 
 * ExtendScript to set a background color on elements 
 * with @status='changed' or @status='new' in all 
 * files in book 
 *
 */
Console("Running ExtendScript on book."); 
// get the active book
var book = app.ActiveBook;
// get the first component in that book
var comp = book.FirstComponentInBook;
// iterate over all components
while (comp.id) 
{
  // get the component name (file name)
  var compName = comp.Name;
  // open that file (ok if already open)
  var doc = SimpleOpen (compName, false);
  // print a message to the console
  Console("Processing: "+compName); 
  // call our function to perform the processing
  fnProcessDoc(doc);
  // get the next component and loop back
  comp = comp.NextComponentInBook;
}

// function that starts the processing of a document
function fnProcessDoc(doc)
{
  // get the root element in the file
  var rootElem = doc.MainFlowInDoc.HighestLevelElement;
  // run function to process all elements in the file 
  // .. (if it's structured)
  if (rootElem.id) {
    fnProcessElements(doc, rootElem);
  }
}

// iterative function to walk through all elements 
function fnProcessElements(doc, elem)
{
  // get the value of the status attribute
  var statusVal = fnGetAttributeValue(elem, "status");
  // check if value is "new" or "changed"
  if ((statusVal == "new") || 
      (statusVal == "changed")) 
  {
    // set the background color to "Green"
    fnSetBackgroundColor(doc, elem, "Green") ;
  }
  // scan for more elements
  var child = elem.FirstChildElement;
  while (child.id) {
    fnProcessElements(doc, child);
    child = child.NextSiblingElement;
  }
}

// function to get the specified attribute value
function fnGetAttributeValue(elem, attrName)
{
  var attrVal = "";
  var attrs = elem.GetAttributes();
  for (n=0; n<attrs.len; n++) {
    if (attrs[n].name == attrName) {
      attrVal = attrs[n].values;
      break;
    }
  }
  return attrVal;
}

// function to set the background color
function fnSetBackgroundColor(doc, elem, colorName) 
{
  var color = doc.GetNamedColor(colorName);
  // check that the color is valid
  if (color.ObjectValid()) {
    var setVal = new TypedVal();
    setVal.valType = Constants.FT_Integer;
    setVal.ival = true;
    doc.SetTextVal(elem.TextRange, 
        Constants.FP_UseBkColor, setVal);
    setVal.valType = Constants.FT_Id;
    setVal.obj = color;
    doc.SetTextVal(elem.TextRange, 
        Constants.FP_BkColor, setVal);
  }
  else {
    Err("Invalid color: " + colorName + "\n");
  }
}

If you’re using a book-build INI file, you can add these settings in the BookBuildOverrides section:

[BookBuildOverrides]
...
RunScript=1
ScriptName=ScriptingSupport
ScriptArgs=C:/publishing/scripts/tag-changes.jsx

When you run the DITA-FMx > Generate Book from Map command, this script will run and your files will be processed accordingly.

If you want to run multiple scripts (or different types of scripts, ExtendScript + FDK plugin), you just use the vertical bar as a delimiter in the ScriptName and ScriptArgs values (be sure to start with a vertical bar). The following example shows how to run the tag-changes script followed by the StructureSnippets plugin.

[BookBuildOverrides]
...
RunScript=1
ScriptName=| ScriptingSupport | Pubs-Tools:StructureSnippets
ScriptArgs=| C:/scripts/tag-changes.jsx | RUNSNIPPETSCRIPT

For FDK plugins, the ScriptName is the “client name” as defined in the maker.ini file, and the ScriptArgs value will vary depending on how that plugin was set up.

This Run Custom Script feature makes it so you can tailor the way FM files are generated from a DITA map to exactly suit your needs. Don’t let anyone tell you that PDFs from DITA have to be boring or ugly!

2 thoughts on “Custom scripting in the DITA-FMx book-build process

  1. Yves Barbion

    This is really great stuff! I have just tested this with DITA-FMx 1.1.16 in FrameMaker 11 and it works (of course it does, because it’s a Leximation product ;-). I can imagine using this script for all types of content which need background shading (no more tables!).
    The only minor issue I see is when I set @status=changed on a section which consists of multiple paragraphs. Background shading is applied to each individual paragraph, but not on the complete section as a whole, but I guess that’s just the way in which background shading currently works in Fm?

Comments are closed.