Your prescription for increased productivity and profitability
Our previous blog focused mainly on creating and using paragraph styles. One big advantage of working with paragraph styles is that they can be saved as part of a style file or template to be used in any number of other documents. Here, we will look at some of these applications, but first a short discussion on Character Styles.
When setting up a document that may be used as a style sheet or template in addition to setting up paragraph styles you may want to consider creating a set of character styles. The character styles that are used consistently in most documents can be set up at the application level so once set up they will be part of every document created thereafter. The styles you will want to include are “Italic”, “Bold”, and “BoldItalic”. The example script following sets up these styles with the only attribute included being the Font Style. This way the font styling can be applied to any text irrespective of its size or other attributes.
set cStyleList to {{"Italic", "Italic"}, {"Bold", "Bold"}, {"BoldItalic", "Bold Italic"}} tell application "Adobe InDesign CC 2019" set x to name of character styles repeat with i from 1 to length of cStyleList set theName to item 1 of item i of cStyleList if not (exists character style theName) then set charStyle to make character style with properties {name:theName} else set charStyle to character style theName end if set attribName to item 2 of item i of cStyleList set font style of charStyle to attribName end repeat end tell
For the above, you may ask why a a list of lists was used to define both the name and the font style attribute when {“Italic”, “Bold”, “Bold Italic”} would have sufficed. The reason is that there are other purposes for text styles in which spaces are not permitted, but the font style attribute requires a space.
In creating paragraph styles, you may also want to create an object style that defines a paragraph style as its first (or only) paragraph style. This is particularly useful when the next style property is used to define a styling pattern in which the styles will be applied. Think of documents such as a newsletter where body text always follows after a headline. (See our previous blog post.) Below is an example script that creaes such an object style. The script allows the user to choose the paragraph style for the object style’s first style.
(*Creates object style for text frames having a chained paragraph style sequence*) set badList to {"[No Paragraph Style]", "[Basic Paragraph Style]"} set stylePrompt to "Choose paragraph style name for first style of object style" set promptStr to "Enter name for object style" set falseAsDefault to false set dAnswer to "Chained Styles" try set styleList to getStyleList(badList) set firstStyleName to getNameFromList(styleList, stylePrompt) set styleName to getString(promptStr, falseAsDefault, dAnswer) set objStyleRef to makeObjectStyle(styleName, firstStyleName on error errStr activate display alert "Error: " & errStr end try (*Returns list of paragraph styles having next style property*) on getStyleList(badList) tell application "Adobe InDesign CC 2019" tell document 1 set nextStyles to (name of paragraph styles where name of next style is not in badList) as list if length of nextStyles is greater than 1 then set styleList to rest of nextStyles else error "Requires list of styles having next style property" end if end tell end tell return styleList end getStyleList (*Creates object style for text frames with paragraph style chaining*) on makeObjectStyle(styleName, firstStyleName) tell application "Adobe InDesign CC 2019" tell document 1 set basedOnRef to object style "[Basic Text Frame]" set firstParaStyle to paragraph style firstStyleName if not (exists object style (styleName)) then set styleRef to make object style with properties {name:styleName} else set styleRef to object style styleName end if set properties of styleRef to {based on:basedOnRef, applied paragraph style:firstStyleName, enable paragraph style:true, apply next paragraph style:true} end tell end tell return styleRef end makeObjectStyle (*Dialog for user to select paragraph style by name for first style of chain*) on getNameFromList(styleList, thePrompt) set userChoice to choose from list styleList with prompt thePrompt if userChoice is not false then return item 1 of userChoice else error "User cancelled" end if end getNameFromList (*Gets string response from user; otherwise throws error*) on getString(promptStr, falseAsDefault, dAnswer) set errStr to "" if falseAsDefault then set dButton to 2 else set dButton to 1 end if set userResponse to display dialog promptStr default answer dAnswer default button dButton if text returned of userResponse = "" then error "Valid string not entered" end if return text returned of userResponse end getString
Notice this script has a main (top) section that calls four handlers:
getStyleList returns list of paragraph styles for document having next style property
getNameFromList presents user with list of paragraph styles to use for the first style in style pattern (“chain”)
getString presents user with dialog for entering name for object style
makeObjectStyle creates an object style for text frames with Next Style enabled.
You could make the script somewhat more user friendly by using a custom dialog in place of the two dialogs.
Try the script with a document that has one or more styles defined using the Next Style property. After creating the object style, add a text frame to the document, apply the object style, and enter in some text using a hard return after each paragraph.
Instead o selecting the object style from the Object Styles panel (or using Quick Apply), you may want to use a script to apply the object to a text frame. This could be part of a script such as the following which, with a text frame selected, has the user choose a text file. The script then imports the file into the selected text frame, and applies the object style. This script is similar to an example in our previous blog post.
set stylePrompt to "Select name of Object Style to use" set filePrompt to "Choose text file to place" set classType to «class txtf» try set frameRef to selectedPageItem(classType) set styleNames to getStyleNames() set objStyleName to getNameFromList(styleNames, stylePrompt) importAndStyleText(filePrompt, frameRef, objStyleName) on error errStr activate display alert "Error " & errStr end try (*Places text file to selected frame and applies object style*) on importAndStyleText(filePrompt, frameRef, objStyleName) set fileRef to choose file with prompt filePrompt if (name extension of (info for fileRef) is not "txt") then error "Requires file with \"txt\" extension" end if tell application "Adobe InDesign CC 2019" tell document 1 set objStyleRef to object style objStyleName tell frameRef place fileRef apply object style using objStyleRef with clearing overrides end tell end tell end tell end importAndStyleText (*Returns reference to text frame selected. If no selection throws error*) on selectedPageItem(classType) tell application "Adobe InDesign CC 2019" set selList to selection if selection is not {} and (class of item 1 of selList is classType) then set selItem to item 1 of selection else activate error "Requires page item of class " & classType & " selected" end if end tell end selectedPageItem (*Returns list of object styles in document other than the first four default styes*) on getStyleNames() tell application "Adobe InDesign CC 2019" tell document 1 if (count of object styles) < 5 then error "Requires document with object styles other than default defined" end if set objStyleNames to (name of object styles where index > 4) end tell end tell return objStyleNames end getStyleNames (*Dialog for user to select paragraph style by name for first style of chain*) on getNameFromList(styleList, thePrompt) set userChoice to choose from list styleList with prompt thePrompt if userChoice is not false then return item 1 of userChoice else error "User cancelled" end if end getNameFromList
One big difference with this script is that the code for selecting the text frame is part of a handler. Because the script calls the handler from outside of InDesign, it needs to use the four letter code for a text frame («class txtf»). This brings up several items for discussion:
In more recent versions of InDesign, the class for a text frame is now text field. You can verify this with the following:
tell application "Adobe InDesign CC 2019" set selList to selection get class of item 1 of selList end tell
Not sure when this changed, but InDesign CC 2015 (which I still have on an older machine) returns text frame. However, scripts still refer to the page item as a text frame:
tell application "Adobe InDesign CC 2019" get geometric bounds of text frame 1 of page 1 of document 1 end tell
Internally, AppleScript targets objects using a class definition inside of chevrons (option and option plus shift on the backslash key). Using the four letter code for a text frame «class txtf» insures the script will work for a text frame class irrespective of which version of InDesign you are using. Additionally, as the above script demonstrates, using a four letter code allows a script to reference a class outside of a tell statement to InDesign.
Once you have a document with text and object styles (and perhaps table and cell styles), save it in a handy folder somewhere on your computer. The following script uses a folder named “Styles” inside the Application’s folder. You may need to come up with a different folder path if you don’t have administration privileges. The script imports text and object styles to the active document.
set thePrompt to "Click button for import style option" set filePrompt to "Select source file for style import" try set docRef to getDocument() set userChoice to display dialog thePrompt buttons {"Text and Object Styles", "All Styles", "Cancel"} default button 1 set buttonChoice to button returned of userChoice set sourceFile to getStyleFile(filePrompt) importStyles(docRef, sourceFile, buttonChoice) on error errStr activate display alert "Error: " & errStr end try (*Choose file used to get reference to file for importing styles*) on getStyleFile(filePrompt) tell application "Adobe InDesign CC 2019" set appPath to file path as string end tell set folderPath to appPath & "Styles:" set dLocation to folderPath as alias set fileChoice to choose file with prompt filePrompt default location dLocation without invisibles return fileChoice end getStyleFile (*Imports styles based on choice made in dialog from file chosen*) on importStyles(docRef, sourceFile, buttonChoice) tell application "Adobe InDesign CC 2019" tell docRef if buttonChoice is "All Styles" then import styles format table styles format from sourceFile import styles format text styles format from sourceFile else --clicking Cancel would throw an error import styles format object styles format from sourceFile end if end tell end tell end importStyles (*Checks for application modal state and returns reference to document if it exists*) on getDocument() tell application "Adobe InDesign CC 2019" if modal state is true then error "Please close modal windows and try again" end if if (count of documents) = 0 then error "Requires an open document." end if set docRef to document 1 end tell return docRef end getDocument
Did you notice in the scripts above that the handlers were written to “handle” specific functionalities. This way, handlers can be mixed and matched to be used in any number of scripts with very little modification, if any. For instance, you might want to create a script that imports styles to a new document and applies the text from a chosen text file to a text frame created by the script. Handlers used in the script above could be part of that script. We will look into this in our next blog post. .