Automating Adobe InDesign 2019 - AppleScript


Lists II

Tuesday, April 09, 2019

In this post we will look at some of the issues surrounding working with lists. Knowing the ins and outs of lists is paramont when writing scripts to automate Adobe InDesign. For instance the following will return a list of the rectangles found on a page:

tell application "Adobe InDesign CC 2019"
   tell page 1 of document 1
	set aList to every rectangle 
   end tell
end tell
aList

In running the above, if no rectangles are found, the value of aList will be an empty list.

Should you want to get the geometric bounds of every rectangle, the following will throw an error when no items are found.

tell application "Adobe InDesign CC 2019"
   tell page 1 of document 1
	set aList to geometric bounds of every rectangle 
   end tell
end tell

To prevent this error, two approaches can be used: (1) put the statement inside a try statement block:

tell application "Adobe InDesign CC 2019"
  tell page 1 of document 1
	try
	   set aList to geometric bounds of every rectangle
	end try
   end tell
end tell
aList --the value returned will be an empty list

(2) Get the count of items before using the every statement

set aList to {}
tell application "Adobe InDesign CC 2019"
   tell page 1 of document 1
	if (count of rectangles) > 0 then
	   set aList to geometric bounds of every rectangle
	end if
   end tell
end tell
aList 

Notice in this second example getting the value for aList at the end of the script would produce an error if the variable has not been initialized.

Selection

The result of a selection is a list.

tell application "Adobe InDesign CC 2019"
    set aList to selection
end tell

As with the above, a script needs to verify there is a selection before trying to get an item from the list or any item properties:

tell application "Adobe InDesign CC 2019"
    if selection is not {} then
	set selItem to item 1 of selection
    end if
end tell

Similarly, trying to get properties from a selection will produce an error if the list is empty

tell application "Adobe InDesign CC 2019"
    if selection is not {} then
	set aList to geometric bounds of every item of selection
    end if
end tell

List of Lists

In running the code above, if there is more than one rectangle on the page as expected, a list of lists is returned similar to the following:

{{423.36, 161.28, 578.88, 482.4}, {207.0, 161.28, 381.6, 482.4}, {36.0, 146.88, 167.04, 491.04}}

Notice that the geometric bounds for the rectangles are each list items separated by commas within the parent list.

However if there is only one recrangle on the page, the value of the list is not a list of lists but a single list of the item's geometric bounds:

{423.36, 161.28, 578.88, 482.4}

To keep the script from falling into this error, your script might want to test for one item as well as no items:

set aList to {}
tell application "Adobe InDesign CC 2019"
   tell page 1 of document 1
	if (count of rectangles) = 1 then
	    set end of aList to geometric bounds of rectangle 1
	else if ((count of rectangles) > 0) then
	    set aList to geometric bounds of every rectangle
	end if
    end tell
end tell
aList

Of course, you could always use a repeat loop to do the same:

set aList to {}
tell application "Adobe InDesign CC 2019"
    tell page 1 of document 1
	repeat with i from 1 to (count of rectangles)
		set end of aList to geometric bounds of rectangle i
	end repeat
    end tell
end tell
aList

The advantage of using every is that every item can serve as the object of a tell statement:

tell application "Adobe InDesign CC 2019"
  tell page 1 of document 1
	tell every rectangle
	    set fill color to "Black"
	    set fill tint to 50
	end tell
    end tell
end tell

Copy Versus Set

One place that working with lists can cause some consternation is in using set and copy. For the most part, there is little difference.

set aList to {1, 2, 3}
    set end of aList to 4
aList --Result is {1, 2, 3, 4}

Change the second line of the above to use copy instead of set:

copy 4 to end of aList

The result is the same.

But should you have the need to duplicate a list, the difference between using set instead of copy can make all a script fail. For instance, suppose you want a second list of numbers to be the same as the first but incremented by a value of 100. You might write:

set myList to {102, 202, 303}
set dupList to myList
repeat with i from 1 to length of dupList
	set item i of dupList to (item i of dupList) + 100
end repeat
{myList, dupList}

The Result is that both lists end up being the same: {{202, 302, 403}, {202, 302, 403}}

Instead, using copy, the result will be as anticipated:

set myList to {102, 202, 303}
copy myList to dupList
repeat with i from 1 to length of dupList
   set item i of dupList to (item i of dupList) + 100
end repeat
{myList, dupList}

The result will be two unique lists as anticipated: {{102, 202, 303}, {202, 302, 403}}

The problem is that set does not create a new list but assigns a reference of the first list to a second variable. When a value in the first list changes, the second does the same.

Text Item Delimiters

A script can coerce any single item into a list using as list.

set myList to "Now is the time" as list
Result is {"Now is the time"}

Using AppleScript's text item delimiters, a script can get a variety of results depending on the need.

By default, AppleScript's text item delimiters is set to an empty string. With this, all of the characters in a string can be coerced into a list.

set myText to "Now is the time"
set myList to text items of myText
myList --Result is {"N", "o", "w", " ", "i", "s", " ", "t", "h", "e", " ", "t", "i", "m", "e"}

Change the value for AppleScript's text item delimiters to a space and the result is entirely different:

set AppleScript's text item delimiters to " "
set myText to "Now is the time"
set myList to text items of myText
set AppleScript's text item delimiters to ""
myList --Result is {"Now", "is", "the", "time"}

Important: Remember to return the value of AppleScript's text item delimiters back to its previous setting after using.

Using text item delimiters comes in handy for getting items from a string. For instance, when you use the choose command to get a path to a file, the items in the path are separated with colons:

set thePath to choose file as string

The result will be similar to: "Macintosh HD:Users:userName:Desktop:Filename.docx"

An easy way to get the name of the file is to use text items with the delimiter set to the colon:

set thePath to (choose file) as string
set AppleScript's text item delimiters to ":"
set fileName to item -1 of (text items of thePath)
set AppleScript's text item delimiters to ""
fileName

To remove a word from a string you can use text item delimiters. But be aware, every word matching the delimiter will be removed.

set origText to "All good people must be there"
set AppleScript's text item delimiters to "good "
set myList to text items of origText
set AppleScript's text item delimiters to ""
myList as text

Notice that the delimiter "good " in the above includes a word space. Without that, the occurrence of good inside of a word would also be removed. Try the above with the delimiter set to "good" (without the space) and the value for origText to "Goodness knows, most good people will be there".

Onward and Upward

You might want to experiment using text item delimiters for creating lists and parsing tab-delimited strings.

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=1528890&A=Trackback
Trackbacks
Post has no trackbacks.

Recent Posts


Tags


Archive