Automating Adobe InDesign CC 2015


InDesign's do script: deeper dive

Wednesday, May 25, 2016

DoScript With Arguments

In our blog of May 7 (this year) we touched on the subject of using doScript in AppleScript to call an InDesign method in ExtendScript (JavaScript). This was needed to get around a problem with InDesign's align/distribute method with AppleScript. The focus of this blog was to show how a script residing in an ExtendScript file could be called from AppleScript. The script used do script arguments to pass a number into the script. This number designadesignated which of a list of AlignOptions to use for InDesign's align method.

The question that remains in the minds of many who are new to writing scripts is exactly how does do script work with arguments. This blog backtracks somewhat to explain the subject further.

A Simple AppleScript

Define the script as text (inside quotes):
set myScript to "alert(\"Hello World\")"
--tell do script to run the script
tell application "Adobe InDesign CC 2015"
   do script myScript language javascript
end tell

Similarly, we can do the same with ExtendScript:

var myScript = 'activate\r';
myScript += 'display alert \"Hello World\"';
app.doScript (myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE);

Of course there is no advantage to calling an alert message from another language, but using an alert dialog keeps the code simple for demonstration,

Pass in Arguments

To pass in values to a do script, we use an argument list. You might think of an argument list as a global variable named arguments. Then consider a do script as a handler (function) that can only see a global variable by the same name. When do script is called, the values of the local variable that defines the script arguments is passed to the variable named arguments. Because arguments has global scope, it can be "seen" by the language specified for the do script. In the following examples the local variable "myArgs" is passed to arguments and used by do script:

AppleScript

set myArgs to {"John"}  --myArgs is local
set myScript to "var arg1 = arguments[0];" & return
set myScript to myScript & "alert (\"Hello \"  + arg1);"
tell application "Adobe InDesign CC 2015"
do script myScript with arguments myArgs language javascript  --myArgs passed to arguments list
end tell

ExtendScript

var myArgs = ["John"];
var myScript = 'set arg1 to item 1 of arguments\r'
myScript += 'activate\r'
myScript += 'display alert ("Hello \" & arg1)'
app.doScript (myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, myArgs);

In the above you can combine the variable assignment statement with the display alert statement, and substitute this in the above scripts as in the following:

AppleScript

set myArgs to {"John"}
set myScript to "alert (\"Hello \" + arguments[0]);"

ExtendScript

var myArgs = ["john"];
var myScript = 'activate\r';
myScript += 'display alert ("Hello \" & item 1 of arguments)';

The Script String

With all of the string manipulation, quotes, and backslashes required, putting a script together as a string to be used by do script can be somewhat of a challenge. The biggest problem is in wrapping one's head around to think in the syntax needed for the other language. For instance, in AppleScript you write:
   set variableName to variableValue

where in ExtendScript you write:
   var variableName = variableValue;

And when you are working with a list in AppleScript, it's an array in ExtendScript. A list in AppleScript uses curly braces
   set myArgs to {"John", 24}

while ExtendScript uses square brackets.
   var myArgs = ["john", 24];

In ExtendScript you may be tempted to try to tell an AppleScript to set a value to the index of the array, writing this:
   set argumentItemValue to arguments[0]; --does not work

instead of what is needed for AppleScript:
   set argumentItemValue to item 1 of arguments

And, of course, there are the quotes that need to be escaped, as well as line returns and semicolons that need to be added.

Get into the habit of testing the script string before attempting to call it with a do string statement.

The result of the script string value should read just as it would inside of its appropriate editor.
For example: Suppose you want the Macintosh computer to say a message using a given voice. In AppleScript you can write:

set theMessage to "Have a good day"
say theMessage using "Junior"

To write this in ExtendScript, you would write:

//write the argument line as normal, you are talking to ExtendScript
var myArgs = ["Have a good day"];
//write do script script inside quotes using AppleScript syntax
var myScript = "set theMessage to item 1 of myArgs\r"
//escape quotation marks using backslash
myScript += "say theMessage using \"Junior\" ";
myScript // have value of myScript written to the console

Now run the script (in ExtendScript) to test for the value of the variable myScript. The result for this will be:

Result: set theMessage to item 1 of myArgs
say theMessage using "Junior"

Read through the result to make sure you don't have any errors. 

Better yet, test the code with AppleScript editor. In a new script for AppleScript Editor, write a statement to set the value of theMessage

set myArgs to {"Have a good day"}

Copy the result returned from running the ExtendScript

set theMessage to item 1 of myArgs
say theMessage using "Junior"

Compile the script and run it, if it compiles. If not, fix the error(s) and test until you get it right. Be sure to update your ExtendScript accordingly when it works.

Now all you need to do in ExtendScript is change the reference to the local variable myArgs inside the script to arguments and add the doScript statement. Your finished script should read:

//write this as normal, you are talking to ExtendScript
var myArgs = ["Have a good day"]; 
//write the do script inside quotes using AppleScript syntax
var myScript = "set theMessage to item 1 of arguments\r"
myScript += "say theMessage using \"Junior\" ";
app.doScript (myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, myArgs)

Be sure that the variable for the argument array in the app.doScript statement matches the variable at the top of the script where the values for the arguments list is declared. Of course you will need to have sound enabled on the computer for the script to work.

Passing In File References

A problem can arise when you start working with files and folders. If you can define the path to the folder or file as text inside the script, so much the better. For example: I want my ExtendScript to read as follows where the file is "test.txt" inside a folder named "Test" : (To test the following scripts make sure you have a file named "test.txt" saved on the desktop in a folder named "Test.")

var deskPath = Folder.desktop;
var filePath = deskPath + "/Test/test.txt";
alert ("filePath is " + filePath);
filePath

In AppleScript I write:

set myScript to "var deskPath = Folder.desktop;" & return
set myScript to myScript & "var filePath = deskPath + \"/Test/test.txt\";" & return
set myScript to myScript & "alert(\"filePath is \" + filePath);"
tell application "Adobe InDesign CC 2015"
do script myScript language javascript
end tell

Should I want to define the filePath outside of the script and pass it to the script using arguments, the script gets a little more difficult:

set myArgs to {"Folder.desktop + \"Test/test.txt\""}
set myScript to "var filePath = " & "  arguments[0];" & return
set myScript to myScript & "alert('filePath is '" & "+  filePath);" & return
set myScript to myScript & "alert('file name is ' + Folder.decode(File(filePath).name))"
tell application "Adobe InDesign CC 2015"
do script myScript with arguments myArgs language javascript
end tell

Notice that here each script statement is enclosed in double quotes, and quotes inside of a statement are escaped with a backslash (\).

To write a similar script in ExtendScript for AppleScript is not quite as easy. Folder.desktop in ExtendScript needs to translate to "(path to desktop from user domain) as string" in AppleScript.

if you know the name of the user you could pass in the string equivalent for the path in the argument list:

set filePath to "Macintosh HD:Users:[username]:Desktop:"  --where [userName] is the user's name

In spite of the above, you might be tempted to try the following in ExtendScript:

var argArr = [Folder.desktop + "Test:test.txt"];
var myScript = 'set filePath to ' + ' item 1 of arguments\r';
myScript += 'display alert (\"filePath is \" & filePath)\r';
myScript += 'tell application "Finder"\r';
myScript += 'set aName to name of file filePath\r';
myScript += 'end tell\r';
myScript += 'display alert (\"file name is \" & aName)';
app.doScript (myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, argArr);

Sadly this won't work, as running the script produces an Error message that reads: "Finder got an error: Can't get file "~Desktop:Test:test.txt".

There are several ways you can work around this situation. If you know the folder will be on the user's desktop, you can establish the path to the desktop as part of the do script. This way you only need to pass in the string value of the folder and file name

var myArgs = ["Test:test.txt"];
var myScript = 'set filePath to ((path to desktop from user domain) as string) & item 1 of arguments\r';
myScript += 'tell application \"Finder\"\r';
myScript += 'set aName to name of file filePath\r';
myScript += 'end tell\r';
myScript += 'display alert(\"Name is \" & aName)\r';
app.doScript(myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, myArgs);

Optionally, you could build a text path to the file using AppleScript's System Events application. In the following we will set the label index for the file designated to a number. This sets a color Tag for the file that can be used for a number of reasons such as if the file has been processed.

var myArgs = ["Desktop:Test:test.txt", 5];
var myScript = 'tell application \"System Events\"\r';
myScript += 'set userName to name of current user\r';
myScript += 'end tell\r';
myScript += 'set fPath to \"Macintosh HD:Users:\" & userName & \":\" & (item 1 of arguments)\r';
myScript += 'tell application \"Finder\"\r';
myScript += 'set label index of file fPath to item 2 of arguments\r';
myScript += 'end tell\r';
app.doScript(myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, myArgs);
myScript

Naturally, you will want to add code to the above to make sure the file exists before attempting to access it.

For the last option, you could just have the user choose the file to be processed.This is a variant of the preceding script that sets the label index for the file.

var myArgs = [6];
var myScript = 'set fileRef to choose file\r';
myScript += 'tell application \"Finder\"\r';
myScript += 'set label index of fileRef to item 1 of arguments\r';
myScript += 'end tell\r';
app.doScript(myScript, ScriptLanguage.APPLESCRIPT_LANGUAGE, myArgs);
myScript

Practical Application

Most of the scripts above are simply for demonstration and provide no benefit over what can be done in your preferred language. For those that do provide some practical application, you will need to add error checking, etc. to the script to make sure the code is bullet proof.

This should give you a good idea of how to use arguments to pass information into a do script. Next, we will look at how to get information back from a do script. Until then, think of ways that you could use do script to make your life with InDesign automated.

Trackback Link
http://www.yourscriptdoctor.com/BlogRetrieve.aspx?BlogID=18153&PostID=1462918&A=Trackback
Trackbacks
Post has no trackbacks.

Recent Posts


Tags

PDF security scripting measurement editboxes Border Panel doScript Export to PDF InDesign dialogs Find Change handlers folder metacharacters directory import text object styles InDesign CC Script Preferences Preferences CALS tables styles Caption Variable save template GPS automating InDesign Interactive Publications Nested Styles AppleScript Templates reframe Numbering ePub for Kindle Read text file as list BrdgeTalk dropdowns massage text with timeout image metadata functions Autoflow XML structure CSS Automating animations entire path placeable Create Document Document stylesheets Custom Buttons stylesheets Image Placement script folder Fixed Format ePub text placement Metadata Bullets Fixed Layout ePub automation active spread do script Embed Document images if/then Enabling Groups Styling Text text editbox Create Text Frame Find by Attribute page items watermark measurements GPS metadata pasteboard text concatenation Editbox Media Custom CSS Style Sheets System Events PDF export preferences ePub for iPad Repeat With Sound Apple apps parent script templates Find by Font cut and paste Checkbox Control resolve new document Publish Online selection lists Templates Combobox coordinates Document Presets Radiobutton Group path Character Styles resize user interaction level Export HTML fit transform Mail enable redraw tutorial PDF arrays records file paths Adding Captions Table cells Index of blogs and scripts for year 2016 Text Cleanup Library Folder AppleScript dialogs table styles say Glossary Hyperlinks automated workflow Custom Dialog trimText parent page Choose file Tables AppleScript transformation matrix Find by Color Document from Template Placing images find change options text item delimiters External Object Scripts try/on error integer editboxes Adobe InDesign CC import XML import HTML InDesign template wild cards Change Text Choose from list repeat loops transform again Video paragraph styles HTML Export XML Find Text Excel XML tags

Archive