Your prescription for increased productivity and profitability
One of the great scripts provided with InDesign is BreakFrame. In a nutshell, it is designed to break the thread between selected text frames. It first checks to make sure there are text frames or text items selected. If at least one text frame or item is in the selection list, it passes the list to the BreakFrames handler which does the work. Interesting is the way the threads are broken. The handler first duplicates the frame, then it deletes the text from the original frame and then deletes the original frame itself.
A recent issue posted in the InDesign Forum sought a solution for re-threading text frames which had been broken with the BreakFrames script. I am sure there are several solutions for this. The one I came up with was to modify the BreakFrames script to preserve the ids of the duplicated frames in a list.
A small change to the script’s myBreakFrames handler might be all that would be needed.
(*Partial listing shows line of code added to repeat loop that saves the item id to a list*) set procList to {} ... tell myObj set myDup to duplicate copy id of myDup to end of procList end tell
Parsing a list such as this, the frames could be rethreaded by setting the next text frame property for each item in the list to the next. To demonstrate, given an id list, the following code structure could be used.
set linkList to {511, 534, 557, 580, 603, 626} set itemCount to (count linkList) tell application "Adobe InDesign 2020" set docRef to document 1 repeat with i from 1 to (itemCount - 1) set thisId to item i of linkList set nextId to item (i + 1) of linkList set thisFrame to text frame id thisId of docRef set nextFrame to text frame id nextId of docRef set next text frame of thisFrame to nextFrame end repeat end tell
The problem then becomes how to store the ids for the duplicated items when the threads are broken. One way this can be done is to use the label property of the document. The label property is a handy place to store any string value. However, the Ids of page items are numerical values. Our breakFrame handler could save the values as a comma-delimited string. Instead, a list was used. To convert the list to a string, AppleScript’s text item delimiters are used.
For example:
set linkList to {511, 534, 557, 580, 603, 626} set linkStr to listToText(linkList) linkStr (*listToText handler converts a list to a comma-delimited string*) on listToText(theList) set AppleScript's text item delimiters to ", " set theStr to theList as text set AppleScript's text item delimiters to "" return theStr end listToText
In testing our BreakList script we discovered several problems. For one, the script throws an error if the user selects an empty text frame. The error is created in trying to delete text that doesn’t exist from the original text frame, To fix this we added a try/end try trap.
on myBreakFrames(myObjectList) set procList to {} tell application "Adobe InDesign 2020" repeat with i from 1 to length of myObjectList set myObj to item i of myObjectList tell myObj set myDup to duplicate copy id of myDup to end of procList end tell try tell text 1 of myObj to delete end try tell myObj to delete end repeat end tell return procList end myBreakFrames
If you compare this handler with the original myBreakFrames handler you will see the following test has been removed:
if class of myObject is not text frame then set myObject to item 1 of parent text frames of myObject end if
The reason for this change is another problem we discovered. If the user accidentally selects a text frame that is not part of the thread, it is included in the id list. For this, the script also needs a test to make sure each text frame is a threaded frame. Considering this and the other tests that need to be performed, the decision was to put all of the tests in the main portion of the script. Rather than have a bunch of nested if statements, you will see in the code below each test is done individually within a try/on error structure.
The top portion of the script is now rewritten as follows:
set myObjectList to {} try tell application "Adobe InDesign 2020" set myTextObjects to {text, text frame, insertion point, character, word, text style range, line, paragraph, text column} if (count documents) is 0 then error "Requires document with text frame selection" end if set mySelection to selection if (count mySelection) is 0 then error ("No items selected") end if repeat with i from 1 to (count mySelection) if class of item i of mySelection is not in myTextObjects then error ("No text items or frames selected") end if if class of item i of mySelection is not text frame then set myObject to item 1 of parent text frames of item i of mySelection else set myObject to item i of mySelection end if set isLinked to (next text frame of myObject is not nothing or previous text frame of myObject is not nothing) if (isLinked) then copy myObject to end of myObjectList end if end repeat if (count myObjectList) is greater than 0 then set procList to my myBreakFrames(myObjectList) end if tell document 1 set label to "" set label to my listToText(procList) end tell end tell procList on error errStr activate display alert "Error " & errStr end try (*listToText handler converts a list to a comma-delimited string*) on listToText(theList) set AppleScript's text item delimiters to ", " set theStr to theList as text set AppleScript's text item delimiters to "" return theStr end listToText
Note: Add the myBreakFrames handler from above to complete the script.
The following script is then used to re-thread the “broken” frames.
(*Gets list of text frames in document label to rethread broken text threads*) try tell application "Adobe InDesign 2020" tell document 1 set theLabel to label if theLabel is "" then error "Document does not have information in label" end if set theList to my textToList(theLabel) repeat with i from 1 to ((length of theList) - 1) set thisId to item i of theList as number set nextId to item (i + 1) of theList as number set thisFrame to text frame id thisId set nextFrame to text frame id nextId set next text frame of thisFrame to nextFrame end repeat end tell end tell on error errStr activate display alert ("Error " & errStr) end try (*Converts comma-delimited string to a list*) on textToList(theLabel) set AppleScript's text item delimiters to "," set theList to text items of theLabel set AppleScript's text item delimiters to "" return theList end textToList
Similar to BreakFrames, InDesign includes a script named SplitStory. For this script any text frame within a thread can be selected.. As with BreakFrames the selection is tested for text frames and uses the parent story as its text frame reference. This solution takes care of non-threaded text frames accidentally being selected. It doesn’t help much when it comes to our wanting to get the text frame ids for later re-threading. Let’s explore. But a scripted break/re-thread frames workflow can take advantage of using the story reference. We will see how this can be put together in a later week’s blog post.