Skip to main content
Fightergator
Inspiring
October 14, 2022
Answered

Searching a Book Using ExtendScript

  • October 14, 2022
  • 1 reply
  • 1560 views

I'm searching a book using ExtendScript.  I can do it opening each document individually using the code below. Is there a better way; possibly something like:  var book = app.ActiveBook; var comp = book.FirstComponentInBook; comp = comp.NextBookComponentInDFSOrder? I ran across some script using these objects and methods from 2013, but it didn't work with my test book. 

//Code that works to step through all docs in book
doc = app.FirstOpenDoc;

while (doc.ObjectValid()) {
doc = SimpleOpen(doc.Name);
doc = app.ActiveDoc;
       // findAndChange(doc)

doc = doc.NextOpenDocInSession; // Open next document in book
}

    Correct answer frameexpert

    You can't have an active book and an active document at the same time. That is why you need the ObjectValid method to test what you have active. In my scripts that work on either an active book or document, I usually use something like this:

    main ();
    
    function main () {
    
        var book, doc;
    
        book = app.ActiveBook;
        if (book.ObjectValid () === 1) {
            // Call a function to process the book.
        }
        else {
            doc = app.ActiveDoc;
            if (doc.ObjectValid () === 1) {
                // Call a function to process the document.
            }
        }
    }

    1 reply

    frameexpert
    Community Expert
    Community Expert
    October 15, 2022

    Here is a shell that I use all the time. The idea is that if the document is already open, it is used; otherwise, the script opens it. When you are done processing it, the script will only save and close documents that it opened. This is consistent with FrameMaker's built-in behavior. You never want to save and close an open document unless you are sure you get the desired result.

    function processBook (book) {
        
        var bookComp = 0, doc = 0;
        
        // Loop through all of the components in the book.
        bookComp = book.FirstComponentInBook;
        while (bookComp.ObjectValid ()) {
            if (bookComp.ComponentType === 512) {
                // Get the document returned in a JavaScript object.
                doc = getDocument (bookComp.Name, undefined, true);
                if (doc) {
                    book.StatusLine = "Processing " + File(bookComp.Name).displayName;
                    // Call the function to process the document.
                    processDoc (doc);
                    // If the document was opened by the script, save it and close it.
                    if (doc.openedByScript === true) {
                        doc.SimpleSave (bookComp.Name,false);
                        doc.Close (true);
                    }
                }
            }
            bookComp = bookComp.NextBookComponentInDFSOrder;
        }
        // Reset the book status line.
        book.StatusLine = "";
    }
    
    function getDocument (filename, structApp, visible) {
        
        // See if the document is already open.
        var doc = docIsOpen (filename);
        if (doc) {
            return doc;
        } else {
            // The document is not already open, so open it.
            return openDocOrBook (filename, structApp, visible);
        }
    }
    
    function docIsOpen (filename) {
        
        // Make a File object from the file name.
        var file = File (filename);
        // Uppercase the filename for easy comparison.
        var name = file.fullName.toUpperCase ();
    
        // Loop through the open documents in the session.
        var doc = app.FirstOpenDoc;
        while (doc.ObjectValid () === 1) {
            // Compare the document’s name with the one we are looking for.
            if (File (doc.Name).fullName.toUpperCase () === name) {
                // The document we are looking for is open.
                doc.openedByScript = false;
                return doc;
            }
            doc = doc.NextOpenDocInSession;
        }
    }
    
    function openDocOrBook (filename, structApp, visible) {
        
        var i = 0, docOrBook = 0;
    
        // Get default property list for opening documents.
        var openProps = GetOpenDefaultParams ();
        // Get a property list to return any error messages.
        var retParm = new PropVals ();
    
        // Set specific open property values to open the document.
        i = GetPropIndex (openProps, Constants.FS_AlertUserAboutFailure);
        openProps[i].propVal.ival = false;
        i = GetPropIndex (openProps, Constants.FS_MakeVisible);
        openProps[i].propVal.ival = visible;
        i = GetPropIndex (openProps, Constants.FS_FileIsOldVersion);
        openProps[i].propVal.ival = Constants.FV_DoOK;
        i = GetPropIndex (openProps, Constants.FS_FileIsInUse);
        openProps[i].propVal.ival = Constants.FV_ResetLockAndContinue;
        i = GetPropIndex (openProps, Constants.FS_FontChangedMetric);
        openProps[i].propVal.ival = Constants.FV_DoOK;
        i = GetPropIndex (openProps, Constants.FS_FontNotFoundInCatalog);
        openProps[i].propVal.ival = Constants.FV_DoOK;
        i = GetPropIndex (openProps, Constants.FS_FontNotFoundInDoc);
        openProps[i].propVal.ival = Constants.FV_DoOK;
        i = GetPropIndex (openProps, Constants.FS_RefFileNotFound);
        openProps[i].propVal.ival = Constants.FV_AllowAllRefFilesUnFindable;
        if (structApp !== undefined) {
            i = GetPropIndex (openProps, Constants.FS_StructuredOpenApplication);
            openProps[i].propVal.sval = structApp;
        }
    
        // Attempt to open the document.
        docOrBook = Open (filename, openProps, retParm);
    
        if (docOrBook.ObjectValid () === 1) {
            // Add a property to the document or book, indicating that the script opened it.
            docOrBook.openedByScript = true;
        }
        else {
            // If the document can't be open, print the errors to the Console.
            PrintOpenStatus (retParm);
        }
    
        return docOrBook; // Return the document  or book object.
    }
    
    Fightergator
    Inspiring
    October 22, 2022

    Thanks Rick...I saw functions from this code in your FindChangeBatch script, but haven't had time to trace each of the function "gets" to have a clear idea of how it worked.  This is exactly what I was looking for.  I agee I don't want the script saving and closing books.  The editor needs to do that after confirming the documents (chapters) reflect the desired changes.

     

    BTW, thanks for urging me (and others) to modularize our code into functions.  It took me a couple of days to get the hang of it, but I love what it did to the code of my longest and most complex script...and like you said, now I can quickly build new scripts using functions I've already written and tested.  Now I just have to figure out a way to organize and store them.   

    frameexpert
    Community Expert
    Community Expert
    October 24, 2022

    I use a program called FileLocator Pro--the free version is called Agent Ransack--to search my file library of scripts. I can usually find what I am looking for in my collection to use in a new script. Also, you may want to consider creating a scipt file that has your common functions. You can put it in the startup folder and those functions will be available from any other script. It keeps you from having to repeat a bunch of code in multiple scripts.