Automating Adobe InDesign 2017


Managing Script Handlers in AppleScript

Tuesday, September 12, 2017

Handlers for Building AppleScript Scripts

In our previous blog post we demonstrated how a fairly complex script can be put together using a number of handlers (functions). These are pieces of code that perform a very specific functionality, and, once written, can be reused in any number of scripts. For example, think of the number of scripts that might be written for InDesign that would need to verify that a document is open. For that, you could use the following:

(*Returns reference to topmost document. If no document is open, an error is generated*)
on getDocRef()
   tell application "Adobe InDesign CC 2017"
	if (count of documents) = 0 then
	   error "Requires open document with graphics for export."
	end if
	set docRef to document 1
   end tell
   return docRef
end getDocRef

To manage these pieces of code, you could have a folder set aside into which these handlers are stored. Interestingly, Apple has set aside a folder for just this purpose. Let's explore, step by step.

Step One - See How It Works

Start by running your AppleScript editor. Create a new script (Command-N). With a new script open, Control-click (right-click) inside the edit window. This opens the application's contextual menu. You may want to choose to read through the documentation provided when you select About These Scripts from the menu. Importantly, the documentation states, in part, "Control-click the script window, then choose a routine from the pop-up menu; the routine is inserted at the cursor location in the script."

About These Scripts menu item opens documentation page...About These Scripts menu item

To try it out, control-click inside the Script Editor edit window. This will open the editor's contextual menu. When the menu opens, release the Control key. Then select Text Input - 1 Btn from the menu that opens when you select Dialogs.

This will place the code for the handler in your script at the text insertion position. Note: If you continue to hold the Control key down when selecting the handler from the menu, the code will run instead of being added. If you are presented a user interaction dialog instead of code inside your new script, try again; this time release the Control key before selecting the menu item.

Assuming code has been inserted into your script. Enter a prompt for the user between the first set of quotes.

Click on the compile button (hammer) to compile the script.

Lastly, run the script (click the forward-facing triangle or use Command-R). The following dialog should open.

The dialog that shows when the script is run...The dialog presented when the script is run

You may want to explore some of the other handlers provided by Apple. For our purpose, we will create our own folder for our InDesign handlers plus a couple of handlers just for starters.

Step 2: Install Script Menu

For our script handlers, we will want our own InDesign Handlers folder inside the Script Editor Scripts folder. You could open the Script Editor Scripts folder from the contextual menu and work from there. The problem with this method is that you may be asked to enter your password each time you want to make a change or add a new item. This can be annoying. Instead, install the Script Menu for the computer. Here's how.

If you read through the Script Editor Help documentation (see discussion above), there is a link to the Script Menu documentation (Acdess your scripts using the Script menu).In the page that opens you will see the option Show the Script Menu in the menu bar. Opening this option, you will see a simple two-step method. All this assumes that you have a more recent version of the Macintosh OS (Snow Leopard and above). In these later versions, the Script Menu is part of AppleScript Editor's Preferences panel which opens from Script Editor's application menu. In the General panel, you will see checkbox options for showing the script menu in the menu bar and showing computer scripts.

Script Editor Preference panel for showing the Script Menu...General tab in Script Editor Preferences

Step 3: Add Folders to Scripts Menu folder

Once you have the Script Menu installed, you can open its menu by clicking on its icon.

When Script Menu is installed, a script icon shows in Application bar when i...the Script Menu icon in the application bar

Notice when you open the Script Menu you not only get access to the Script Editor Scripts, but also access to prewritten scripts targeted to other applications. You may want to add the Script Editor Scripts folder to your Favorites for easy access when saving files to the folder.

Open the Script Editor Scripts folder. Inside this folder add a folder named InDesign Handlers. Inside this folder add a folder named Dialogs and one named Files-Folders. You are now ready to add a few handlers of your own for Adobe InDesign.

Step 4: Your First Handler

To display a Hello World alert in AppleScript, enter the following in the Script Editor:

activate
display alert "Hello World"

The activate statement makes sure the display appears on top of all other windows. Simple.

Should you want to write a handler that displays any message, a handler is added to the code above. It now reads:

set myMessage to "This is my message"
showMessage(myMessage)

on showMessage(myMessage)
   activate
   display alert myMessage
end showMessage

Remember: If a handler is to be called from inside of a tell statement to Adobe InDesign you need to add a "my" before the call. For the showMessage() handler this would read:

set myMessage to "This is my message"
my showMessage(myMessage)
--handler here

Step 5: See How Apple Does It

For script code to be added to an existing script using AppleScript's contextual menu, it needs to be converted to uncompiled (plain) text. Apple does it by placing this code inside a script that defines the code, and then loads it to the active text insertion point inside the active application.

Often the procedure for writing a new script is to look at one already written that performs a similar functionality. We will follow this procedure for creating our own script files for adding handlers using AppleScript Editor's contextual menu.

For an example, use the Script Editor to open the Text Input - 1 Btn.scpt file we worked with above. (In Script Menu's Script Editor Scripts > Dialogs folder, hold down the Option key and click on Text Input - 1 Btn.scpt.)

Opening a script from the Script Menu...Open a script from the Script Menu

What opens is a script with a lot of code that starts with a copyright comment. Next there are two set statements. The first sets target_string to a dummy default (we won't be using this). The next is the actual text that is inserted into the script. Notice that the code is written as text (inside quotes). As text, any quotes inside the code must be escaped using a backslash.

Next we have a tell statement to the current application (which for our purpose would be Script Editor). Inside the tell statement, the script checks to make sure that there is no text selected (an empty string). If no text is selected, the cursor is loaded with the handler text. For simplicity, we will assume that no text is selected and restrict the behavior of our handler code to simply replacing the empty string with the code for our handler. Once you understand how this works, if you want, you can go on to provide the same full functionality that Apple provides in their file.

Step 6: Create a Simple Template for Your Handlers

To convert compiled code into a plain text file, the process is two-fold:

  1. Create a variable with a commented placeholder inside of quotes:
  2. set scriptText to "
        --paste code here
    "
  3. Next, tell Script Editor (current application) to paste the code at the insertion point.
  4. tell current application
        activate
        tell the front document
           set selectedText to contents of selection
           if selectedText is "" then
              set contents of selection to scriptText
           end if
        end tell
    end tell
  5. Save this code as a template named "Handler Template" to use for future reference.

For our purpose, that's it. You can save the template in the InDesign Handlers folder you created in Step 3 above.

Step 7: Add Your Handler

Now that you have a template, all you need is to add your handler code.

  1. Duplicate your Handler Template.
  2. Copy the code for the showMessage() handler above.
  3. Paste the code where the comment says --paste code here.
  4. Place a backslash before any quotation marks.
  5. Your completed handler code should read as follows:

    set scriptText to "
        set myMessage to \"This is my message\"
        showMessage(myMessage)
    
        on showMessage(myMessage)
           activate
           display alert myMessage
        end showMessage
    "
    tell current application
        activate
        tell the front document
           set selectedText to contents of selection
           if selectedText is "" then
              set contents of selection to scriptText
           end if
        end tell
    end tell

Save the file to the Dialogs folder inside the Script Editor Scripts folder. Name the file Dialog - showMessage.scpt. Note: If you get a message that the script cannot be saved, save the file to your desktop and manually add it to the Script Editor Scripts > Dialogs folder. (You will probably need to enter your administrator password.)

Step 7: Try It Out

Inside Script Editor, start a new script. Use the contextual menu (Control+click) to open the list of handlers. Inside the Dialog folder you should see your Dialog - showMessage file. Select it to add it to your new script.

Compile and run the script. Voila! You now have a code snippet you can add to a script and modify as needed.

Repeat the Process

Now that you see how to work with handlers in Script Menu. Let's try something a little more involved. This time a handler targeted to Adobe InDesign. The getDocRef() handler from our previous blog post is a good candidate for a script handler library. Since the call to this handler will probably be one of the first things a script will do, we can include the try/on error/end try statements as part of the file. Note: If you are using a different version of Adobe InDesign, change the reference to the application in the getDocRef() handler as appropriate.

try
    set docRef to getDocRef()
on error errMsg
    activate
    display alert errMsg
end try
(*Returns reference to frontmost document.
If document does not exist, an error is thrown*)
on getDocRef()
    tell application "Adobe InDesign CC 2017"
        if (count of documents) = 0 then
            error "Requires open document with graphics for export."
        end if
        set docRef to document 1
    end tell
    return docRef
end getDocRef

Open your Handler Template.scpt file (saved as part of Step 5 above). Copy the code for the getDocRef() handler above.

Paste the code into the template so the top part reads as follows: (Make sure you include the ending quotation mark.)

set scriptText to "
    try
        set docRef to getDocRef()
    on error errMsg
        activate
        display alert errMsg
    end try
    (*Returns reference to frontmost document.
    If document does not exist, an error is thrown*)
    on getDocRef()
        tell application \"Adobe InDesign CC 2017\"
            if (count of documents) = 0 then
                error \"Requires an open document.\"
            end if
            set docRef to document 1
        end tell
        return docRef
    end getDocRef
"

Save the file as getDocRef.scpt into your InDesign Handlers > Documents folder (created in Step 3 above).

Try It Out

Create a new script in Script Editor. Control click at the top of the editor panel. From the contextual menu, select the script handler you just saved (InDesign Handlers > Documents > useDocRef.scpt). Compile and run the script. If you have an InDesign document open, you will have a reference to the document in the editor's Result window.

One Last Example

Another handler you may use quite often is one that checks for the path to the parent folder for the open document. Let's see how this would be written as a handler that would use the reference to the document returned from the getDocRef() handler above.

 set docRef to getDocRef()
 set folderRef to getDocumentFolder(docRef)
 (*Returns string reference to parent folder for document referenced.*)
 on getDocumentFolder (docRef)
    tell application "Adobe InDesign CC 2017"
       set folderPath to (file path of docRef as string)
    end tell
 end getDocumentFolder
 --add getDocRef() handler here

Convert the code above to a text script using your Handler Template and save it as getDocumentFolder.scpt in the Files-Folder folder you created above in the Script Editor Scripts > InDesign Handlers folder. (For review: Open your Handler Template file. Duplicate the file. Copy the code for your handler and paste where indicated. Escape all quotation marks in the handler code. Save into Adobe Handlers > Folder - Files.)

Try It

Start a new script. Usig Script Editor's contextual menu, add the getDocRef() code to the script. Next, place the text cursor at the bottom of the script. Control-click and select the getDocumentFolder handler you just saved from Script Editor's contextual menu.

Move both the call to both the getDocRef() handler and the getDocumentFolder() in place of the current call to getDocRef()). The top of your script should read as follows:

try
    set docRef to getDocRef()
    set folderRef to getDocumentFolder(docRef)
on error errMsg
    activate
    display alert errMsg
end try

On Your Own

As you write scripts, you will most likely create handlers that you will see a need for in future scripts. Add them to your Script Editor Scripts library and enjoy saving hours of time as you use these handlers in your scripts.

Onward and Upward

Revisit the code for Apple's Text Input - 1 Btn.scpt file. Determine under what conditions the display_message() handler will be called. What happens if the "Help" button is clicked? What happens if the user clicks the "Continue" button? Determine if you would want to add this functionality to your script handler files. If so, add the code to your handler files accordingly.

Disclaimer: Code samples are to be used as a guide for users in creating their own real world scripts and is provided "AS IS". No representation is made as to the accuracy or completeness of the code. Use of the code and its operation is at the discretion and responsibility of the user.

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

Recent Posts


Tags


Archive