Sunday, November 20, 2005


En space after Period

I've been toying with writing this script all day, and I finally got fed up with doing this manually and broke down. I'm working on a document where certain paragraphs require an en space after the first period, but the Word documents from the client have a regular space there. Here's the script:
//DESCRIPTION: Utility to insert en space after first period in each para of selection

Object.prototype.isPureText = function() {
    case "InsertionPoint":
    case "Character":
    case "Word":
    case "TextStyleRange":
    case "Line":
    case "Paragraph":
    case "TextColumn":
    case "Text":
      return true;
    default :
      return false;

if ((app.documents.length != 0) && (app.selection.length != 0)) {
  var mySel = app.selection[0];
  if   (mySel.isPureText) {
    var myParas = mySel.paragraphs;
    for (var j = myParas.length - 1; j >= 0; j--) {
      var myInd = myParas[j].contents.indexOf(". ");
      if ( myInd != -1) {
        myParas[j].characters[myInd + 1].contents = SpecialCharacters.enSpace;
} else {

// +++++++ Functions Start Here +++++++++++++++++++++++

function errorExit(message) {
  if (arguments.length > 0) {
    if (app.version != 3) { beep() } // CS2 includes beep() function.
  exit(); // CS exits with a beep; CS2 exits silently.
There are probably more elegant ways of doing this; perhaps even more efficient; but I'm operating on selections and they're never likely to be more than a few paragraphs.


Open with No Warnings

In some workflows, the persistent "missing fonts" or "missing links" messages on opening an InDesign document are more annoying than helpful. So it occurred to me to write a script to address the issue. Obviously, to be useful, the script must be called in place of whatever technique is being used to open documents right now. That rules out double-clicking on the document's icon or using File/Open because the script can't insinuate itself into those processes. [Note to self: check out Rogue Sheep's plug-in; perhaps it can help in those cases.]

When this request came up on the Adobe User-to-User forum this morning, I banged out this script. I've written it to work with both CS and CS2:
//DESCRIPTION: Open Doc with No Warnings

if (app.version == 3) {
  app.userInteractionLevel = UserInteractionLevels.neverInteract;
} else {
  app.scriptPreferences.userInteractionLevel = UserInteractionLevels.neverInteract;

var myFile = File.openDialog("Choose InDesign document to open");
var myErr = "";
if (myFile != null) {
  try {;
  } catch (e) {
    myErr = e;
if (app.version == 3) {
  app.userInteractionLevel = UserInteractionLevels.interactWithAll;
} else {
  app.scriptPreferences.userInteractionLevel = UserInteractionLevels.interactWithAll;
if (myErr != "") {
This script has one important lesson in it: if you're messing around with user preferences, make sure there's no way out of the script that leaves them in their "messed-around" state. That's why the error handling is pushed to the end of the script so that the interaction preference is reset before exiting.

The script also raises an issue (other than the idea to explore the Rogue Sheep plug-in): how does one filter an openDialog call so only InDesign documents are visible in the resulting dialog? When I have more time, I'll return to that issue.

Tuesday, November 15, 2005


Select and Display

One of the challenges of complex scripts is showing the user object in a document when things go wrong. For example, say you have a completely overset cell in a table or a text frame that meets some criteria of interest. Well, here's a little function that will do the job:
function selectIt(theObj) {
  // Selects object, turns to page and zooms in on it,SelectionOptions.replaceWith);
  app.activeWindow.zoom = ZoomOptions.fitPage;
  app.activeWindow.zoomPercentage = 200
Why does this work? Well, making the selection makes the page that the selection is on the active page. That causes the zoom command to operate on that page, no matter which page might previously have been active. By zooming to fitPage, we make sure that the selected object (or text) is visible in the window so that zooming in to 200 does so with the selection centered.

Friday, November 04, 2005


Fixing a Numbered List

I make most of my numbered lists myself using nested styles and hanging indents (and, where appropriate, right-aligned tabs to allow for 10).

But one particular list that crops up in the job I'm working on at the moment has as its numbers an inline group. Within each group is an image (of a shadowed circle created in Photoshop) and two text frames, each holding the number, one in white and one in black-- they're slightly offset from each other so the black number forms a shadow of the white one.

During a correction cycle, my client changed one of the lists, deleting one of the numbers. The thought of using find/replace to fix the list up crossed my mind, but it really would have been tedious. So, instead, I banged out this quick and dirty script. Fortunately, each of these lists is segregated into a separate story, so I didn't have to worry about restarting the list for any reason. Here's the script:
//DESCRIPTION: Q&D script to fix numbering in BCS list

Object.prototype.isInArray = function(myArray){
 for (var i=0; myArray.length > i; i++) {
  if(myArray[i] == this){
   return true;
 return false;

var myStory = app.selection[0].parentStory;
var myParaStyles = myStory.paragraphs.everyItem().appliedParagraphStyle;
var myListStyleNames = ["BasicSkillNL","BasicSkillNLkeep"]
var myCounter = 1;
var myPlim = myParaStyles.length;
for (var j = 0; myPlim > j; j++) {
 if (myParaStyles[j].name.isInArray(myListStyleNames)) {
  fixNumbers(myStory, j, myCounter);


// +++++++ Functions Start Here +++++++++++++++++++++++

function fixNumbers(story,paraindex,counter) {
 var myGroup = story.paragraphs[paraindex].groups[0];
 var myTFs = myGroup.textFrames;
 var myLim = myTFs.length
 for (var k = 0; myLim > k; k++) {
  myTFs[k].parentStory.contents = String(counter);
It simply cycles through all the paragraphs of the story looking for list members (there are two eligible styles) using myCounter to hold the current state of the list counter. Worked like a charm and probably took no longer to write than doing the job by hand would have required.

The exit() isn't strictly necessary, but I include it for debugging purposes. I can put a breakpoint next to it so that when I'm testing the script (in its final form and at intermediate stages) I can use ESTK's data browser to view the states of the variables the script sets up.

Wednesday, November 02, 2005


Flagging Images

In one of my workflows, I've found it desirable to flag images in Photoshop for needed future actions. For example, some of the images will be resized in InDesign and so I don't want to sharpen them until the final size is established in InDesign (in some cases, I'm resizing to as small as 20% of the original, so waiting until I know the size before sharpening is vital). Other images are provided in low resolution format so the composition can go ahead and the higher resolution image can be inserted later.

I probably should be using metadata for what I'm doing, but instead I create a text layer in Photoshop and type "LOW RES" or "Not Sharpened" into it, as appropriate -- I use actions for these. In the low resolution case, the layer is visible so that the reviewers can instantly see that the image is known to still need work. For the "Not Sharpened" images, the layer is invisible.

I've been worrying about how to make sure I attend to all these. Well, guess what, among the properties of an image is graphicLayerOptions, which in turn has a collection property graphicLayers. And each graphicLayer has a name property. So:
returns the names of all the layers in the image myImage.

So, it is just a matter of technique to write a script that reviews all the linked images to produce a report of all the images that need attention.

This page is powered by Blogger. Isn't yours?