Search code examples
javascriptadobedirectoryadobe-indesignextendscript

Javascript code to open several files in subdirectories


I'm a fairly new programmer. I'm attempting something pretty advanced, but I enjoy a good challenge. :~) I'm using Adobe's ESTK (ExtendScript Toolkit) to write a complex script for InDesign CS6. I've gone through most of the tutorials and have learned quite a bit, but I have run into a wall now.

I need the script to detect whether a certain folder meets a certain criteria, and if it does, to delve into that folder, count all of its subfolders, and open each of the .indd files in each of those subfolders, in turn, performing tasks on each one. I have only just started the script today and this is what I've got so far:

var getDataDialog = app.dialogs.add({name:"Job Info"});
with(getDataDialog){
    // Add a dialog column.
    with(dialogColumns.add()){
        // Create the order number text edit box.
        var orderNumTextEditBox = textEditboxes.add({minWidth:80});
        }
    }
// Show the dialog box.
var dialogResult = getDataDialog.show();
if(dialogResult == true){
    // Get the order number and put it in the variable "orderNum".
    var orderNum = orderNumTextEditBox.editContents;
    // Get the first three numbers of the order number and put it in "orderPrefix".
    var orderPrefix = orderNum.substr(0,3);
    // Remove the dialog box from memory.
    getDataDialog.destroy();
    // Store the folder prefix into "folderPrefix".
    var folderPrefix = "/g/ ArtDept/JOBS/" + orderPrefix + "000-" + orderPrefix + "999/"
    // Open the document with the order number.
    var myDoc = app.open(File(folderPrefix + orderNum + " Folder/" + orderNum + ".indd"), true);
    }
else{
    getDataDialog.destroy();
    }

So, if the order number entered is "405042", it will look in the "405000-405999" folder, then into the packaged folder called "405042 Folder", then open the .indd file inside that. Trouble is, we sometimes have several packages within a folder. For example, we might have:

405000-405999/405007/405007_N10/405007_N10.indd
405000-405999/405007/405007_C12/405007_C12.indd
405000-405999/405007/405007_Orange/405007_Orange.indd

I would want the script to open up each of those files, in turn, and perform some tasks on them. I'm certain that it's possible, but I just need to know how to code it.


Solution

  • If I understand your problem correctly, there are two parts:

    Part 1: Find a certain folder meeting certain criteria. (Looks like you've got this covered.)

    Part 2: For each InDesign document that is a descendant of this folder, open it and do some processing to it.

    In the sample below, I've labeled where you should add the code that finds the top folder and the code that manipulates each document. If you run the sample as-is, it will use the script's parent folder as the top folder, and for each descendant document it will simply log its name.

    // TODO: (Part 1) Put code here that determines the top folder.
    var topFolder = (new File($.fileName)).parent; // Change me. Currently the script's folder.
    forEachDescendantFile(topFolder, doStuffIfdocument); // Don't change this line.
    
    /**
     * Does stuff to the document.
     */
    function doStuff(document) {
        // TODO: (Part 2) Put code here to manipulate the document.
        $.writeln("Found document " + document.name);
    }
    
    /**
     * Opens the given file if it ends in ".indd". Then calls doStuff().
     * 
     * @param {File} oFile
     */
    function doStuffIfdocument(oFile) {
        if (matchExtension(oFile, "indd")) {
            var document = app.open(oFile);
            try {
                doStuff(document);
            }
            finally {
                document.close(SaveOptions.YES);
            }
        }
    }
    
    /**
     * Calls the callback function for each descendant file of the specified folder.
     * The callback should accept a single argument that is a File object.
     * 
     * @param {Folder} folder The folder to search in.
     * @param {Function} callback The function to call for each file.
     */
    function forEachDescendantFile(folder, callback) {
        var aChildren = folder.getFiles();
        for (var i = 0; i < aChildren.length; i++) {
            var child = aChildren[i];
            if (child instanceof File) {
                callback(child);
            }
            else if (child instanceof Folder) {
                this.forEachDescendantFile(child, callback);
            }
            else {
                throw new Error("The object at \"" + child.fullName + "\" is a child of a folder and yet is not a file or folder.");
            }
        }
    }
    
    /**
     * Returns true if the name of the given file ends in the given extension. Case insensitive.
     *
     * @param {File} iFile
     * @param {String} sExtension The extension to match, not including the dot. Case insensitive.
     * @return {boolean}
     */
    function matchExtension(iFile, sExtension) {
        sExtension = "." + sExtension.toLowerCase();
        var displayName = iFile.displayName.toLowerCase();
        if (displayName.length < sExtension.length) {
            return false;
        }
        return displayName.slice(-sExtension.length) === sExtension;
    }