Showing posts with label InDesign. Show all posts
Showing posts with label InDesign. Show all posts

2010-05-10

Paragraphs of Selection

Handy for certain tasks
This is another function that I tend to use when needing to work with paragraphs. I recently came across it again and thought it was fine time to share.
The basic premise is that if the user has some text selected and you want to automate something with regard to the whole paragraphs that have any part selected, then you need something like this.
With all the ifs, switches, etc., this code sure does go marching off to the right, but that is just the way it is. It doesn't have to be pretty, it just has to work.
Comments?

//
function getParagraphsOfSelection () {
//----------------------------------------------------------------------------
//-- G E T P A R A G R A P H S O F S E L E C T I O N
//----------------------------------------------------------------------------
//-- Generic: Yes.
//----------------------------------------------------------------------------
//-- Purpose: To return an array of paragraphs relating to the selection
//-- or false if there is no selection or an error.
//----------------------------------------------------------------------------
//-- Written: 10 March 2009 by Jon S. Winters from a prior work.
//-- eps@electronicpublishingsupport.com
//----------------------------------------------------------------------------

//-- Determine is there in an appropriate selection.
try {
//-- Initialize the object
var myObject = false ;
//-- Check for a selection.
if(app.documents.length != 0){
if(app.selection.length != 0){
//Process the objects in the selection to create a list of
//qualifying objects (text frames).
switch(app.selection[0].constructor.name){
case "TextFrame":
myObject = ( app.selection[0].parentStory.paragraphs ) ;
break;
default:
if(app.selection.length == 1){
//If text is selected, then get the parent text frame.
switch(app.selection[0].constructor.name){
case "Text":
case "InsertionPoint":
case "Character":
case "Word":
case "Line":
case "TextStyleRange":
case "Paragraph":
case "TextColumn":
myObject = ( app.selection[0].paragraphs );
break;
} //-- end of switch
} //-- end of if selections == 1
break;
} //-- end of switch
} //-- end of app.selection.length
} //-- end of app.documents.length
} //-- end of try
catch (caughtError) {
return {} ;
}
return myObject ;
}//-- End of function
//

2010-05-03

Insert Glyph

Method to insert additional special characters
A client has been asking me for create an extension of Adobe InCopy and Adobe InDesign's Insert Special Character submenus. This blog already has code posted to create menu items with keyboard shortcuts. The code below actually inserts a glyph at the current insertion point. This code takes a slightly different approach than the Insert Special Characters in that it will not replace as selection, it only works when there is an insertion point.

What is interesting is that it is driven by the same Unicode text that the Info Panel displays when the desired glyph is selected in a story. So to insert a 1/4 fraction glyph you would use:
insertGlyph ('0xBC') ;

That unicode number is internally converted to a different encoding by replacing the 0x with a %u and adding any necessary leading zeros before being unencoded and forced to be a string. There is far more error checking than actual code.

//
function insertGlyph (charCodeOfGlyphToInsert) {
//-------------------------------------------------------------------------
//-- I N S E R T G L Y P H
//-------------------------------------------------------------------------
//-- Generic: Yes for Adobe InDesign and Adobe InCopy CS3 and newer
//-------------------------------------------------------------------------
//-- Purpose: To take a code for a glyph as listed by the Info panel and
//-- insert the the glyph at the insertion point if there is an insertion
//-- point.
//-------------------------------------------------------------------------
//-- Arguments:
//-- charCodeOfGlyphToInsert: a String appearing as 0xEB pr 0x2014
//-------------------------------------------------------------------------
//-- Calls: Nothing.
//-------------------------------------------------------------------------
//-- Returns: nothing truely useful. Does return true if successful, false
//-- if the arguments or the selection is invalid.
//-------------------------------------------------------------------------
//-- Sample Use:
//~ insertGlyph ('0xBC') ; // 1/4 fraction
//~ insertGlyph ('0x401') ; // Capital E with umlaut
//~ insertGlyph ('0x2020') ; // Dagger
//-------------------------------------------------------------------------
//-- Notes: Use the Info Panel with a single character selected to learn
//-- the glyph number. These are unicode numbers or in very simple cases
//-- they are ascii number. But they are Hexidicmal based. However, they
//-- may be large 4 digit numbers or smaller 2 digit numbers based upon
//-- the specific glyph.
//-------------------------------------------------------------------------
//-- Written: 2010.04.25 by Jon S. Winters of electronic publishing support
//-- eps@electronicpublishingsupport.com
//-------------------------------------------------------------------------

//-- Verify that what we were passed was a valid glyph number with the 0x
var len = charCodeOfGlyphToInsert.length ;
if (((len != 4) && (len != 5) && (len != 6)) || (charCodeOfGlyphToInsert.substr (0, 2) != '0x')) {
return false ;
}
//-- Verify that the selection is an insertion point, but check docs first
if (1 > app.documents.length) {
return false ;
}
var curSel = app.selection ;
if ((curSel.length != 1) || (curSel[0].constructor.name != 'InsertionPoint')) {
return false ;
}
//-- create the glyph. Not really necessary to make it a spearate variable,
//-- but this makes it easier to debug.
var glyph = String (unescape ('%u' + ('00').substr (0, 6 - len) + charCodeOfGlyphToInsert.substr (2))) ;

//-- insert the glyph
curSel[0].insertionPoints[0].contents = glyph ;
return true ;
}
//

2010-04-19

Set Text Variables

Part of a routine to set folios
I used to set folios by leaving misspelled tags on pages such as 'mMonth' and then scripting their replacement for folios. The advantage of this is that if a user fails to run the script that does the swap, or if the document doesn't conform to the site's naming convention, the misspelled tags remain and hopefully they would be found during a spell check of the document. Alas, users don't seem to follow the rules.

So, I've changed to using Adobe InDesign text variables for folios. The template would be set to have no values and then at key moments (like opening, and saving as) the values would get set.

The function below makes it easy to set values as it adds the text variable if it doesn't exist.

//
function setCustomTextVariable (docRef, name, value) {
//-------------------------------------------------------------------------
//-- S E T C U S T O M T E X T V A R I A B L E
//-------------------------------------------------------------------------
//-- Generic: Yes for InDesign CS4 and newer.
//-------------------------------------------------------------------------
//-- Purpose: To set a Custom Text Variable value. These can be used for
//-- a multitude of items, but they are commonly used for folios.
//-------------------------------------------------------------------------
//-- Arguments:
//-- docRef: The reference to the document to alter
//-- name: The name of the CustomText Variable
//-- value: The text that the CustomText Variable should be set to.
//-------------------------------------------------------------------------
//-- Calls: Nothing.
//-------------------------------------------------------------------------
//-- Returns: true unless an error occurs, which returns false.
//-------------------------------------------------------------------------
//-- Sample Use:
//~ setCustomTextVariable (app.documents[0], 'Publication', 'Star-Ledger')
//-------------------------------------------------------------------------
//-- Notes: The Text Variable does not have to exist, this will create it.
//-- But if the text variable is not a Custom Text Variable, its value
//-- won't be able to be set, and this function will fail silently. See
//-- returns above.
//-------------------------------------------------------------------------
//-- Written: 2010.04.19 by Jon S. Winters of electronic publishing support
//-- eps@electronicpublishingsupport.com
//-------------------------------------------------------------------------
try {
var atv = docRef.textVariables.everyItem() ;

if (atv.hasOwnProperty (name)) {
//-- Note, not testing to see if the value can be set. If the TV
//-- isn't a 'Custom' TV, this will fail.
atv [name].variableOptions.contents = value ;
}
else {
//-- Create the TV and set the value.
var newTV = docRef.textVariables.add({name:name, variableType:VariableTypes.CUSTOM_TEXT_TYPE}) ;
newTV.variableOptions.contents = value ;
}
return true ;
}
catch (failSilently) {
var localError = failSilently ;
return false ;
}
}
//

2010-04-16

Get Document that Triggered Event

The correct document isn't always the one in front...

Event handlers are ways to run scripts when certain key events happen in Adobe InDesign or Adobe InCopy. Most things can be caught if there is a menu version of that function. Adobe's documentation does a decent job of explaining the common events, but not what to do with the 'event' itself, and is downright poor at the rest of the event handler issues.

But below is a very simple function that you can call inside the event handlers for 'open' and for 'close' event. Imagine you had multiple documents open. Now imagine that the windows are stacked so that you can see the close button for all the windows. Now assume you have an event handler that will do something useful (like look for overset text, preflight, adjust folios, for log a version comment). Well your event handler needs to know which document you just tried to close. That is where this function comes into play.

Event handlers always reference a function. But the function is a specified only in name. You can't pass it anything. Well your event handler will always receive a single argument -- an event. And the event has a property called .target and that .target property has another property .name. And the name of the target of the event is the name of the document.


//
function docRefFromEvent (event) {
//-------------------------------------------------------------------------
//-- D O C R E F F R O M E V E N T
//-------------------------------------------------------------------------
//-- Generic: Yes for ExtendScript CS3, CS4, etc.
//-------------------------------------------------------------------------
//-- Purpose: To return the document triggering the event handler or the
//-- default of the frontmost document.
//-------------------------------------------------------------------------
//-- Arguments: event: the event which triggered some other function which
//-- in turn called this function. Likely it would be an open or a close
//-- function so that you can catch the correct document. For example,
//-- you need this for open handlers becasue if you have two documents
//-- open, documents[0] or .activeDocument will point to the first doc
//-- and not the document you just opened. Likewise with closing files,
//-- your windows could be tiled and you can close a file other than the
//-- active or the documents[0].
//-------------------------------------------------------------------------
//-- Calls: Nothing.
//-------------------------------------------------------------------------
//-- Returns: Either a reference to the front document or the document that
//-- triggered the passed event.
//-------------------------------------------------------------------------
//-- Written: 2010.04.06 by Jon S. Winters of electronic publishing support
//-- eps@electronicpublishingsupport.com
//-------------------------------------------------------------------------
//-- Created for version 3.52
if ((event != undefined) && event.hasOwnProperty ('target') && event.target.hasOwnProperty ('name')) {
var testDocRef = app.documents.itemByName (event.target.name) ;
if (testDocRef != null) {
return testDocRef ;
}
}
return app.documents[0] ;
}
//

2009-11-13

Gather Assigned Frames

The Text Frames associated with Adobe InCopy Assignments

On to more things with Adobe InCopy Assignments in Adobe InDesign.
The generic function below will generate a return object with two properties. One contains references to every text frame in the passed document reference that has assigned content. The second segregates the assigned frames by assignment.
Either property will allow you to locate the frames that are used in an assignment.

//
function gatherAssignedFrames ( docRef ) {
//-------------------------------------------------------------------------
//-- G A T H E R A S S I G N E D F R A M E S
//-------------------------------------------------------------------------
//-- Generic: Yes.
//-------------------------------------------------------------------------
//-- Purpose: To return an associative array of all the text frames in the
//-- passed coument that have associated Adobe InCopy Assignments
//-------------------------------------------------------------------------
//-- Arguments:
//-- docRef: An [object Document] to investigate
//-------------------------------------------------------------------------
//-- Calls: Nothing.
//-------------------------------------------------------------------------
//-- Returns: a custom object with two properties
//-- .assignmentFrames: An Associatve Array of Assignment IDs using
//-- the $ prefix as described below.
//-- Each element will contain a property for every text frame
//-- with the text frame ID with the $ prefix.
//-- The contents of these properties will be a reference
//-- to the text frame itself.
//-- .assignedTextFrames: An Associative Array of Text Frame IDs
//-- with each Text Frame ID have a $ prefix. The contents
//-- of each property is a reference to the text frame itself.
//-------------------------------------------------------------------------
//-- $ Prefix on IDs
//-- IDs are prefixed with a $. Thus Text Frame 188 will be returned as
//-- $188. This is done because objects cannot be named with numbers.
//-------------------------------------------------------------------------
//-- Sample Use:
//-- gatherAssignedFrames ( docRef )
//-------------------------------------------------------------------------
//-- Notes: Decide how you want to handled the Unassigned InCopy Content
//-- There will be references to that assignment as well. It is valid.
//-------------------------------------------------------------------------
//-- Written: 2009.11.12 by Jon S. Winters of electronic publishing support
//-- eps@electronicpublishingsupport.com
//-------------------------------------------------------------------------

//-- Note, we are using a $ prefix on the object names in the associative
//-- array because pure numbers are not allowed.

//-- Create the return object.
var returnObject = new Object () ;
returnObject.assignmentFrames = new Object () ;
returnObject.assignedTextFrames = new Object () ;

//-- Gather all assignments.
var allAssignments = app.documents[0].assignments ;

//-- Loop through each of the assignments -- backwards for efficiency.
for ( var ai = allAssignments.length - 1 ; ai >= 0 ; ai-- ) {

//-- Get a reference to the current assignment in the loop and its ID.
var activeAssignment = allAssignments[ai] ;
var activeAssignmentID = '$' + activeAssignment.id ;
//-- Add the property to the return object for the current assignment.
returnObject.assignmentFrames[ activeAssignmentID ] = new Object () ;
//-- Get a reference to every assigned story for the assignment.
//-- There can be one or many. Most CMS's use many.
var allAssignedStories = activeAssignment.assignedStories ;

//-- Loop backwards through each story of the active assignment.
for ( var asi = allAssignedStories.length - 1 ; asi >= 0 ; asi-- ) {

//-- Get a reference to the story indicated by the loop index.
var activeStory = allAssignedStories[asi].storyReference ;
//-- Get all the text containers for the active story.
//-- There could be more than one if the text frame is
//-- manually threaded to additonal frames.
var allTextContainers = activeStory.textContainers ;

//-- Finally...
//-- Loop through all the text containers (text frames in most
//-- cases) and add the container ID with a $ prefix to both
//-- main properties of the return object.
for ( var tci = allTextContainers.length - 1 ; tci >= 0 ; tci-- ) {
//-- Get a reference to the container indicated by the loop.
var activeTextContainer = allTextContainers[tci] ;
var activeTextContainerID = '$' + activeTextContainer.id ;

//-- Add the IDs to the two objects
returnObject.assignedTextFrames[ activeTextContainerID ] = activeTextContainer ;
returnObject.assignmentFrames[ activeAssignmentID ][ activeTextContainerID ] = activeTextContainer ;
}
}
}
return returnObject ;
}
//