Your prescription for increased productivity and profitability
One of the most popular of the sample scripts provided by Adobe for InDesign is FindChangeByList. The script is designed for the non-scripter in that the parameters for find/change procedures are supplied by a plain text file. This is then read by the script for performing the find/change. Each line of the text file consists of a set of 5 find/change attributes delineated by a tab.
The attributes in order are:
At the top of the script the author provides a few examples of a typical find/change entry in the text file:
--Very simple example: --text {find what:"--"} {change to:"^_"} {include footnotes:true, include master pages:true, include hidden layers:true, whole word:false} Find all double dashes and replace with an em dash. -- --More complex example: --text {find what:"^9^9.^9^9"} {applied character style:"price"} {include footnotes:true, include master pages:true, include hidden layers:true, whole word:false} Find $10.00 to $99.99 and apply the character style "price".
Note the use of meta characters in the second example above.
The script reads the text file and uses the information to perform the find/change procedures. The scope of the find/change is defined by the user. If a text item, text frame, or insertion point is selected when the script is run, the user is given the option of targeting the entire document or the selection. In the event of a text frame or insertion point, this will be its parent story. This option is provided by a custom dialog which provides the following choices:
As a person interested in writing scripts, you may want to look at this sample script to see how it was written. Even better, you might want to write your own script and avoid the hassle of having to create a separate text file each time you want to do a find/change. For this, instead of creating a text file, provide the list of find/change parameters at the top of the script.
For a script designed to find and change a string of text, the list could be defined as follows. Note that the last item in the parameter list is itself a list of true/false values for the following, in order: include footnotes, include master pages, include hidden layers, whole word.
set myFindChangeList to {"text", {find what:"text to find"}, {change to:"text to replace"}, {true, false, false, true}}
Your script will then need to perform the following:
To demonstrate how this could be done, the following skeleton for the proposed script is provided:
tell application "Adobe InDesign CC 2015" set myFindChangeList to {"text", {find what:"aid of their country"}, {change to:"assistance of their leaders"}, {true, false, false, true}} set objRef to my getTargetObject() copy myFindChangeList to {searchType, findRecord, changeRecord, optionList} if searchType is "text" then my doFindChangeText (objRef, findRecord, changeRecord, optionList) end if end tell (*Handler performs actual find/change*) on doFindChangeText (objRef, findRecord, changeRecord, optionList) tell application "Adobe InDesign CC 2015" set find text preferences to nothing set change text preferences to nothing set properties of find text preferences to findRecord set properties of change text preferences to changeRecord my setOptions (optionList) tell objRef set myFoundItems to find text if myFoundItems is not {} then change text end if end tell end tell return myFoundItems end doFindChangeText (*Handler sets options for find/change*) on setOptions (optionList) tell application "Adobe InDesign CC 2015" tell find change text options set include footnotes to item 1 of optionList set include master pages to item 2 of optionList set include hidden layers to item 3 of optionList set whole word to item 4 of optionList end tell end tell end setOptions (*returns object for performing find change; assumes complete document is target for range*) on getTargetObject() tell application "Adobe InDesign CC 2015" if (count of documents) > 0 then return active document end if end tell end getTargetObject
There is a lot more that needs to be included in the getTargetObject handlert to allow for a selection option, but for now we will let this suffice.
Notice that the script skeleton was written using handlers to facilitate adding other functionality. In keeping with the sample FindChangeByList script, you could expand your script to allow grep and glyph find/change. For this, you will need to write a handler for doing a grep find/change as well as one for a glyph find/change.
In the main section of the script, add code to test to see if the first word of the list is “text”, “grep”, or “glyph”.
if searchType is "text" then my doFindChangeText (objRef, findRecord, changeRecord, optionList) else if searchType is "grep" then my doFindChangeGrep (objRef, findRecord, changeRecord, optionList) else my doFindChangeGlyph (objRef, findRecord, changeRecord, optionList) end if
Following the pattern for the doFindChangeText() handler, add a handler for grep (doFindChangeGrep) and one for glyph (doFindChangeGlyph). Hint: Change references to find text preferences to find grep preferences and change text preferences to change grep preferences. Also, change the find text method to find grep and change text to change grep.
Change the definition of the myFindChangeList for a grep find/change. To remove spaces after a line return the myFindChangeList variable definition could be written:
set myFindChangeList to {"grep", {find what:"\r "}, {change to:"\r"}, {true, false, false, false}}
To provide for multiple find/change operations, the script becomes a little more involved. Essentially, all that is needed is to provide multiple lists for the myFindChangeList variable definition. Then add a repeat loop to the body of the script to iterate over the lists.
tell application "Adobe InDesign CC 2015" --change this list of lists for multiple find/change operations set myFindChangeList to {{"text", {find what:"aid of their party"}, {change to:"assistance of their leaders"}, {true, false, false, true}},{"grep", {find what:"\r "}, {change to:"\r"}, {true, false, false, false}}} set objRef to my getTargetObject() repeat with i from 1 to length of myFindChangeList copy item i of myFindChangeList to {searchType, findRecord, changeRecord, optionList} if searchType is "text" then set myFoundItems to my doFindChangeText (objRef, findRecord, changeRecord, optionList) else if searchType is "grep" then set myFoundItems to my doFindChangeGrep (objRef, findRecord, changeRecord, optionList) else set myFoundItems to my doFindChangeGlyph (objRef, findRecord, changeRecord, optionList) end if end repeat end tell myFoundItems --for testing
To give the user the option of using a selected item or the entire document for the target text range, your script will need to expand on the getTargetItem handler. It first needs to check for a selection. If there is a valid selection, the script will then need to create a customDialog to provide choices for the user. You may want to look at Adobe’s sample script (FindChangeByList) to see how they wrote this portion of the code. An alternate version for the getTargetObject() follows:
(*Checks for selection and empty selection. If selected item is a text item, insertion point, or text frame, user is given option of targeting the selection or the entire document.*) on getTargetObject() set objRef to missing value set dialogName to "Find Change Range" set allowSelection to false tell application "Adobe InDesign CC 2015" set selList to selection if selList is {} then set allowSelection to false set selItem to item 1 of selList if class of selItem is text frame then set objRef to object reference of text 1 of selItem if contents of contents of objRef is not "" then set allowSelection to true end if else if class of selItem is insertion point then set parentStory to parent story of selItem if contents of parentStory is not "" then set allowSelection to true end if end if if allowSelection then set objRef to my customDialog("Find Change Range", selItem) else return active document end if end tell end getTargetObject (*Gives user choice of entire document or selection for search find range*) on customDialog(dlgName, selItem) tell application "Adobe InDesign CC 2015" set origLevel to user interaction level of script preferences set user interaction level of script preferences to interact with all set dlgRef to make dialog with properties {name:dlgName, can cancel:false} tell dlgRef tell (make dialog column) set radioGroup to (make radiobutton group) tell radioGroup make radiobutton control with properties {static label:"Entire Document", checked state:true} if class of parent of selItem is story then make radiobutton control with properties {static label:"Selected Story"} else make radiobutton control with properties {static label:"Selection"} end if end tell--radioGroup end tell--dialog column end tell --dialog set dlgResult to show dlgRef if dlgResult is true then set rangeIndex to selected button of radioGroup if rangeIndex is 0 then set objRange to document 1 else if rangeIndex is 1 then if class of selItem is not story then set objRange to parent story of selItem else set objRange to selItemf end if end if end if set user interaction level of script preferences to origLevel return objRange end tell end customDialog
Custom dialog for choosing target object
Once you test your script and have it working as desired, place the script in the Scripts Panel folder of your choice (Application or User). Make sure the target document has been saved so you can revert back to the last saved version, if needed. Then, to run the script, control-click on the script in the Scripts Panel list to edit the lists for defining the myFindChangeList variable. Save the modified script and then run. In my opinion, this is a lot easier than creating the text file and copying it to the FindChangeSupport folder inside the application’s Scripts Panel folder.
Compare how the above skeleton script was written with that of Adobe’s sample script. Do you find one structure easier to read than the other? Besides adding handlers for findChangeGrep and findChange Glyph, what additional functionality is needed by the sample script above to make it a real world script?