• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers

Searching a Book Using ExtendScript

Participant ,
Oct 14, 2022 Oct 14, 2022

Copy link to clipboard

Copied

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
}

Views

289

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 3 Correct answers

Community Expert , Oct 15, 2022 Oct 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 
...

Likes

Translate

Translate
Community Expert , Oct 24, 2022 Oct 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.

Likes

Translate

Translate
Community Expert , Dec 09, 2022 Dec 09, 2022

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) {
          
...

Likes

Translate

Translate
Community Expert ,
Oct 15, 2022 Oct 15, 2022

Copy link to clipboard

Copied

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.
}

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Oct 22, 2022 Oct 22, 2022

Copy link to clipboard

Copied

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.   

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 24, 2022 Oct 24, 2022

Copy link to clipboard

Copied

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.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Dec 08, 2022 Dec 08, 2022

Copy link to clipboard

Copied

Took me a while to get back to the second part of your post regarding ways to file functions so I can find them later.  I'm going to start by creating a script file for my common functions, and may purchase FileLocator Pro if it becomes too unwieldy to manage.  Also, thanks for the tip on putting the folder with my favorite scripts in the FM user startup folder.  I was completely unaware you could do that...and Adobe's doesn't say anything about it under "Managing Scripts" in the user guide...very useful information.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Dec 08, 2022 Dec 08, 2022

Copy link to clipboard

Copied

I finally got around to your script for processing a book.  I must be doing something wrong.  I have a book open in FrameMaker.  Everything tells me it's a valid book object, but it does not appear as a valid object.  Using the code below...

var doc = app.ActiveDoc;
    $.writeln (doc.Name);
var odocName = doc.Name;
var book = app.ActiveBook;
    $.writeln(book);
var bookComp = book.FirstComponentInBook;
    $.writeln(bookComp);
var compType = bookComp.ComponentType;
    $.writeln("Component Type = " + compType);

I get the following results...

C:\Users\fight\Desktop\Boeing-737_CH01.fm
[object Book]
[object BookComponent]
Component Type = 0

While the ActiveDoc tests valid, neither book nor bookComp test valid.  Without a valid book object, the processBook function won't work.  Everything else in Frame treats the book as a book. 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 09, 2022 Dec 09, 2022

Copy link to clipboard

Copied

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.
        }
    }
}

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Dec 11, 2022 Dec 11, 2022

Copy link to clipboard

Copied

Thanks Rick...kind of an "aha" moment for me.  Once you understand, the solution is relatively simple.  Basically, test every object you are trying to select before trying to access it.  The workaround I came up closes all the open documents in the book and reopens them individually for processing.  Basically, using brute force.  This should be a lot easier. 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 12, 2022 Dec 12, 2022

Copy link to clipboard

Copied

I use brute force sometimes just to get things to work. Then the "aha" moment comes and I can sheepishly clean things up. Fortunately, most clients don't actually look at my code 🙂

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Dec 14, 2022 Dec 14, 2022

Copy link to clipboard

Copied

Thanks Rick...good to know the experts do the same thing.  I'm coming at this with zero computer coding training.  However, spent eight years developing a set of editing tools in Word VBA, with well worn copies of Mansfield's Mastering VBA dating back to 2010.  Now trying to translate the FindChange modules into ExtendScript so editors don't have to jump between two docs to make the changes.  My scripts aren't pretty, but I'll take your advice and improve them as I get smarter.  Thanks.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 15, 2022 Dec 15, 2022

Copy link to clipboard

Copied

LATEST

I am glad to see that you are diving in and experimenting. That is the best way to learn. I enjoy helping when I can.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines