2009-07-15
Unlock an Adobe InDesign Object
2009-07-14
Listing Paragraph Styles
Note the two different ways of referencing the document. The first method uses a function posted here. Delete that line if you don't want to use it (no real need in this case).
Oh, and here with the 900+ Paragraph Styles, we had to add 7 more broadsheet pages to show the styles.
try {
//see if there is a parentStory. If so, then fill it with the names of the styles
//-- The next line errors if there isn't a proper selection
var storyRef = app.selection[0].parentStory.textContainers[0].parentStory ;
//-- Get a valid reference to the document holding the story
var docRef = returnDocumentReference ( storyRef ) ;
//OR use
var docRef = app.documents[0];
//-- Call the function to add the styles.
listParagraphStyles ( storyRef , docRef )
}
catch (err) {
//-- The next line quits the script.
exit() ;
}
//
function listParagraphStyles ( storyRef , docRef ) {
//-- Clear the contents of the the frame
storyRef.contents = '\r' ;
//-- Get an array of all the Paragraph Styles
var allPS = docRef.allParagraphStyles ;
var numPS = allPS.length ;
//-- Loop through the styles adding the name of the style and applying that style to the story
for ( var pIndex = 0 ; pIndex < numPS ; pIndex++ ) {
storyRef.paragraphs[pIndex].contents = allPS[pIndex].name + '\r ' ; //note the space after the return
//-- Remove the next line if you don't want to see the style name formatted with that
Paragraph Style.
storyRef.paragraphs[pIndex].appliedParagraphStyle = allPS[pIndex] ;
}
}
//
2009-07-13
Display Dialog of Checkboxes of Array Elements
The code snippet looks like this...
//-- Limit which pages to print if the method details indicates to
if ( limitOutputToSpecificPages ) {
var arrayToCheck = app.documents[0].pages.everyItem().name ;
var prmt = 'Pages:' ;
var pagesToOutput = selectListOptions( arrayToCheck , prmt , true )
}
//
//-- Determine how to handle the naming of the extra pages
//-- Loop through the pages
for (var pgIndex = numPages - 1 ; pgIndex >= 0 ; pgIndex-- ) {
//-- Deny output of pages if the user didn't check to output them
if ( limitOutputToSpecificPages && ( ! pagesToOutput[pgIndex] ) ) {
continue ;
}
//
//-- HANDLE THE OUTPUT HERE
}// end of for loop
Of course that snippet leaves out a lot of details, but basically if a value (limitOutputToSpecificPages) says to limit to specific pages, use a function (below) to display a dialog of page numbers with check boxes. The function (below) returns an array of true or false values.
And if the value is false, then skip the rest of the inner part of the for loop (the continue causes teh for loop to not finish, but to go back and check for the end point and increment the loop index)
//
function selectArrayElementsViaCheckboxes(lst,prmt,dflt,colLimit) {
//-------------------------------------------------------------------------
//-- S E L E C T A R R A Y E L E M E N T S V I A C H E C L B
O X E S
//-------------------------------------------------------------------------
//-- Generic: Yes! Should work with all current versions of Adobe
Products
//-- that support custom dialog boxes.
//-------------------------------------------------------------------------
//-- Purpose: Displays a dialog with a series of checkboxes with
//-- choices passed into 'lst'.
//-------------------------------------------------------------------------
//-- Parameters: 4
//-- lst: The array whose contents will be displayed to the user
//-- prmt: A string to be used as a prompt
//-- dflt: (optional) A boolean indicating if ALL the checkboxes
//-- should initially be selected (checked) or deselected
//-- (unchecked). _ALL_!
//-- colLimit: (optional) The maximum number of entries to place
//-- in any one column.
//-------------------------------------------------------------------------
//-- Returns: an array the the same length of the of chosen items. If
the
//-- items are selected as a result of the checkbox items being
//-- checked, the array will be set to true, else false.
//-- If the user cancels the dialog, then the returned array is []
//-------------------------------------------------------------------------
//-- Calls: Nothing.
//-------------------------------------------------------------------------
//-- Sample Use:
//-- var sampleArray = ['extreme', 'fantastic', 'great',
'monstrous', 'monumental', 'prodigious', 'stupendous', 'tremendous']
//-- var chosenItems = selectArrayElementsViaCheckboxes
( sampleArray , 'Select the desired words:' , true , 4 )
//-- for ( i = 0 ; i < chosenItems.length ; i++ ) {
//-- if ( chosenItems[i] ) {
//-- $.writeln('User selected: ' + sampleArray[i] ) ;
//-- }
//-- }
//-------------------------------------------------------------------------
//-- Written by Jon S. Winters on 2008.12.24
//-- Edited: 2009.07.13 onboard flight to Charlotee, NC
//-- eps@electronicpublishingsupport.com
//-------------------------------------------------------------------------
//-- Force Adobe InDesign to display dialogs. Without the
//-- line below the dilaog may not appear on some systems.
app.scriptPreferences.userInteractionLevel =
UserInteractionLevels.INTERACT_WITH_ALL ;
//-- Assign a default default choice if one isn't passed;
//-- This should either be true or false
dflt = ( dflt == undefined ) ? true : Boolean ( dflt ) ;
//
//-- Verify that there is a limit to the number of items in a column.
if ( ! colLimit ) { colLimit = 10 ; }
//-- create a new array of user responses to return
var userChoices = new Array () ;
var listDialog = app.dialogs.add({canCancel:true}) ;
var buttons = new Array () ;
with (listDialog) {
with (dialogColumns.add()) {
with ( borderPanels.add() ) {
with ( dialogColumns.add() ) {
staticTexts.add({staticLabel:prmt});
with (dialogRows.add()) {
//-- loop thorugh the passed list and create the checkbox as
well as the array to return
for ( var listIndex = 0 ; listIndex < lst.length ; listIndex++ ) {
if ( listIndex % colLimit == 0 ) {
var Col = dialogColumns.add();
}
with ( Col ) {
userChoices[listIndex] =
( checkboxControls
.add({staticLabel:String(lst[listIndex]),checkedState:dflt})) ;
}
}
}
}
}
}
}
//-- Show the dialog
var listResult = listDialog.show() ;
if ( listResult ) {
var returnArray = new Array () ;
//-- loop the result and rebuild the results
for ( var listIndex = 0 ; listIndex < lst.length ; listIndex++ ) {
returnArray.push ( userChoices[listIndex].checkedState ) ;
}
//-- return the selected list index unless they
return returnArray ;
}
else {
//-- User clicked Cancel -- return an empty array
return [] ;
}
}
//
2009-07-02
Today in History — Sorting Paragraphs with Leading Dates
- 319 B.C.: Something happened.
- 57: Something happened in the middle of those dates.
- 1976: Something else happened.
- 2001: The last important thing happened.
- 1976: Something else happened.
- 2001: The last important thing happened.
- 319 B.C.: Something happened.
- 57: Something happened in the middle of those dates.
- 57: Something happened in the middle of those dates.
- 319 B.C.: Something happened.
- 1976: Something else happened.
- 2001: The last important thing happened.
2009-06-30
Why not just use app.activeDocument
In recent days I've posted two different generic ExtendScript functions for getting a document reference from an object.
Why can we just use:
var docRef = app.activeDocument ;
Simple: It doesn't always work. .activeDocument is the application property for the active document -- the document the user is using. However, when using Adobe InDesign Server, there is never an active document and thus it fails. So, without anything else going on, app.activeDocument doesn't always work, and if you can't count on it even part of the time, you should use it.
Well, if I can't count on it all the time I won't use it. Many of the ExtendScript scripts I create for clients are clients that I have never met, sometimes never even spoken too on the telephone. I need the scripts to work 100% of the time -- don't you?
Well then, why not use:
app.documents[0] ;
That gives you the front document, which should be the one you are using. Yes, it generally does. But for that to work, you need to have the document open in a visible window. And one of the the options for opening a file is to open it without displaying it. And if you don't display it, it isn't in front. And if it isn't in front, it won't be document[0]. Thus, it too doesn't work 100% of the time. Do you want your automobile to only be drivable some of the days? Perhaps that is a bad analogy -- you might actually like it if you couldn't drive to work some days.
There is another problem with both of these functions, lets assume you have a group of Adobe InDesign documents open. Lets assume you are using a findObject search function. Lets assume you locate an object on one of your open documents. Which document is it? It likely isn't the .activeDocument or .documents[0], so you need a function like the recently posted generic functions to point you to the particular document.
Another case where these two application properties won't work; Lets assume you are constructing a new document from an old document -- for example I have a script I wrote for a client that replicates an ad stack from a converted QuarkXPress document (I think the client produced it with BrainWorks) to an Adobe InDesign document created from their current template. In this case we will always have two documents open and will need to have good static references to both of them. The documents don't have to be switching between active and not (just because you can't see a document doesn't mean that you can't be manipulating it) but even if both are visible, only one will ever be the .activeDocument. You can manipulate things in a document that isn't the active document or the first document.
Good document references allow your scripts to work reliably. And with automation, reliability is more important than raw speed.
2009-06-29
Read Tab Delimited Text File
var fileData = readTabDelimitedFile ( aFile ) ;
for ( var dIndex = 0 ; dIndex < fileData.length ; dIndex++ ) { //-- Do what you want with the data on a line by line basis. //-- This will write it to the JavaScript Concole with //-- and ugly '' indicator to show you where the
//-- tabs were in the original file.
$.writeln( fileData[dIndex].join ('' ) ) ;
}
//
function readTabDelimitedFile ( fPath ) {
//-------------------------------------------------------------------------
//-- R E A D T A B D E L I M I T E D F I L E
//-------------------------------------------------------------------------
//-- Generic: Yes for all versions of ExtendScript with Adobe InCopy and
//-- Adobe InDesign. Does not work with browser based JavaScript as
//-- there is no File object. The File Object is one of the things
//-- that makes ExtendScript not the same as JavaScript.
//-------------------------------------------------------------------------
//-- Purpose: To read a tab delimited file at the passed 'fPath' and
//-- return an array of arrays. The main array will contain a sub
//-- array for each tab delimiated value from each line of the file.
//-- The file can be ASCII or unicode encoded.
//-- Note, if the file has blank lines or lines without tabs, those
//-- lines of the file will be ignored. This allows you to have
//-- commented and empty lines in the file.
//-------------------------------------------------------------------------
//-- Parameters: fPath a full path to the file.
//-------------------------------------------------------------------------
//-- Returns: An array of arrays if a tab delimited file is successfully
//-- read by the function. Returns an empty array if there were
//-- problems. Because of this, you can successfully loop through
//-- the array elements if there were issues reading the file.
//-------------------------------------------------------------------------
//-- Calls: nothing.
//-------------------------------------------------------------------------
//-- Sample Use:
//-- var aFile = File.openDlg ( 'Select a Tab delimited file to parse:', '*.txt', false ) ;
//-- var fileData = readTabDelimitedFile ( aFile ) ;
//-- for ( var dIndex = 0 ; dIndex < fileData.length ; dIndex++ ) {
//-- var activeLineArray = fileData[dIndex] ;
//-- //-- Do what you want with that subarray
//-- }
//-------------------------------------------------------------------------
//-- Written by Jon S. Winters of electronic publishing support from
//-- scratch on 29 June 2009.
//-- eps@electronicpublishingsupport.com
//-------------------------------------------------------------------------
//-- Setup the result of the function. When errors occur the function
//-- should return an empty array.
var returnArray = new Array ( ) ;
//-- Verify that the file exists
var fileObject = File ( fPath ) ;
if ( ! fileObject.exists ) {
return returnArray ; // an empty array because the file doesn't exist.
}
//-- Create a regular expression for a tab.
var tabExpression = new RegExp ( '\\t' ) ;
//-- Read the file.
try {
//-- The file has to be open.
fileObject.open ('r') ; //-- Open for reading.
//-- repeat until eof (End Of File) or an error
while ( ! fileObject.eof ) {
//-- Read one line, and only one line.
var currentLine = fileObject.readln () ;
//-- verify that the line contains at least one tab
//-- The .test() is my favorite way of using regular
//-- expressions as it returns true or false if
//-- the string contains the patter. The 'confusing'
//-- thing about .test is that in the code it almost
//-- reads backwards. Because you think you want to
//-- know if the string has the pattern, but with
//-- .test() you ask the regular expression if the
//-- string will create a match.
if ( tabExpression.test( currentLine ) ) {
//-- Break the line into tab delimited parts and put that
//-- array into the end of the array to return.
//-- This will remove the tabs from the string and only
//-- include the text between the tabs.
returnArray.push(currentLine.split ('\t')) ;
}
}
//-- if we didn't error, we need to close the file
fileObject.close() ;
}
//-- If there was an error reading the file,
//-- then return the empty array.
catch (errMain) {
try {
//-- an error was generated, try to close the file one more time
fileObject.close() ;
}
//-- if the close generates an error skip it.
catch (errInner ) { /* nothing here */ }
}
//
return returnArray ;
}
//
Document, Page, and Spread References of Frame
function docPageSpreadOfFrame (theFrame) {
//-------------------------------------------------------------------------
//-- D O C P A G E S P R E A D O F F R A M E
//-------------------------------------------------------------------------
//-- Generic: Yes, for Adobe InDesign. Tested with CS3 but should work
//-- will CS2 through CS4
//-------------------------------------------------------------------------
//-- Purpose: To return a reference to the document, page, and spread
//-- for the passed frame.
//-- The need for referencing a page and a spread is because an item
//-- on the pasteboard won't be on a page. If you are creating new
//-- ojbects nearby, you need to know where the object is.
//-------------------------------------------------------------------------
//-- Returns: An object of 4 properties:
//-- objectDoc: The Document Object for the frame
//-- objectPageNum: The page number from the front of the document
//-- objectPageRef: A referece to that page
//- objectSpreadRef: A reference to the spread of the object.
//-------------------------------------------------------------------------
//-- Calls: Nothing.
//-------------------------------------------------------------------------
//-- Written: 2008.08.28 by Jon S. Winters
//-- Edited: 2009.01.21 by Jon S. Winters for version 2n to reutrn object.
//-- © 2009 electronic publishing support. All rights reserved.
//-------------------------------------------------------------------------
//-- How it works:
//-- Assume we have an item on a page. If instead it is on a spread, then
//-- the normal method of finding the document (looking at the paretnt)
//-- will instead find the application. If so, then back down.
//-- Note, we will assume the page the item goes on is the right hand page
//-- of the spread. This is only if the item doesn't appear on a page
//-------------------------------------------------------------------------
//-- Version 2.05 put in controls so that it will return if a frame
//-- was not passed.
//-------------------------------------------------------------------------
if ( '|Group|TextFrame|GraphicLine|Oval|Polygon|Rectangle|'.indexOf ('|' + theFrame.reflect.name + '|' , 0 ) < 0 ) {
alert ( "The function 'docAndPageFromFrame' was not passed a frame." ) ;
return null ;
}
//-- Verify that we do not have an anchored item. 2.05
if (theFrame.parent.reflect.name == 'Character' ) {
theFrame = theFrame.parent.parentStory.textContainers[0] ;
}
//-- Version 2.05 method works when theFrame is part of a group or
//-- even if it is burried deeper.
var objRef = theFrame
var objRefParent = objRef.parent ;
while ( objRefParent.reflect.name != 'Spread' ) {
objRef = objRefParent ;
objRefParent = objRef.parent ;
}
//-- At this point, the objRef is still unknown, but we know the spread details
//-- Keep the spreadReference and build the doc reference.
var spreadRef = objRefParent ;
//-- Get the doc from the frame using the normal method.
var theDocOfTheFrame = spreadRef.parent ;
//-- Now check to see if the obeject before the spread is a page
if (objRef.reflect.name == 'Page' ) {
//--on a page
var pageRef = objRef ;
var thePageNumOfTheFrame = pageRef.documentOffset + 1 ;
}
else {
//-- likely a group or something else
//-- The below 'Page' is fake, but it works in most cases
var pageRef = spreadRef ;
var lastPageOfSpread = spreadRef.pages.item( (spreadRef.pages).length - 1 ) ;
var thePageNumOfTheFrame = lastPageOfSpread.documentOffset + 1
}
//-- Now setup a return object
return {objectDoc:theDocOfTheFrame , objectPageNum:thePageNumOfTheFrame , objectPageRef:pageRef , objectSpreadRef:spreadRef }
} //-- End of Function
//