Search code examples
javascriptadobe-indesignextendscript

Select, adjust and distribute textframes in InDesign [ExtendScript]


I want to write a script that does the following:

  • select some textframes
  • center the selection horizontally
  • distribute the frames horizontally
  • the whole routine has to be done on several pages

My first problem is, that I only want to select textframes from a unlocked layer. I found several solutions where all textframes, even on locked layers, were selected. And the only solution I found so far that just selects the textframes from my unlocked layer (app.menuActions.item("$ID/Select &All").invoke();) doesn't provide an object I can work with (adjust, distribute) afterwards.

Is there a solution to my requirements?


Edit: My last attempt looked like this (for a single page, I didn't used a loop for several pages while testing):

// 'allPageItems' erfasst alle Rahmen, zusätzlich Gruppen und Bilder 
var allObjects = app.activeDocument.layoutWindows[0].activeSpread.allPageItems; 
// eine Schleife durch die Objekte 
for (var n=0; n<allObjects.length; n++) { 
    var curObject = allObjects[n]; 
    // prüfen, ob Textrahmen 
    if (curObject.constructor.name == "TextFrame") { 
        // verankerte Textrahmen ausschliessen 
        if (curObject.parent != "[object Character]") { 
            // zur Auswahl hinzufügen 
            curObject.select(SelectionOptions.ADD_TO); 
        }   
    } 
} 

Solution

  • Generally, selection is something that is intended for UI interaction, not for scripting. Therefore you should avoid handling all the selection stuff in your script and collect the textFrames as objects in an array that you then can use to do the other stuff.

    This should work:

    #target indesign
    
    var doc = app.activeDocument;
    var curSpread = doc.layoutWindows[0].activeSpread;
    var spreadItems = curSpread.allPageItems;
    
    var distObjects = [];
    
    // collect all relevant objects in distObjects
    for (var i = 0; i < spreadItems.length; i += 1) {
      var si = spreadItems[i];
    
      // skip if itemLayer is locked
      if (si.itemLayer.locked) continue;
    
      // skip if item is not a textFrame
      if (!(si instanceof TextFrame)) continue;
    
      // skip if item is anchored
      if (si.parent.constructor.name === "Character") continue;
    
      distObjects.push(si);
    };
    
    // group all collected objects to center them, then ungroup
    var distGroup = curSpread.groups.add(distObjects);
    doc.align([distGroup], AlignOptions.HORIZONTAL_CENTERS, AlignDistributeBounds.SPREAD_BOUNDS);
    distGroup.ungroup();
    
    // distribute all objects horizontally
    doc.distribute(distObjects, DistributeOptions.HORIZONTAL_CENTERS, AlignDistributeBounds.ITEM_BOUNDS);
    

    Note: If this is used with an older ID version (prior to CC2014 I believe), after ungrouping, all pageItems will stay on the same layer. The feature for them to move back to the original layer was only introduced recently. If you need a solution for an older InDesign version, you would need to calculate the bounds of the group of objects you found, then offset them all one by one, so the entire "selection" can get centered.