Modular programming for InDesign JavaScripts using ExtendScript
The focus of the Boston Review is its print edition. So one task in creating their new web site has been creating an automated system for parsing the InDesign files that lay out an issue of the print edition, and creating the files needed to post the entire issue, if they desire, to their new web site.
The best answer to this task is clearly not one huge script, but a collection of smaller scripts that call one another, pass variables, and share one common log file (for my own sanity when debugging). In this article, I list some of the issues I have overcome in setting up such a collection of JavaScript files, rather than one enormous JavaScript, to script InDesign CS2.
Setting up a library
The first thing I wanted to do was set up a library, which is to say a collection of JavaScript functions in a common file, say, that other JavaScripts use. To do this, I used the ExtendScript directive #include to grab the library, which just has a lot of common functions, like so:
#include "importWeblibrary.jsxinc"The file importWebLibrary.jsxinc is in the InDesign scripts directory located as Presets/Scripts/ under the Adobe InDesign CS2 directory.
The full header of my files
There are a couple other important pieces at the top of all my scripts in this collection, so the complete header looks like this:
#strict on
#target indesign
#engine importerToDrupal
#include "importWeblibrary.jsxinc"The '#strict on' turns on strict error checking, which always seems like a good idea top me, having lots of experience in C/C++. The '#target indesign' says the JavaScript refers to the InDesign application and its Document Object Model, so a dialog will pop up when you run a script and there is no InDesign instance running. And the directive '#engine importerToDrupal' makes all the scripts into one group.
Things to watch out for
There are a number of important issues that came up for me around this modular programming environment.
The first is that the representation of the engine (your collection of scripts) happens within InDesign, so the first time you invoke one of your scripts must be done through InDesign's "Window -> Automation -> Scripts" pane for your grouping of scripts to be recognized as such. This should cause "importerToDrupal" to become a choice in ExtendScripts dropdown list of available scripting engines. Unfortunately, in my case, I must switch the target to something else and then back to InDesign CS2 in order for the dropdown list of scripting engines to be updated. After my "scripting engine" importerToDrupal is selected in the ExtenScript Toolkit (ESTK) things will continue to function smoothly even if I instantiate one of the scripts directly from ESTK, rather than from InDesign, in order to debug it.
This leads directly to the next important consideration, which is that any included files (like importWebLibrary.jsxinc) do not appear in the debugger. So I generally get new functions working tacked on to the source file I am debugging before I move them into the library file itself.
Calling another script, and passing variables
You may be wondering, if you've hung in to this point, how to call one script from another and pass variables. Here is a code fragment from my code demonstrating the way I do this:
if(sectionTypeGroup.selectedButton == 1) { log(logFile, "OPENING file #" + index + ' AS FORUM : ' + contentsItem.fullName + "..."); app.open(contentsItem.fullName,true); var thescript = new File("/Applications/Adobe%20InDesign%20CS2/Presets/Scripts/processForumFile.jsx"); var setpagerange = "var DocumentPageRange='"+contentsItem.documentPageRange+"';"; app.doScript(setpagerange); app.doScript(thescript); app.activeDocument.close(); }
Note that I am executing a one-line script to pass the variable DocumentPageRange. It does the job, but if you have a cleaner way, please let me know.
By now you may have realized that 'log()' is the function that was the subject of my previous post. And since it automatically tacks the passed string onto the end of the log file, all I need to do is pass it the same logFile variable to get the one log file behavior I wanted, regardless of where in the collection of scripts I begin execution.
var filePath = "~/Desktop/tempLogFile.txt"; var logFile = new File(filePath);
Since processForumFile.jsx acts on the active InDesign script I can execute it directly through ESTK in order to debug it and it still functions correctly. All I have to do, in my case, is make sure that processForumFile.jsx does something reasonable if the variable 'DocumentPageRange'.
Taking all of these things together makes a reasonable system for architecting a collection of modular JavaScripts to perform a complex task, and be clear to future programmers who may have to maintain your solution.
