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
1 Correct answer
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;
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?
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 oVariablefunction 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 GetVarsInDocfunction 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
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;
}
}
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.
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;
Copy link to clipboard
Copied
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

