Automating Adobe InDesign 2019 - AppleScript


Taking Time for Time

Tuesday, July 23, 2019

Time to Look at Time

The big reason why people write and use scripts is to save time. Sure, it takes time to write a sript but over the long haul the time saved should reap big rewards. What often amazes me is just how quickly the computer can process a page or many pages of code. Mind blowing!

Time Lapse

To see how long it takes a script to run you can put the following at the top of the script:

set startTime to (current date)

Then put the following at the end:

set timeLapse to (current date) - startTime
activate
display alert ("Time lapsed:  " & timeLapse)

Just for fun I recently put these lines on a script that produces an 11x17 calendar from a template: Twelve pages with twelve images and twelve tables. The script took a total of 18 seconds with most of the time I am sure in how long it took me to locate the folder of images to be placed.

One big time saver in an InDesign script that has a fair amount of work to do in a document is to hide the screen display. This eliminates the time it takes to update the display. Makes sense!

Showing Window

The following sample script hides the screen display when it opens or creates a document from a template selected by the user. (Note: Requires a template saved to a folder named Templates inside the InDesign application folder.)

Doc From Template

set savePrompt to "Select folder and enter file name for save"
try
tell application "Adobe InDesign CC 2019"
   set appPath to file path as string
   set templateFolder to appPath & "templates"
   set templatePath to my getFile(templateFolder)
   set docRef to open file templatePath without showing window
   --statements to process the document then display the window
   tell docRef to make window
   --save the document
   set savePath to choose file name with prompt savePrompt
   save docRef to savePath without force save
end tell
on error errStr
   activate
   display alert ("Error: " & errStr)
end try
(*Returns path to file selected from folder identified by folderPath*)
on getFile(folderPath)
   set fileList to list folder folderPath without invisibles
   set userResponse to choose from list fileList
   if userResponse is not false then
      set fileChosen to item 1 of userResponse
      return folderPath & ":" & fileChosen
   else
      error "User did not select a file"
   end if
end getFile

If the script will take more than a second or two to do its job you might want to let the user know that the script is working. Without a window displaying, the user may panic and think there was a problem with the script. Sadly, as far as I know, InDesign does not have the capability of displaying a floating window with AppleScript but we can use JavaScript to do the work for us. We do this with do script.

Floating Window - Do Script

Do script is InDesign's way of allowing code in a different language to be used. For the purpose of creating a floating window in an AppleScript script do script comes to the rescue in allowing our script to target JavaScript.

Script Is Working

tell application "Adobe InDesign CC 2019"
	set docRef to make document without showing window
	--puts a floating window to the screen
	set startScript to my getStartScript()
	do script startScript language javascript
	tell docRef
		--statements that work with the document
	end tell
	--now to close the window
	set endScript to my getEndScript()
	do script endScript language javascript
	tell docRef to make window
	set active page of active window to page 1 of docRef
end tell
--javascript code to create floating window telling user the script is running
on getStartScript()
   set js to "#targetengine \"session\"" & return
   set js to js & "w = new Window ('palette', ' ');" & return
   set js to js & "var myText = w.add('statictext', undefined, 'WORKING...Please be patient');" & return
   set js to js & "app.activate();" & return
   set js to js & "w.show();"
   return js
end getStartScript
--javascript code to close floating window
on getEndScript()
set es to "#targetengine \"session\"" & return
set es to es & "w.hide();" & return
return es
end getEndScript

Image of floating window telling user that script is working...Script is Working window

Interestingly, I have found very few scripts that would need this capability. This of course depends on the speed of the particular computer running the script. On the other hand, protecting a script from failing because of a user error is a more common issue.

User Error

The most common error a script needs to trap is the user clicking a Cancel button instead of performing the intended instruction. If nothing else, surround your script with a try/on error trap to catch this and any other user-centered error.

try 
  --script statements
on error errStr
   activate
   display alert ("Error: " & errStr)
end try

One common error that pops up when a user gets distracted or otherwise takes longer than anticipated to respond is a timeout error. 

Timeout Error window displays when application response exceeds timeout value...Timeout error display

Most commonly this happens when a choose method such as choose folder or choose file is issued within a tell statement to an application such as InDesign. In this instance, AppleScript, by default, gives the application statement 120 seconds for a response. For most purposes this is ample time, but to be safe you will want to extend the timeout to three minutes (or more) by surrounding problematic statements with a timeout block.

with timeout of 300 seconds
  --something the user might take a long time to do
end timeout 

To trap a timeout error test the number returned from the error.

Timeout Error

set promptStr to "Select folder for images"
try
   with timeout of 300 seconds
      tell application "Adobe InDesign CC 2019"	
      set folderChosen to choose folder with prompt promptStr
	--statements that work with files in folder
      end tell
   end timeout
on error errStr number errorNumber
   if errorNumber is -1712 then
	activate
	display dialog "User exceeded allowed time for response" giving up after 10
   end if
end try

Notice the giving up after parameter added to the display dialog statement above with 10 (seconds) as its value. This automatically closes the error dialog when the time (in seconds) is reached. Giving up after also works with display alert.

The problem with the above is that the original choose folder window stays around until physically dismissed. You can, however, modify the code above to close the choose folder window programmatically. Modify the code for the script Timeout Error above to read as follows:

set promptStr to "Select folder for images"
tell application "Adobe InDesign CC 2019"
   with timeout of 300 seconds
	try
	   set folderChosen to choose folder with prompt promptStr
	on error errStr number errorNumber
	   if errorNumber is -1712 then
	      activate
	      display dialog "User exceeded allowed time for response" giving up after 10
	      my closeWindow("Choose a Folder")
           else
              display dialog "Error: " & errStr giving up after 10
	   end if
	end try
   end timeout
end tell
on closeWindow(windowName)
   tell application "System Events" to tell process "Adobe InDesign CC 2019"
	click (button "Cancel" of window windowName)
   end tell
end closeWindow

This works similarly when working with display dialog,

Closing Display Dialog

Should you wish to close a display dialog window when a script exits with a timeout error, you first need to identify the window. This is done by defining its label value. The label value becomes the name reference for a click button statement. The sample script below uses try/on error to trap a display dialog timeout error. The user is given a message that closes after 10 seconds. The display dialog is then closed programmatically.

Close Window on Timeout

set closeWindow to false
tell application "Adobe InDesign CC 2019"
   with timeout of 300 seconds
      try
          set userResponse to display dialog "Enter your name" default answer "John Jones" with title "Enter Name"  
      on error errStr number errorNumber
         if errorNumber is -1712 then --timeout error
            set errStr to "User exceeded allowed time for response"
            set closeWindow to true
         end if
         activate
         display alert "Error: " & errStr giving up after 10
      end try
   end timeout
end tell
if closeWindow then
   tell application "System Events" to tell process "Adobe InDesign CC 2019"
      if exists (button "OK" of window "Enter Name") then
         click (button "OK" of window "Enter Name")
      end if
   end tell
end if

Display Dialog showing label at top of the window...Display Dialog with Label

Notice that the label of the display dialog window displays in its title bar.

Note: Methods for closing windows has changed with system releases. The methods shown above were tested with Mojave version 10.14.5.

Above and Beyond

Make sure you to extend the timeout value for your scripts that require user input, especially custom dialogs. And, if a timeout error raises its head, notify the user. Be aware of instances that can cause errors in your code when working with the user and set up traps to catch those errors.

Disclaimer:
Scripts provided are for demonstration and educational purposes. No representation is made as to their accuracy or completeness. Readers are advised to use the code at their own risk.

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

Recent Posts


Tags


Archive