FILLING IN THE GAPS

In writing a script the major task often relies on a number of dependencies that must be resolved before the script can be successful. This is true of the script that we began in the previous blog, “TextFrameInfo”. This script is designed to collect information about the text frames in a document. The information will be written to a text file in the same folder as the document.

The script, as currently written, depends on the following:

  1. There is an existing open document
  2. The document has been saved
  3. All text frames have been placed on a single layer
  4. The script knows the name of the layer on which all text frames of the document are found

GET DOCUMENT REFERENCE

The first two dependencies can be handled by a single subroutine: getDocRef()

AppleScript

try
	set docRef to getDocRef()
on error errStr
	display alert errStr
	return
end try

--========
--HANDLERS
--========

(*Returns reference to active document; otherwise generates error.*)
on getDocRef()
	tell application "Adobe InDesign CS6"
		if modal state = true then
			error "Please close dialogs before running script"
		end if
		if not (exists document 1) then
			error "Requires active document"
		end if
		if saved of document 1 is false then
			error "Please save document before running script"
		end if
		return document 1
	end tell
end getDocRef 

ExtendScript

/*Returns reference to active document; otherwise throws exception; place call to function  inside try/catch block */
try {
	var docRef = getDocRef() ;
} catch (e) {
	alert (e);
}

//returns reference to active document; otherwise throws exception
function getDocRef(){
	//if a variable is not assigned a value, its value is undefined
    if (app.modalState == true) {
        throw ("Please close dialogs before running script");
     }
	if (app.documents.length == 0) {
		throw ("No documents open");
	}
    var docRef = app.documents.item(0);
    if (docRef.saved == false) {
        throw ("Please save document before running script");
    }
	//returns value  for variable docRef back to call statement
	return docRef;
}

For the next two dependencies, we will rely on the user to define the layer for the script. First, the script gets a list of the names of all layers in the document with the subroutine getLayerNames().

GET LIST OF LAYER NAMES

AppleScript

set layerNames to getLayerNames (docRef)

(*Returns list of names of layers for the document referenced*)
on getLayerNames(docRef)
	tell application "Adobe InDesign CS6"
		tell docRef
			set layerNames to name of every layer
		end tell
	end tell
	return layerNames
end getLayerNames

ExtendScript

var layerNames = getLayerNames (docRef)

/*Returns list of names of layers for the document referenced*/
function getLayerNames (docRef) {
var layerNames = docRef.layers.everyItem().name;
return layerNames;
}

Next, the user is asked to choose the layer all of the text frames rely on using the subroutine chooseFromList (). With AppleScript, this is fairly simple using the choose from list command.

AppleScript

set docRef to getDocRef()
set layerList to getLayerNames(docRef)
set multipleItems to false
set promptStr to "Choose text frame layer"
try
	set userChoice to chooseFromList(layerList, promptStr, multipleItems)
on error errStr
	activate
	display alert errStr
	return
end try
set layerName to item 1 of userChoice

(*Throws error if user Cancels, otherwise returns user choice from list*)
on chooseFromList (layerList, promptStr, multipleItems)
	set userChoice to choose from list layerList with prompt promptStr multiple selections allowed multipleItems
	if userChoice = false then
		error "User Cancelled"
	end if
	return userChoice
end chooseFromList

ExtendScript

For ExtendScript it is necessary to create a custom dialog from which the user can select the name of the script.

var docRef = getDocRef()
var layerNames = getLayerNames (docRef)
var dlgName = "Layer List";
var dlgLabel = "Layer List Choice";
var cancelIt = true;
var promptStr = "Choose text frame layer";
var defaultItem = 0;
var choiceList = layerNames;
try {
	var userChoice = chooseFromList_Index (dlgName, cancelIt, dlgLabel, promptStr, choiceList, defaultItem);
	userChoice;
} catch (e) {
	alert (e);
}
var layerName = layerNames[userChoice];
var layerRef = docRef.layers.itemByName(layerName);

//returns index of item chosen from dropdown
function chooseFromList_Index (dlgName, cancelIt, dlgLabel, labelText, dropList, defaultChoice) {
	//make sure that user interaction levels will allow a dialog
	var origLevel = app.scriptPreferences.userInteractionLevel;
	app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL;
	//create the dialog
	var dlgRef = app.dialogs.add();
	//create master column with a single row
	var dlgMColumn = dlgRef.dialogColumns.add();
	var dlgMRow = dlgMColumn.dialogRows.add();
	//add a container for your items; we are providing two dialog columns: one for a label and one for the widget
	var dlgColumn1 = dlgMRow.dialogColumns.add();
	var dlgColumn2 = dlgMRow.dialogColumns.add();
	//add your items for your container (use container reference for parent
	dlgColumn1.staticTexts.add({staticLabel:labelText});
	var choiceField = dlgColumn2.dropdowns.add({stringList:dropList, selectedIndex:defaultChoice, minWidth:144});
	//show the dialog and capture the result
	if (dlgRef.show() == true) { 
		var userChoice = choiceField.selectedIndex;
		dlgRef.destroy();
		//restore script preference
		app.scriptPreferences.userInteractionLevel = origLevel;
		return userChoice;
	} else { 
		//destroy the dialog before throwing exception
		dlgRef.destroy();
		//restore script preference
		app.scriptPreferences.userInteractionLevel = origLevel;
		throw ("User cancelled");
	}
}

All that is left at this point is to add these subroutines to the script that was started in our previous blog. The complete script will be used in a project designed to create a fixed layout document for iPad. That will be in the final installment for this series.