Your prescription for increased productivity and profitability
In our previous post we touched on a problem that exists with AppleScript. This has to do with align and distribute when there is a selection key object.
So what is a selection key object? It is a member of a selection the user has double-clicked to make it the key.
Selection with selection key object
An AppleScript script can determine if there is a selection key object with the following:
tell application "Adobe InDesign CC 2015" set selList to selection set selObject to selection key object end tell
With no selection key object, the result of the above is nothing.
For ExtendScript (JavaScript) the syntax is similar:
var docRef = app.documents.item(0); var selList = docRef.selection; var selItem = docRef.selectionKeyObject;
With a selection key object defined, an operation such as alignment will use that object as its alignment reference. For instance, should you tell InDesign to align selected objects to the top edge, without a selection key object it will align all selected items to the upper-most page item selected. With a selection key object defined, it will use that object for reference. At least, that is the way it is supposed to work. And it does, if you do it manually using the Align panel (Shift F7).
As part of an AppleScript, it does not. The following script demonstrates. It returns an error “Missing required parameter “reference” for method “align”.
tell application "Adobe InDesign CC 2015" set docRef to document 1 set selList to selection set selObject to selection key object tell docRef align align distribute items selList align option top edges align distribute bounds key object end tell end tell
A few hundred attempts to add the reference for the selObject to the align statement just produces frustration.
You can change the statement to use item bounds as the align distribute bounds parameter and work around the problem.
(*For a top-edge alignment, you could use the following*) tell application "Adobe InDesign CC 2015" set docRef to document 1 set selList to selection set selObject to selection key object if selObject is not nothing then copy geometric bounds of selObject to {y0, x0, y1, x1} tell docRef align align distribute items selList align option top edges ¬ align distribute bounds item bounds copy geometric bounds of selObject to {a0, b0, a1, b1} set ydif to (y0 - a0) move selList by {0, ydif} end tell end if end tell
This is one place where ExtendScript rules over AppleScript. The syntax is concise, and works without a problem.
try { var docRef = app.documents.item(0); var selList = app.selection; var selItem = docRef.selectionKeyObject; if (!!selItem) { docRef.align (selList, AlignOptions.TOP_EDGES, AlignDistributeBounds.KEY_OBJECT,selItem); } } catch (e) { alert ("Error " + e); }
If you haven’t played with do script before, now is as good of time as ever.
To add the JavaScript to an AppleScript, you first create the script as text.
Then, you use do script to run the script.
For a simple example: The syntax for telling ExtendScript to show an alert message is as follows:
alert ("Hello world");
Converting the script to text, it would read:
"alert (\"hello world\")"
Notice that the entire script is enclosed in quotes. Quotes inside of quotes are escaped with a backslash.
To run the script, an AppleScript will read as follows:
set myScript to "alert (\"Hello World:\")" tell application "Adobe InDesign CC 2015" do script myScript language javascript end tell
For a more elaborate script, the process can pose a little bit of a challenge.
For the ExendScript Align To Key script above, take it step by step:
set scpt to "try {" & return
set scpt to scpt & "
set scpt to scpt & "var docRef = app.documents.item(0);" & return
set scpt to scpt & "alert (\"Error \" + e);"
Now add your script definition (the value for the variable scpt) to a do script method.
Beneath the statements above, add:
tell application "Adobe InDesign CC 2015" do script scpt language javascript end tell
With a sample document open and page items selected having a selection key object, run the script.
If you find yourself having to use do script to call an ExtendScript fairly often, you may consider saving the script as an external file.
Simply write the ExtendScript code as is (see code above) and save it to a file with a .jsx extension. Of course you will want to make sure your script works, so why not open ExtendScript Toolkit and write the script there. Test the script, and when tested, save it to a protected location on your computer. May I suggest keeping a folder of all of your favorite ExtendScripts in a folder named JavaScripts in the User folder for InDesign.
Use InDesign’s Script Preferences to get a path to the folder and use a do script method to access the script from there.
For example, the following example script expects that a file named “Align_ToTop.jsx exists in a folder named JavaScripts inside the User’s Scripts folder. It then uses do script to run the script from within the AppleScript script.
tell application "Adobe InDesign CC 2015" set scriptFolder to (scripts folder of script preferences as string) set fileAlias to (scriptFolder & "JavaScripts:Align_ToTop.jsx") as alias do script fileAlias language javascript end tell
If there is a document open with a selection key object, the page items selected will align with the top of the selection key object. If no objects are selected, the script errors without a report as to why. For this reason you might want your AppleScript to test for conditions before using do script. The following not only tests for a selection key object, but will throw an error if any other condition fails.
try tell application "Adobe InDesign CC 2015" set selList to selection set selObject to selection key object if selObject is not nothing then set scriptFolder to (scripts folder of script preferences as string) set fileAlias to (scriptFolder & "JavaScripts:Align_ToTop.jsx") as alias do script fileAlias language javascript else error "Requires page items selected with selection key object" end if end tell on error errStr activate display alert errStr end try
This last script works well with a top edge alignment, but what about the other alignment options? Instead of having a script for each alignment option, pass a number to the JavaScript to indicate the alignment option required. This is passed as part of an arguments array. For the purpose of this script, only one value needs to be passed. Even so, it is passed as a single value array.
(*Alignment arguments are in order: 0-top, 1-right, 2-bottom, 3-left, 4-horizontal centers, 5-vertical centers*) set myArgs to {4} tell application "Adobe InDesign CC 2015" set folderRef to (scripts folder of script preferences) as string set fileRef to (folderRef & "JavaScripts:Align_Options.jsx") as alias activate do script fileRef with arguments myArgs language javascript end tell
Add code to test for selection key object as in the script above.
/*This script is saved in the User's Scripts Panel for InDesign inside a folder named JavaScripts*/ var arg1 = arguments[0]; var docRef = app.documents.item(0); var optList = [AlignOptions.TOP_EDGES, AlignOptions.RIGHT_EDGES, AlignOptions.BOTTOM_EDGES, AlignOptions.LEFT_EDGES, AlignOptions.HORIZONTAL_CENTERS, AlignOptions.VERTICAL_CENTERS] var aOption = optList[arg1]; var selList = app.selection; var selItem = docRef.selectionKeyObject; if (!!selItem) { docRef.align (selList, aOption,AlignDistributeBounds.KEY_OBJECT,selItem); }
Think of some other applications where using do script with a JavaScript can help with an automation solution.