LISTS

In creating a script for InDesign that will require the user to choose an item from a list, a number of methods an be used in AppleScript. The demonstration script below has CHOOSE FROM LIST as part of the getNameFromList() handler. The script assumes that document presets have been created with a Web or Mobile label if not print intent. (See previous blog post.)

Get Document Preset

set presetPrompt to "Select preset for new document"
try
    set myList to getPresets(1) --
    set presetName to getNameFromList(myList, presetPrompt)
on error errStr
    display alert ("Error: " & errStr)
end try
(*Returns list of names for document presets having intnet designated by list index*)
on getPresets(intentIndex)
    tell application "Adobe InDesign CC 2019"
	if intentIndex is 1 then
	    set fullList to (name of document presets where intent is print intent)
	    set fullList to rest of fullList
	else if intentIndex is 2 then
	    set fullList to (name of document presets where label is "Web")
	else if intentIndex is 3 then
	    set fullList to (name of document presets where label is "Mobile")
	end if
    end tell
    return fullList
end getPresets
(*dialog for user to select item from list*)
on getNameFromList(theList, thePrompt)
    set userChoice to choose from list theList with prompt thePrompt
    if userChoice is not false then
	return item 1 of userChoice
    else
	error "User cancelled"
    end if
end getNameFromList

LIST BASICS

For AppleScript a collection of items is represented by a list. You might want to think of a list as a box: the box can be empty, or it can contain any number of items. An empty list is represented by a pair of curly brackets. In InDesign, if no selection is made in the open document, the following will return an empty list.

tell application "Adobe InDesign CC 2019"
   set mySelection to selection
end tell
mySelection --result is {} 

A script creates a list by assigning a variable to a pair of empty braces.

set myList to {}

A script can create a list with any number of items by placing the items, separated by commas within the curly brackets. In AppleScript these items can be of different types.

set myList to {1, 2, "cherry", "vanilla", 1.4} 
set myClass to class of item 2 of myList
--result is integer

Try this code with different values for the item index number.

A script can add items to a list by using the syntax end.

set myList to {}
set end of myList to "chocolate"
set end of myList to "vanilla"
myList --result is {"chocolate", "vanila"}

You can also use beginning to add an item to a list:

set myList to {}
set end of myList to "chocolate"
set beginning of myList to "vanilla"
myList --result is {"vanilla", "chocolate"}

As in above, using end of or beginning of is the most efficient way to add an item to a list You can also add an item to a list using the concatenation operator (&).

set myList to {"cherry"}
set myList to myList & {"chocolate"}
myList
--result is {"cherry", "chocolate"}

Another way of adding items to a list is to use the concatenation (&) operator.

set myList to {}
set mList to myList & 123
--result is {123}

Interestingly, the concatenation operation can be used to add a number of items to a list.

set myList to {}
set mList to myList & 1 & 2 & 3
--result is {1, 2, 3}

The concatenation operator can even be used to create a list with list items.

set myList to 1 & 2 & 3
myList
--result is {1,2,3}

A list can contain another list. This is known as a list of lists. To add a list to another list, use end or beginning. In the following the list {4, 5, 6} is added as a list.

set myList to {1, 2, 3}
set end of myList to {4, 5, 6}
myList --result is {1, 2, 3, {4, 5, 6}}

Be careful. When using the concatenation operator to add a list to a list, the items in the added list are added as items, not as a list.

set myList to {1, 2, 3}
set myList to myList & {4, 5, 6}
myList --result is {1, 2 ,3, 4, 5, 6}

ITEMS WITHIN A LIST

The individual items in a list are defined by their position within the list.

set myList to {"cherry", "vanilla", "chocolate"}
set myChoice to item 3 of myList
myChoice
--result is "chocolate"

Notice that item positions in a list (indexes) begins with 1, not 0 as in other languages such as JavaScript.

In AppleScript other references can be used to target items within the list. These include: last, first, middle, and some.: For the myChoice variable in the code above, instead of item 3 try one of the following:

first item of myList
--result is "cherry"
last item of myList
--result is "chocolate"
middle item of myList
--result is "vanilla"

It is well to note that if there is an even number of items in the list “middle’ will return the item to the left of center.

set myList to {"cherry", "vanilla", "caramel", "chocolate"}
set myChoice to middle item of myList
myChoice--returns "vanilla"

And, just for fun (or randomness), a script can use some to return an item from a list.

set myList to {"cherry", "vanilla", "caramel", "chocolate"}
set myChoice to some item of myList
myChoice --result is any item in the list

Finally, you can get a range of items in a list by using the thru operator.

set myList to {"cherry", "vanilla", "caramel", "chocolate"}
set myItems to items 2 thru 3 of myList
myItems --result is { "vanilla", "caramel"}

Using the range technique shown above is the principal way to remove an item, or items, from a list.

set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
set myList to items 1 thru 2 of myList & items 4 thru (length of myList) of myList
myList --result is {"cherry", "vanilla", "chocolate", "mint"}

To remove items from the end of a list, you can use a negative index value with the thru operator.

set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
set myList to items 1 thru -2 of myList
--result is {"cherry" "vanilla", "caramel", "chocolate"}

To remove the first item from a list, rest can be used.

set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
set myList to rest of myList
--result is {"vanilla", "caramel", "chocolate", "mint"}

LIST PROPERTIES

The number of items in a list is returned using the length property of the list.

set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
set myNumber to length of myList
--result is 5

The rest of a list is all of its items with exception of the first item.

set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
set myList to rest of myList
myList --result is {"vanilla", "caramel", "chocolate", "mint"}

In addition to properties length and restreverse returns the list in reverse order (what else?).

set myList to {1, 3, 5, 7, 9}
set myList to reverse of myList
myList --result is {9, 7, 5, 3, 1}

PARSING A LIST

To find an item within a list a repeat with is often used.

set myChoice to "chocolate"
set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
repeat with i from 1 to length of myList
    if item i of myList is myChoice then
	set myItem to i
	exit repeat
    end if
end repeat
myChoice & " is item " & myItem & " of the list."
--result is "chocolate is item 4 of the list"

Instead, the rest property of a list can be used. It is most advantageous when doing a search within a very long list. The reason is that the list to parse becomes shorter with each iteration.

set myChoice to "chocolate"
set myCount to 0
set myList to {"cherry", "vanilla", "caramel", "chocolate", "mint"}
repeat while myList is not {}
    set thisItem to item 1 of myList
    if thisItem is myChoice then
	set thisCount to myCount + 1
        exit repeat
    end if
    set myCount to myCount + 1
    set myList to rest of myList
end repeat
set myString to "" & myChoice & " is item " & thisCount & " of the list items"
myString --result is "chocolate is item 4 of the list items"

Working with items in a list can pose a few problems when working with InDesign. For the following it will be assumed that a selected text frame in InDesign’s open document has a number of paragraphs the first three of which begin with the words “One”, “Two”, and “Three” respectively. A script to change the first letter of the sequential paragraphs will demonstrate. 

Change Size_First Letter

In reading through the code below, one would think that the script would work.

tell application "Adobe InDesign CC 2019"
   set selList to selection
   if selList is not {} and class of item 1 of selList is text frame then
	set frameRef to item 1 of selList
	tell frameRef
	    set theCount to count of paragraphs
	    repeat with i from 1 to theCount
		set thisParagraph to  paragraph i
		set point size of character 1 of word 1 of thisParagraph to "24 pt"
	    end repeat
	end tell
    end if
end tell
selList --Will return value of selList or force error 

Instead, the result of the error reads “Can’t set size of \”O\” to 24…

The problem is the value of the variable thisParagraph is the text of the paragraph, not a reference to the paragraph object.

To fix this, change the offending line (the one that establishes the value of the variable thisParagraph) to read:

    set thisParagraph to (a reference to paragraph i)

Run the script. The first character of each paragraph is changed without an error.

Alternatively, you could write the script to repeat the list using a reference to the item itself:

tell application "Adobe InDesign CC 2019"
    set selList to selection
    if selList is not {} and class of item 1 of selList is text frame then
	set frameRef to item 1 of selList
	tell frameRef
	    set theList to a reference to every paragraph
	    repeat with eachItem in theList
		set point size of character 1 of eachItem to "24 pt"
	    end repeat
	end tell
    end if
end tell

In this example, the value of the variable eachItem takes on the value of the next item in the list until the list is empty.

UPWARD AND ONWARD

Understanding how to work with lists is fundamental with AppleScript as it provides a wealth of ways to automate objects in the operating system as well as items in applications such as Adobe InDesign. Next week, we dive a little deeper into working with lists and lists of lists.