Skip to main content
Inspiring
February 21, 2023
Question

Extendscript: finding book component with specific string in filename

  • February 21, 2023
  • 1 reply
  • 1060 views

Dear fellows,

I'm trying to put together a script that performs the following on an open FM book:

1. Creates an array of book components.

2. In the array, finds the book component with a file name that includes the word 'Carrier' and (nice to have: doesn't include the word "Internal").

3. When found, opens the book component that includes the word 'Carrier' and (nice to have: doesn't include the word "Internal").

4. Imports the conditional/variable settings from the 'Carrier' to the rest if the book components.

5. Closes all book components. 

 

Here is my code snippet.

#target framemaker

var book = app.ActiveBook;
var bookComp = book.FirstComponentInBook;
book.IsOnScreen = 1;
	
importCarrier();

function importCarrier() {
	
    var carrier = "Carrier";
	var compAr = [];

    if (book.ObjectValid()) {
        while (bookComp.ObjectValid()) {

            compAr.push(bookComp);
            bookComp = bookComp.NextBookComponentInDFSOrder;
		}
		
        for (var i = 0; i < compAr[i].length; i++) {
            alert(compAr[i].Name);
            var tMatch = compAr[i].Name.match(carrier);
				if (tMatch == carrier){
                var CarrierFileName = compAr[i].Name;
			}
        }
		
        var openParams = getOpenPrefs();
        var openReturnParams = new PropVals();
		
        var openCarrierFM = Open(CarrierFileName, openParams, openReturnParams);
        if (openCarrierFM.ObjectValid()) {

              var targetDoc = Open(bookComp.Name, openParams, openReturnParams);
                if (targetDoc.ObjectValid()) {
                    targetDoc.SimpleImportFormats(openCarrierFM, Constants.FF_UFF_COND | Constants.FF_UFF_VAR);
                    targetDoc.SimpleSave(targetDoc.Name, false);
					targetDoc.Close(1);
                }
                else { 
					alert("Cannot open " + targetDoc.Name); }
                targetDoc = bookComp.NextBookComponentInDFSOrder;
            }
			openCarrierFM.Close(1);
		    
    }
}
function getOpenPrefs() {
    var params, i;

    params = GetOpenDefaultParams();

    i = GetPropIndex(params, Constants.FS_RefFileNotFound);
    params[i].propVal.ival = Constants.FV_AllowAllRefFilesUnFindable;
    i = GetPropIndex(params, Constants.FS_FileIsOldVersion);
    params[i].propVal.ival = Constants.FV_DoOK;
    i = GetPropIndex(params, Constants.FS_FontChangedMetric);
    params[i].propVal.ival = Constants.FV_DoOK;
    i = GetPropIndex(params, Constants.FS_FontNotFoundInCatalog);
    params[i].propVal.ival = Constants.FV_DoOK;
    i = GetPropIndex(params, Constants.FS_FontNotFoundInDoc);
    params[i].propVal.ival = Constants.FV_DoOK;
    i = GetPropIndex(params, Constants.FS_LockCantBeReset);
    params[i].propVal.ival = Constants.FV_DoOK;
    i = GetPropIndex(params, Constants.FS_FileIsInUse);
    params[i].propVal.ival = Constants.FV_OpenViewOnly;
    return (params);
}

Issues:

1. The code doesn't identify the array members' file names.

2. Doesn't recognize openCarrierFM.Close(1); as a function.

 

Will appreciate your inputs. Thank you in advance!

    This topic has been closed for replies.

    1 reply

    frameexpert
    Community Expert
    Community Expert
    February 21, 2023

    It is best to break down your script into separate tasks and then post the questions separately. Once you have each task solved, you can assemble a complete script. Here is some code that will loop through a book, and apply a "find" regular expression and an "exclude" regular expression to each base file name. If both conditions are fulfilled, the book component is added to an array of BookComponent objects. See if this makes sense to you. Once you have a list of book components, you can do the other tasks.

     

     

    #target framemaker
    
    main ();
    
    function main () {
        
        var book, matchedComps;
        
        book = app.ActiveBook;
        if (book.ObjectValid () === 1) {
            matchedComps = getMatchingComps (book,
                /Carrier/i, /Internal/i);
            alert (matchedComps);
        }
    }
    
    function getMatchingComps (book, findRegex, excludeRegex) {
        
    	var matchedComps, bookComp, file;
    	
    	// An array of matched book components.
    	matchedComps = [];
    	
        // Loop through all of the components in the book.
        bookComp = book.FirstComponentInBook;
        while (bookComp.ObjectValid () === 1) {
            // Make a file object for the component.
    		file = new File (bookComp.Name);
    		// See if the find regular expression matches the base 
    		// file name and the exclude regex doesn't match.
    		if ((findRegex.test (file.name) === true) &&
    		    (excludeRegex.test (file.name) === false)) {
    		    // Add it to the array.
    			matchedComps.push (bookComp);
    		}
            bookComp = bookComp.NextBookComponentInDFSOrder;
        }
        
        return matchedComps;    
    }

     

    Rom_BaAuthor
    Inspiring
    February 21, 2023

    Hi Rick,

     

    I greatly appreciate your response! 

    I totally agree with your golden rule of chunking the code into specific actions and testing each chunk separately. 

    I think finding a specific string in the file name and negating the existence of another string is the most challenging part.

     

    I went over your code sample and I have a couple of questions:

    1. You declare the matchedComps variable twice, both in the function prototype and in the main() function. Why is there a need to declare it twice, instead of definining it just in the prototype?

     

    2. What's the function of the slash chars and "i" in /Carrier/i? 

     

    3. When running your code, the alert function displays "[Object BookComponent]". How can one display the bookComp name added to the array instead? 

    Thank again!

    frameexpert
    Community Expert
    Community Expert
    February 21, 2023

    1. Because I want it to be local to both functions.

    2. This is a regular expression which allows you to match patterns in addition to literal strings. The i flag means a case-insensitive search. Google Javascript regular expressions.

    3. I am adding each BookComponent to the array. You can easily get its Name property by using matchedComps[0].Name.