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

Find variables in appearing order

Community Expert ,
Dec 13, 2017 Dec 13, 2017

Copy link to clipboard

Copied

Dear friends,

Collecting variables in the order of their creation works fine for me:

function GetVarsInDoc (oDoc, aDocVars) { //=== Fill the doc variables array with all found vars in Doc ======
var oTR, oVar, sVarName, sValue;
  aDocVars.length = 0;                            // clear array for new build up
  oVar = oDoc.FirstVarInDoc;                      // the variable in the text
  while (oVar.ObjectValid()) {
    sVarName = oVar.VarFmt.Name;                  // name of the variable
    sValue   = oVar.VarFmt.Fmt;                   // contents of variable
    oTR      = oVar.TextRange;                    // the text range of the variable
    aDocVars.push (new oVariable (sVarName, sValue, oVar, oTR));
    oVar = oVar.NextVarInDoc;
  }
} //--- end GetVarsInDoc

When walking (do you have a better term) through the collected variables the display jumps between body and master pages and the first few variables are all on the master pages. This jumping irritates the user. Hence I want to collect the variables in the order as they appear in the document (will jump only once to the master pages) - same as when using the Find dialogue with Any Variable.

The following, however, does not do anything at all - what is wrong?

function GetVarsInDoc (oDoc, aDocVars) { //=== Collect variables in the 'natural' order ===========
var findParams, oPara, oTRnew TextRange(), oTxtLoc1, oTxtLoc2;
  oPara = oDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf; // Start at the beginning of the document
  oTR.beg.obj =  oTR.end.obj = oPara;
  oDoc.ScrollToText(oTR);        //  test - nothing to see
  findParams = GetFindParameters (2, null);       // Get the find parameters for finding any variable
  InitFA_errno ();                                // reset - it is write protected (function not shown here)
  oTR = oDoc.Find(oTR.beg, findParams);           // and do an initial find to get started.
  while(FA_errno === Constants.FE_Success) {
    oDoc.TextSelection = oTR;                     // set up the text range

// here code is required to come from oTR  to the variable object for storage
    oDoc.ScrollToText(oTR);        //  test - nothing to see
    InitFA_errno ();                              // to be used to track the progress of the find and replace
    oTR = oDoc.Find(oTR.end, findParams);         // prepare for next find
  }
} //--- end GetVarsInDoc

This is a stripped down version:

function GetFindParameters (iType, sSearch) { //=== set up parameters for various find actions ====
var findParams, propVal;
  findParams = new PropVals() ;
  switch (iType) {
    case 2: // ---------------------------------- find any variable
      propVal = new PropVal() ;
      propVal.propIdent.num = Constants.FS_FindObject; 
      propVal.propVal.valType = Constants.FT_Integer; 
      propVal.propVal.ival = Constants.FV_FindAnyVariable ; 
      findParams.push(propVal); 
      return findParams;
    default:
      return null;
  }
} //---  end GetFindParameters

Who can give me a hint?

Klaus

TOPICS
Scripting

Views

488

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 1 Correct answer

Community Expert , Dec 15, 2017 Dec 15, 2017

The "find" method should also work on master and reference pages as well as body pages. You just have to switch to the current page type before invoking the find.

doc.CurrentPage = doc.FirstMasterPageInDoc;

doc.CurrentPage = doc.FirstRefPageInDoc;

Votes

Translate

Translate
Community Expert ,
Dec 13, 2017 Dec 13, 2017

Copy link to clipboard

Copied

I don't have time to provide code right now, but I would collect 2 arrays of variables, those on the master pages and those on body pages. Then you can process each array, starting with master page variables. Something like this:

var variables = {masterPageVars: [], bodyPageVars: []};

// Loop through the variables.

// If the variable is on a master page, add it to the first array.

variables.masterPageVars.push (variable);

// Else add it to the other array.

variables.bodyPageVars.push (variable);

// Now you can loop through them one at a time.

varsArray = variables.masterPageVars;

...

varsArray = variables.bodyPageVars;

Does that make sense?

Votes

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 14, 2017 Dec 14, 2017

Copy link to clipboard

Copied

Sorry Rick, no success.

It turns out that oDoc.FirstVarInDoc and oVar.NextVarInDoc collect in the order of creation and hence traverse all types of pages.

I have now a version which finds all variables in the correct order - but only on the body pages. I have no idea how to collect on the other page types.

// CollectVariablesB.jsx
#target framemaker
var oDoc = app.ActiveDoc, aDocVars = [];

GetVarsInDoc (oDoc, aDocVars);
$.bp(true);
var oTextRange = aDocVars[0].TextRange            // go to the first variable
    oDoc.ScrollToText(oTextRange);
$.bp(true);
var maxIndex = aDocVars.length - 1;
    oTextRange = aDocVars[maxIndex].TextRange    // go to the last variable
    oDoc.ScrollToText(oTextRange);
// ================================================================================================

function oVariable (sName, sContents, oVar, bUsed, bSystem, oTr) {
  this.Name    =  sName;                        // Name of variable
  this.Contents =  sContents;                    // Contents of variable
  this.VarObj  =  oVar;                          // Var object in document
  this.VarUsed  =  bUsed;                        // User var is used in document
  this.IsSystem =  bSystem;                      // true for system variable
  this.TextRange=  oTr;                          // textrange of this occurance in the doc
} //--- end oVariable

function GetVarsInDoc (oDoc, aDocVars) { //=== Collect variables in the 'natural' order ===========
// Comment  Variables are found only on body pages, although they may exist on all page types
//          (Body, Master, Reference). How to get stuff from the other page types?
//          oDoc.FirstBodyPageInDoc, oDoc.FirstMasterPageInDoc, oDoc.FirstRefPageInDoc are dead ends
var aVarsRange, bIsSystem, bIsUsed, findParams, jFound = 0, iVrLen, oPara, oTextItem, oTR = new TextRange(), oVar, sVarName, sValue;

  oPara = oDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;
  oTR.beg.obj =  oTR.end.obj = oPara;            // starting text range as the very beginning
  oDoc.TextSelection = oTR;
  oTR.beg.offset = oTR.end.offset = 0;
  findParams = GetFindParameters (2, null);      // finding any variable, no wrap
  InitFA_errno ();                                // reset - it is write protected
  oTR = oDoc.Find(oTR.beg, findParams);          // and do an initial find to get started.

  while(FA_errno === Constants.FE_Success) {
    jFound += 1;
    oDoc.TextSelection = oTR;                    // set up the text range
    aVarsRange = oDoc.GetTextForRange (oTR, Constants.FTI_VarBegin);  // this is an array
    iVrLen = aVarsRange.length;                    // have not found anything other than 1
    if (iVrLen === 0) {                            // superfluous ?
      return null;                                // no selection, assume 0 in calling routine
    }
    oTextItem = aVarsRange[0];                    // have not found anything other than 1 item
    oVar = oTextItem.obj;
    sVarName = oVar.VarFmt.Name;                  // name of the variable
    sValue  = oVar.VarFmt.Fmt;                  // contents of variable
    oTR      = oVar.TextRange;                    // the text range of the variable
    bIsSystem= (oVar.VarFmt.SystemVar !== Constants.FV_VAR_USER_VARIABLE);
    bIsUsed  = UsrVarIsUsed (oDoc, sVarName);
    aDocVars.push (new oVariable (sVarName, sValue, oVar, bIsUsed, bIsSystem, oTR));
$.writeln ("sVarName= " + sVarName);
    InitFA_errno ();                              // track the progress
    oTR = oDoc.Find(oTR.beg, findParams);        // prepare for next find
  }
$.writeln ("jFound= " + jFound + " nVars= " + aDocVars.length );
} //--- end GetVarsInDoc

function InitFA_errno() { //=== Reset FA_errno as it is write protecte ===========================
// Reset FA_errno as it is write protected
// see https://forums.adobe.com/thread/962910
  app.GetNamedMenu("!MakerMainMenu");            //If this fails, you've got bigger problems
  return;
}

function GetFindParameters (iType, sSearch) { //=== set up parameters for various find actions ====
// stripped down version for case 2 only
var findParams, propVal;

  findParams = new PropVals() ;
  switch (iType) {
    case 2: // ---------------------------------- find any variable, don't wrap
      propVal = new PropVal() ; 
      propVal.propIdent.num = Constants.FS_FindWrap ; 
      propVal.propVal.valType = Constants.FT_Integer; 
      propVal.propVal.ival = 0 ;  // don't start at the beginning 
      findParams.push(propVal); 
      propVal = new PropVal() ;
      propVal.propIdent.num = Constants.FS_FindObject; 
      propVal.propVal.valType = Constants.FT_Integer; 
      propVal.propVal.ival = Constants.FV_FindAnyVariable ; 
      findParams.push(propVal); 
      return findParams;
  }
} //---  end GetFindParameters

Votes

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 14, 2017 Dec 14, 2017

Copy link to clipboard

Copied

I think you are making this more complicated than you have to. Take a look at the stand-alone code below. The key is looping through all of the variables in the document, but separating them as you collect them into two separate arrays. Then you can process the arrays in whatever order you want; in this case, I am processing the master page variables first and then the body page variables. You can see how I collect them first in the "getVariables" function and sort them as I am collecting them. Then you can navigate them after you collect them.

#target framemaker

var doc = app.ActiveDoc;

// Get the variables in the document.

var variables = getVariables (doc);

// Write the master page variables first.

writeVariablesToConsole (variables.masterPageVars, "Master Pages");

// Now write the body page variables.

writeVariablesToConsole (variables.bodyPageVars, "Body Pages");

function writeVariablesToConsole (variables, pageType) {

   

    var i, count, variable;

   

    count = variables.length;

   

    $.writeln ("There are " + count + " variables on this document's " + pageType);

    for (i = 0; i < count; i += 1) {

        $.writeln (variables.VarFmt.Name);

    }

   

}

function getVariables (doc) {

   

    var variable, page, variables;

   

    // Create an object containing 2 arrays.

    variables = {bodyPageVars: [], masterPageVars: []};

   

    variable = doc.FirstVarInDoc;

    while (variable.ObjectValid () === 1) {

        page = getPage (variable, doc);

        if (page.constructor.name === "BodyPage") {

            variables.bodyPageVars.push (variable);

         }

        else if (page.constructor.name === "MasterPage") {

            variables.masterPageVars.push (variable);

        }

        variable = variable.NextVarInDoc;

    }

       

    return variables;

}

function getPage (obj, doc) {

   

    var frame = 0, cell = 0;

    var objType = "", prop = 0;

   

    while (obj) {

       

        frame = obj;

        objType = obj.constructor.name;

       

        switch (objType) {

            case "SubCol" :

                obj = obj.ParentTextFrame;

                break;

            case "Tbl" :

                obj = obj.FirstRowInTbl.FirstCellInRow;

                break;

            case "Row" :

                obj = obj.FirstCellInRow;

                break;

            case "Cell" :

            case "Pgf" :

            case "AFrame" :

                obj = obj.InTextFrame;

                break;

            case "TextLine" :

            case "TextFrame" :

            case "UnanchoredFrame" :

            case "Arc" :

            case "Ellipse" :

            case "Group" :

            case "Inset" :

            case "Line" :

            case "Math" :

            case "Polygon" :

            case "Polyline" :

            case "Rectangle" :

            case "RoundRect" :

                if (obj.FrameParent.ObjectValid()) {

                    obj = obj.FrameParent;

                } else {

                    obj = 0;

                }

                break;

            case "Var" :

            case "XRef" :

                prop = doc.GetTextPropVal (obj.TextRange.beg, Constants.FP_InTextObj);

                var obj = prop.propVal.obj;

                break;           

            default:

                // Prevent endless loop if unknown object type is found.

                obj = 0;

                break;

        }

    }

    if (frame) {

        return frame.PageFramePage;

    } else {

        return 0;

    }

}

Votes

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, 2017 Dec 15, 2017

Copy link to clipboard

Copied

Thank You Rick

Currently i have implemented this method according to your information given for "Display selection on proper page type".

Using this method for the masterpages presents the navigated variables in an 'unnatural' order: the order in which they were put into the document. The display thus jumps back and forth in the document (f it is not a brand new document created in order). Hence I decided to implement a combination of both methods.

See this pdf.

Votes

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, 2017 Dec 15, 2017

Copy link to clipboard

Copied

The "find" method should also work on master and reference pages as well as body pages. You just have to switch to the current page type before invoking the find.

doc.CurrentPage = doc.FirstMasterPageInDoc;

doc.CurrentPage = doc.FirstRefPageInDoc;

Votes

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 18, 2017 Dec 18, 2017

Copy link to clipboard

Copied

LATEST

Thank You Rick for this important hint.

Now I run the find method in a loop to get the variables from all page types. During testing I have discovered that a valid FM document may have strange properties:

This requires some checks in the function:

function CollectVarsInDoc (oDoc, aDocVars) { //=== Collect variables in the 'natural' order =======
var aVarsRange, bIsSystem, findParams, jFound = 0, jPageType, iVrLen, oFirst, oPage, oPara,
    oSavedLoc, oTextItem,  oTR = new TextRange(), oVar, sVarName, sValue,
    aPages = [oDoc.FirstBodyPageInDoc, oDoc.FirstMasterPageInDoc, oDoc.FirstRefPageInDoc];

  aDocVars.length = 0;                            // clear array for refill
  for (jPageType = 0; jPageType < 3; jPageType++) { // for all page types
    oFirst = aPages[jPageType];
    if (oFirst.id == 0 && jPageType != 1) {continue}; // only master page(s) exist
    oDoc.CurrentPage = oFirst;
    oPage = oDoc.CurrentPage;
    oPara = oPage.PageFrame.FirstGraphicInFrame.FirstPgf;
    while (oPara == undefined) {                  // can happen on ref pages
      oPage = oPage.PageNext;
      if (oPage.id == 0) {
        goFMc.nDocVars = aDocVars.length;
        return}                                  // no next page available
      oPara = oPage.PageFrame.FirstGraphicInFrame.FirstPgf;
    }
    oTR  = oDoc.TextSelection;
    oTR.beg.obj =  oTR.end.obj = oPara;
    oDoc.TextSelection = oTR;
    oTR.beg.offset = oTR.end.offset = 0;

    findParams = GetFindParameters (2, null);    // finding any variable, no wrap
    InitFA_errno ();                             // reset - it is write protected
    oTR = oDoc.Find(oTR.beg, findParams);        // and do an initial find to get started.

    while(FA_errno === Constants.FE_Success) {
      jFound += 1;
      oDoc.TextSelection = oTR;                  // set up the text range
      aVarsRange = oDoc.GetTextForRange (oTR, Constants.FTI_VarBegin);  // this is an array
      iVrLen = aVarsRange.length;                // have not found anything other than 1
      if (iVrLen === 0) {                        // superfluous ?
        goFMc.nDocVars = aDocVars.length;        // what we have found so far
        return null;                             // no selection, assume 0 in calling routine
      }
      oTextItem = aVarsRange[0];                 // have not found anything other than 1 item
      oVar = oTextItem.obj;
      sVarName = oVar.VarFmt.Name;               // name of the variable
      sValue  = oVar.VarFmt.Fmt;                 // contents of variable
      oTR      = oVar.TextRange;                 // the text range of the variable
      bIsSystem= (oVar.VarFmt.SystemVar !== Constants.FV_VAR_USER_VARIABLE);
      aDocVars.push (new oVariable (sVarName, sValue, oVar, bIsSystem, oTR));
      InitFA_errno ();                           // track the progress
      oTR = oDoc.Find(oTR.beg, findParams);      // prepare for next find
    }
  }
  goFMc.nDocVars = goFMc.aDocVars.length;
} //--- end CollectVarsInDoc

it's all fine now.

Klaus

Votes

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