Skip to main content
Participant
January 12, 2016
Answered

Convert an ExtendScript to FDK

  • January 12, 2016
  • 9 replies
  • 1167 views

Hi All.

I have never used FrameMaker until today so this is my first post here. 🙂

I have combined a file-reading script and Ian Proudfoot's Search and Replace script into a script that reads comma separated values from a file, and then searches the FrameMaker file for the first string in the array and if found replaces that string with the second string in the array. Making it possible to e.g. loop through a list of old product numbers and replacing them with new ones.

It does actually work, but the thing is that the people who are going to use this script are still using FrameMaker 9.So I need to convert this script to a FDK script. And i need to inform them how to run this script in FrameMaker 9.

So does anyone know if there are any easy ways of converting this ExtendScript to a FDK script to be used in FM9. And could anyone please help me understand how such a script would be run in FrameMaker 9?

Here's "my" script:

//initializing variables

var activeDoc = app.ActiveDoc;

var flow = activeDoc.MainFlowInDoc;

var findString = '';

var replaceString = '';

var considerCase = 0;

// telling FrameMaker which file to open

var csvFile = File.openDialog('Select a CSV File','comma-separated-values(*.csv):*.csv;'); 

if (csvFile != null)

{

    sarArray = readInCSV(csvFile);  //read the file into the Search And Replace (sar) array using the readInCSV function

}

for (var i=0, len=sarArray.length; i < len; i++) { //loop through the array and do a search and replace for each collection of elements in the array

    findString = sarArray[0];  //the find string is the first element in the current collection

    replaceString = sarArray[1] //the replace string is the second element in the current collection

    FindAndReplaceString(activeDoc, flow, findString, replaceString, considerCase)  //the actual search and replace routine

}

function readInCSV(fileObj)

{

     var sarArray = new Array(); //creating the array

     fileObj.open('r');  //open the file for reading

     fileObj.seek(0, 0);  //go to the beginning of the file

     while(!fileObj.eof)  //as long as end of file has not been reached

     {

          var thisLine = fileObj.readln(); //read each line

          var csvArray = thisLine.split(';'); //split the line in two at the ; character

          sarArray.push(csvArray); //insert each value into the array

     }

     fileObj.close();  //close the file

     return sarArray; //and return an array full of search and replace strings

}

function FindAndReplaceString(activeDoc, flow, findString, replaceString, considerCase) {

    var tr = new TextRange();

    var restoreTR, frame = 0;

    var loopCounter = 0, replacementCounter = 0;

    var findParams = new PropVals();

    //if the flow object is not valid, assume the main flow

    if(activeDoc.ObjectValid() && !flow.ObjectValid()){

        flow = activeDoc.MainFlowInDoc;

    }

    //get the first text frame in the flow, a starting point to

    //find the first paragraph

    if(flow.ObjectValid()){

        frame = flow.FirstTextFrameInFlow;

    }

    //At this point, if we don't have a frame object, might as well abort.

    if(!frame.ObjectValid()){

        Alert("Could not find a starting point for the search. Cannot continue." , Constants.FF_ALERT_CONTINUE_WARN);

    return replacementCounter;

    }

    //store the original text selection as an amenity to restore after the action.

    restoreTR = activeDoc.TextSelection;

    //now, set up the starting text range as the very beginning

    //of the flow. We'll move straight from beginning to end.

    tr.beg.obj = tr.end.obj = frame.FirstPgf;

    tr.beg.offset = tr.end.offset = 0;

    //set up our find parameters. We want to configure it to look

    //for a string and perhaps be case sensitive. We don't need

    //the find to wrap because we are controlling the flow from

    //beginning to end.

    findParams = AllocatePropVals(2);

    findParams[0].propIdent.num = Constants.FS_FindText;

    findParams[0].propVal.valType = Constants.FT_String;

    findParams[0].propVal.sval = findString;

    findParams[1].propIdent.num = Constants.FS_FindCustomizationFlags;

    findParams[1].propVal.valType = Constants.FT_Integer;

    if(considerCase){

        findParams[1].propVal.ival = Constants.FF_FIND_CONSIDER_CASE;

    }

    else{

        findParams[1].propVal.ival = 0;

    }

    //initialize the errno global, which will be used to

    //track the progress of the find and replace

    FA_errno = Constants.FE_Success;

    //and do an initial find to get started.

    tr = activeDoc.Find(tr.beg, findParams);

    //now, run the find and replace loop as long as we keep finding things.

    //The loop counter is just an emergency back door in case something

    //goes critically wrong and causes an endless loop.

    while(FA_errno === Constants.FE_Success && loopCounter++ < 1500){

    //set up the text range to clear the original text

        activeDoc.TextSelection = tr;

        //clear it

        activeDoc.Clear(0);

        //insert the new text. We should be able to use the

        //original beginning of the text range where the old text was

        //found.

        activeDoc.AddText(tr.beg, replaceString);

        //now, lets jimmy the text range in memory to place it directly

        //after the string we just inserted, so the find picks back up after that.

        tr.beg.offset += replaceString.length;

        //increment our return counter

        if(FA_errno === Constants.FE_Success){

            replacementCounter++;

        }

        //...and find the next instance. We'll reset FA_errno again just in case

        //something screwy happened while we were replacing text.

        FA_errno = Constants.FE_Success;

        tr = activeDoc.Find(tr.beg, findParams);

    }

    //we're done. Restore the document to it's original area of display

    activeDoc.TextSelection = restoreTR;

    activeDoc.ScrollToText(restoreTR);

    return replacementCounter;

}

This topic has been closed for replies.
Correct answer frameexpert

There is no "converter" to go from ExtendScript to FDK code. The FDK is C/C++ based. Your best bet is to download the FDK docs and see if you can recode it with C. You will need a MS compiler to work with the FDK.

Another alternative for FrameMaker 9 would be FrameScript (http://www.framescript.com). There is no direct conversion, but like ExtendScript, it is a scripting language. I have been using FrameScript since 1998 and it is very good and reasonably priced.

9 replies

frameexpert
Community Expert
frameexpertCommunity ExpertCorrect answer
Community Expert
January 13, 2016

There is no "converter" to go from ExtendScript to FDK code. The FDK is C/C++ based. Your best bet is to download the FDK docs and see if you can recode it with C. You will need a MS compiler to work with the FDK.

Another alternative for FrameMaker 9 would be FrameScript (http://www.framescript.com). There is no direct conversion, but like ExtendScript, it is a scripting language. I have been using FrameScript since 1998 and it is very good and reasonably priced.

www.frameexpert.com
trondkAuthor
Participant
January 13, 2016

Thank you very much for your swift response, Rick.

As you understand, Im not new to scripting, but I am new to FrameMaker. Will FrameScript be able to pull off the same thing as this ExtendScript? And how does FrameScript handle the search parameters and constants?

Another important question is whether FrameScript needs to be installed on the computer running FrameMaker 9, or is it enough that it is installed on our computer.

Best regards

Trond

frameexpert
Community Expert
Community Expert
January 13, 2016

Hi Trond, Yes, FrameScript will need to be installed on each computer that has to run the script. They use an activation scheme to ensure unique licenses on each FrameMaker installation. FrameScript can do what your ExtendScript script can do. -Rick

www.frameexpert.com