Your prescription for increased productivity and profitability
If you have created scripts having a custom dialog you know that the code can be quite involved. For instance, having to create a row, then a column, and then a user interface element can take up a few lines of code to say the least. You can eliminate some of the code and redundancy by having a few coding tricks up your sleeve. In this discussion we will look at a few:
Instead of:
tell application "Adobe InDesign CC 2014" set dlgRef to make dialog with properties {name:"Test Dialog", can cancel:true, label:""} tell dlgRef set mColumn to make dialog column tell mColumn set mRow to make dialog row end tell tell mRow make static text with properties {static label:"Name:"} set nameField to make text editbox with properties {min width:200} end tell --mRow end tell --dlgRef set userResponse to show dlgRef destroy dlgRef end tell
You can write:
tell application "Adobe InDesign CC 2014" set dlgRef to make dialog with properties {name:"Test Dialog", can cancel:true, label:""} tell dlgRef tell (make dialog column) tell (make dialog row) make static text with properties {static label:"Name:"} set nameField to make text editbox with properties {min width:200, edit contents:""} end tell end tell end tell set userResponse to show dlgRef destroy dlgRef end tell
Test Dialog
Nesting tell statements in this manner results in a savings of 2 lines of code and having to create 2 additional variables. The only time a variable is created is when an object reference is needed later in the code.
If you have a number of fields that are similar, use a repeat loop to create the fields. To reference the field later in the code, create either a name or object reference as part of its make statement. The following illustrates using a list to hold a reference to the text fields.
set textFields to {} --list to hold object references set fieldList to {"First Name:", "Last Name", "Address:", "Address 2:", "City:", "Zip Code:"} tell application "Adobe InDesign CC 2014" set dlgRef to make dialog with properties {name:"Test Dialog", can cancel:true, label:""} tell dlgRef tell (make dialog column) tell (make dialog row) set col1 to make dialog column set col2 to make dialog column end tell repeat with i from 1 to length of fieldList tell col1 make static text with properties {static label:(item i of fieldList)} end tell tell col2 set end of textFields to make text editbox with properties {min width:200, edit contents:""} end tell end repeat end tell --dialog column end tell --dlgRef set userResponse to show dlgRef destroy dlgRef end tell
Writing just this much code will allow you to test and see how your interface will look before you start adding all of the rest.
In running the code above, if the result of the variable userResponse is true the values can be returned using a similar loop construct. Add the following in place of the last two statements in the code above, and test filling in the text fields, and clicking OK.
if userResponse is true then set stringValues to {} repeat with eachItem in textFields set end of stringValues to edit contents of eachItem end repeat end if destroy dlgRef end tell stringValues
If you attempted to test the code above and got an error instead of a dialog, the problem may be that script preferences need to be set. To finish off the custom dialog you need to make sure the user interaction level for script preferences is set to interact with all. As with other application preferences, the good neighbor policy is to place values for existing preferences in a variable before changing, then restoring the original value when you are through.
After the tell application statement in the code above, add the following:
set origPrefs to user interaction level of script preferences set user interaction level of script preferences to interact with all
Then after the destroy dlgRef statement in the code above add:
set user interaction level of script preferences to origPrefs
There is just one more thing you need to do to make the code useable. You need to take care of the problem that will arise if the user presses the Cancel button. Just to test, run the script as it now stands and press the Cancel button.
The best way to handle the problem is to generate an error if the value of userResponse is not true and handle the error in a try/end try block.
It would be nice if we could just add an else statement to the if userResponse is true statement. But we can’t simply because the destroy dlgRef statement needs to occur in either event (userResponse is true or false).
For this you will need to test for the value of userResponse after destroying the dialog. Have the script throw an error if true, or return the dialog result if false.
After the set user interaction level statement at the bottom of the script, add the following:
--notice the first line is a one line if statement if userResponse is false then error "User Cancelled" --if userResponse is true the code gets to the next line return stringValues --end tell statement follows
Of course your script now needs to handle the error that is generated if the user cancels. To do this, you can place the custom dialog code in a handler and call the handler from within a try statement.
The script will now read as follows:
set fieldList to {"First Name:", "Last Name:", "Address:", "Address 2:", "City:", "Zip Code:"} set dialogName to "Test Dialog" try set userResponse to userDialog (dialogName, fieldList, true) on error errStr activate display alert "Error: " & errStr end try --Handler for custom dialog on userDialog (dialogName, fieldList, canCancel) set textFields to {} --add the rest of the code from above here end userDialog
Test this out to make sure the script works as expected.
Dialog elements created using repeat loop
Once a dialog is created using the show command, it remains in memory until destroyed. While you have been working with your script, you may have left a few dialogs in memory along the way. To test for this you may want to use the following:
tell application "Adobe InDesign CC 2014" set dialogCount to count of dialogs set theName to (name of dialog (dialogCount)) destroy dialog dialogCount set dialogCount to count of dialogs end tell dialogCount
or simply
tell application "Adobe InDesign CC 2014" set dialogCount to count of dialogs if dialogCount > 0 then destroy dialogs end if set dialogCount to count of dialogs --just to make sure end tell dialogCount --should be 0
You may want to improve the appearance of your custom dialog by varying the widths of the text editboxes. This can be done easily by changing the fieldList to a list of lists where the first value in each of its lists is the title for the field, and the second is its width. You could even place default values in the fields by adding a third item to each list inside the fieldList. For dialog elements other than text fields (perhaps a drop down for choosing a State: code), these will need to be created outside of the text field loop.
In our next installation we will look at some AppleScript commands that you may want to incorporate to give even more usability to your custom dialog .