Copy link to clipboard
Copied
Dear all,
In my script FMGraph I collect tables and anchored frames in arrays of objects (aoObjects). An arry element contains
aoObjects[iObject].Name // User string from the object
aoObjects[iObject].Obj // the object (Tbl, AFrame)
aoObjects[iObject].TL // text loction of object (anchor paragraph)
When I then navigate to a particular object i want to see that it is selected (there may be multiple tables/frames on a page).
oTL = aoObjects[iObject].TL;
oTR = new TextRange(oTL, oTL);
oDoc.TextSelection = oTR;
oDoc.ScrollToText(oTR);
selects the anchor point - not the object itself. How to select the object to make the selection visible?
Hi Klaus,
here's the way to select a table:
...var oDoc = app.ActiveDoc;
var aTabs = [];
var flow = oDoc.MainFlowInDoc;
GetTblInFlow(oDoc,aTabs);
var SelTbl = aTabs[0];
oDoc.SelectedTbl = SelTbl.obj;
var oPgf = SelTbl.obj.TextLoc.obj
var oTblAnchors = oPgf.GetText(Constants.FTI_TblAnchor);
var oAnchorOffset = oTblAnchors[0].offset;
var oTlocStart = new TextLoc (oPgf, oAnchorOffset);
var oTlocEnd = new TextLoc (oPgf, oAnchorOffset +1);
oDoc.TextSelection
Copy link to clipboard
Copied
Hi Klaus,
here's the way to select a table:
var oDoc = app.ActiveDoc;
var aTabs = [];
var flow = oDoc.MainFlowInDoc;
GetTblInFlow(oDoc,aTabs);
var SelTbl = aTabs[0];
oDoc.SelectedTbl = SelTbl.obj;
var oPgf = SelTbl.obj.TextLoc.obj
var oTblAnchors = oPgf.GetText(Constants.FTI_TblAnchor);
var oAnchorOffset = oTblAnchors[0].offset;
var oTlocStart = new TextLoc (oPgf, oAnchorOffset);
var oTlocEnd = new TextLoc (oPgf, oAnchorOffset +1);
oDoc.TextSelection = new TextRange(oTlocStart,oTlocEnd);
function GetTblInFlow(foDoc,faTabs)
{
var textItems = flow.GetText(Constants.FTI_TblAnchor);
for (var i = 0; i < textItems.length; i++)
{
faTabs.push(textItems)
}
}
Copy link to clipboard
Copied
What Rick is indicating in a general way comes down to one small change in your existing script. Instead of creating a text range from two identical TLoc elements, you need to create a second TLoc element with an offset + 1. What your code is doing is pointing to a text location. Making the range extend one character position to the right will make the entire object fall within the selection.
You could try to add this line after you create your TR:
TR.end.offset++;
Copy link to clipboard
Copied
To test the code below, put your cursor in any table in the active document.
#target framemaker
var doc, tbl, textLoc, textRange;
doc = app.ActiveDoc;
tbl = doc.SelectedTbl;
// Text location of the table
textLoc = tbl.TextLoc;
// Make a text range so that it includes the table anchor.
textRange = new TextRange (textLoc, new TextLoc (textLoc.obj, textLoc.offset + 1));
// Select the table.
doc.TextSelection = textRange;
Of course, best practice is to generalize this into a function so you can use it on any table:
selectTable (tbl, doc);
function selectTable (tbl, doc) {
var textLoc, textRange;
textLoc = tbl.TextLoc;
textRange = new TextRange (textLoc,
new TextLoc (textLoc.obj, textLoc.offset + 1));
doc.TextSelection = textRange;
}
You are dealing with tables and anchored frames so you can generalize it further (it would also work with markers):
selectAnchoredObject (tbl, doc);
function selectAnchoredObject (anchoredObj, doc) {
var textLoc, textRange;
textLoc = anchoredObj.TextLoc;
textRange = new TextRange (textLoc,
new TextLoc (textLoc.obj, textLoc.offset + 1));
doc.TextSelection = textRange;
}
Copy link to clipboard
Copied
Wow, such a host of good ideas!
I will need to check out which one would fit best...
Klaus: thanks for this method to collect the tables/frames. I will check whether the order is as they appear (OK) or as they are created (less OK).
Jang: Thanks for the tip - it seems that Rick already deals with that +1 in 2nd and 3rd snippet.
Rick: Great input
So, let me work with Your contributions!
Klaus
Copy link to clipboard
Copied
Combining Klaus' and Rick's input I got this working prototype:
/* CollectTables.jsx ====== UTF-8 =================================================================
Collect tables in main flow and select them one be the other.
Display the User String of the object
Reference Klaus Göbel, Rick Quatro; https://forums.adobe.com/thread/2597350
History 2019-02-21
*/ ; // ===========================================================================================
#target framemaker
main ();
function main () {
var oDoc, aoTables = [], oFlow, nTables, j, sName;
oDoc = app.ActiveDoc;
oFlow = oDoc.MainFlowInDoc;
GetTblInFlow (oFlow,aoTables);
nTables = aoTables.length;
for (j = 0; j < nTables; j++) {
SelectAnchoredObject (aoTables
, oDoc) sName = aoTables
.obj.UserString; alert (sName, "Usert String", false); // stop to see the selection
}
alert (nTables + " tables displayed", "Collect Tables in Flow", false);
} //--- end main
function GetTblInFlow(oFlow,aoTables) {
var j, aTextItems = [];
aTextItems = oFlow.GetText(Constants.FTI_TblAnchor);
for (var j = 0; j < aTextItems.length; j++) {
aoTables.push(aTextItems
) }
} //--- end GetTblInFlow
function SelectAnchoredObject (anchoredObj, oDoc) {
var oTL, oTR, oTL1;
oTL = anchoredObj.obj.TextLoc;
oTL1 = new TextLoc (oTL.obj, oTL.offset + 1);
oTR = new TextRange (oTL, oTL1);
oDoc.TextSelection = oTR;
oDoc.ScrollToText(oTR); // Selection is viewed
} //--- end SelectAnchoredObject
Thank You all - to whom I now should give the credit?
... and of course it was easy to create the variant of this for anchored frames!
Copy link to clipboard
Copied
Hi Klaus,
A few suggestions for minor improvements:
1) I would rename GetTblInFlow to GetTblsInFlow since you are getting all of the tables in the flow, not just one.
2) On line 32, you are pushing the TextItem into your array, but why not just push the object itself into the array?
aoTables.push (aTextItems
That means you only use .obj once here and don't need it throughout the rest of the script.
3) When you have a "Get" function, I like to set the return variable inside of the function itself instead of outside. So, line 17 would become
aoTables = GetTblInFlow (oFlow);
line 28 would become
var j, aTextItems = [], tbls = [];
line 32 would become
tbls.push (aTextItems
and you would have this between lines 32 and 33
return tbls;
Copy link to clipboard
Copied
Thank You Rick for Your suggestions.
I already renamed the function to CollectTablesInFlow.
Pushing already the object, not the text item makes things further on much clearer - because I will need this quite often during the full script.
My habit is to return just true for success or false for failure of a function - whenever reasonable (obviously not for math functions).
I decided to give the points to Klaus, because he has the lower level than Rick...
Copy link to clipboard
Copied
It turns out that the collectiing method described above does not find anchored frames in table cells. Hence I developed this alternative:
// CollectFramesInBody.jsx --- 2019-05-28
#target framemaker
var aoDocFrames = [];
CollectFramesInBody (app.ActiveDoc, aoDocFrames);
function CollectFramesInBody (oDoc, aoDocFrames) { // === Collect anchored frames in document =====
// Arguments oDoc current document
// aoDocFrames array holding the frame objects and some properties
// Returns aoDocFrames
// Called by Fgr_BtnRefreshI, Fgr_BtnRefreshP
// Calling GetPage, oFrmEtc
// Comment Only body pages are searched. Frames may be in table cells!
var aTextItems = [], j, jPage, oGraphic, oObject, oPage, sName, oTL;
oGraphic = oDoc.FirstGraphicInDoc;
while (oGraphic.ObjectValid( ) ) { // find frame on correcty linked list
if (oGraphic.constructor.name == "AFrame" ) {
oPage = GetPage (oGraphic, oDoc); // GetPage by Rick Quatro
if (oPage.type == Constants.FO_BodyPage) {
oObject = oGraphic;
sName = oObject.UserString;
oPage = Fgr_GetPage (oObject, oDoc);
jPage = oPage.PageNum; // starts with 0!
oTL = oObject.TextLoc; // text location of the frame
id = oObject.id;
aoDocFrames.push (new oFrmEtc (sName, oObject, jPage, oTL, id));
$.writeln(aoDocFrames.length-1 +"\tid= " + id); // debugging only
}
}
oGraphic = oGraphic.NextGraphicInDoc;
}
} //--- end CollectFramesInBody
function oFrmEtc (sName, oObject, jPage, oTL, id) { // used by CollectFramesInBody, CollectTablesInFlow
this.Name = sName; // User string from the object
this.Obj = oObject; // The object for further investigation
this.Page = jPage; // Pagenum (0…) on which the object occurs
this.TL = oTL; // Text location of this object in the doc
this.ID = id; // Unique ID - to compare with current obj etc.
} //--- end oFrmEtc
Copy link to clipboard
Copied
Based on my CollectMarkers which is in my 'library' since two years I figured out the ultimate solution - which collects the objects in the order of appearance in the document. I just had to find the relevant Constant.xxx:
Object | line 78 in script below | line 35 in script below |
---|---|---|
Tables | FV_FindAnyTable | FTI_TblAnchor |
AFrames | FV_FindAnchoredFrame | FTI_FrameAnchor |
Markers | FV_FindAnyMarker | FTI_MarkerAnchor |
Footnotes (not tested) | FV_FindFootnote | FTI_FnAnchor |
Variable | FV_FindAnyVariable | FTI_VarBegin |
Of course the following script is not a genric one, but serves a particular purpose. Hence the collected items are not just the (for example) Table objects. But It may serve as a template.
function Fgr_CollectTablesInBody (oDoc, aoTables) { //=== Gather table-objects, store in array ====
// Arguments oDoc current document
// aoTables array holding the table objects
// Returns number of tables collected
// Called by ReadDataFromTable, Fgr_BtnRefreshI, xxx
// Calling Fgr_SaveCurrentLocation, Fgr_GetPage, Fgr_RestoreLocation, Fgr_GetPage
// Comment Only body pages are searched.
// The order in aoTables is by appearance in doc.
// Reference KLaus Gobel, https://forums.adobe.com/message/8704549
var aTableList = [], docStart, foundTextRange, j, k, locTextRange, mListLen, nTables,
oDoc, oFindParams, oLocation, oTableTI, oTextItem, tloc;
oDoc = app.ActiveDoc
//Fgr_SetDisplay (false); // avoid flicker
//oLocation = Fgr_SaveCurrentLocation(goFMc.oCurrentDoc); // Save cursor location/TR
docStart = oDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;
tloc = new TextLoc (docStart, 0);
locTextRange = new TextRange (tloc, tloc);
oDoc.TextSelection = locTextRange;
oFindParams= GetFindParameters (); // parameters to find Tables
foundTextRange = oDoc.Find(tloc, oFindParams);
while (foundTextRange.beg.obj.ObjectValid()) {
aTableList.push(foundTextRange);
tloc = foundTextRange.end;
foundTextRange = oDoc.Find(tloc, oFindParams);
}
mListLen = aTableList.length;
if (mListLen < 1) {
// Fgr_RestoreLocation (oDoc, oLocation); // Restore cursor location/TR
// Fgr_SetDisplay (true);
return null; // common situation for new document
}
aoTables.length = 0; // clear before filling again.
for (j = 0; j < mListLen; j++) {
oTableTI = oDoc.GetTextForRange (aTableList
, Constants.FTI_TblAnchor); // FTI_FrameAnchor for (k = 0; k < oTableTI.length; k++) {
oTextItem = oTableTI
; oPage = Fgr_GetPage (oTextItem.obj, oDoc); // GetPage by Rick Quatro
if (oPage.type == Constants.FO_BodyPage) {
oObject = oTextItem.obj; // specials for my script
sName = oObject.UserString; // "
oPage = Fgr_GetPage (oObject, oDoc); // Rick's famous script
jPage = oPage.PageNum; // starts with 0!
oTL = oObject.TextLoc; // text location of the frame anchor
id = oObject.id; // special for my script
aoTables.push (new oFrmEtc (sName, oObject, jPage, oTL, id));
// $.writeln(aoTables.length-1 +"\tid= " + id +"\tpage= " + jPage);
}
}
}
//Fgr_RestoreLocation (oDoc, oLocation); // Restore cursor location/TR//Fgr_SetDisplay (true);
return aoTables.length;
} //--- end Fgr_CollectTablesInBody
function oFrmEtc (sName, oObject, jPage, oTL, id) { // used by Fgr_CollectFramesInBody, Fgr_CollectTablesInBody
this.Name = sName; // User string from the object
this.Obj = oObject; // The object for further investigation
this.Page = jPage; // Pagenum (0…) on which the object occurs
this.TL = oTL; // Text location of this object in the doc (anchor)
this.ID = id; // Unique ID - to compare with current obj etc.
} //--- end oFrmEtc
function GetFindParameters () { //=== set up parameters for various find actions ====
// Returns Parameters for the find method
// Reference FDK Function Reference, F_ApiFind(), https://forums.adobe.com/thread/961616
var findParams, propVal;
findParams = new PropVals() ;
propVal = new PropVal() ;
propVal.propIdent.num = Constants.FS_FindWrap ;
propVal.propVal.valType = Constants.FT_Integer;
propVal.propVal.ival = 0 ; // don't wrap
findParams.push(propVal);
propVal = new PropVal() ;
propVal.propIdent.num = Constants.FS_FindObject;
propVal.propVal.valType = Constants.FT_Integer;
propVal.propVal.ival = Constants.FV_FindAnyTable ;
findParams.push(propVal);
return findParams;
} //--- end GetFindParameters
Now I cansleep better and eventually close this thread.