Make selection visible for table/frame

Adobe Community Professional ,
Feb 21, 2019 Feb 21, 2019

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?

TOPICS
Scripting

Views

1.2K

Likes

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

Enthusiast , Feb 21, 2019 Feb 21, 2019
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 ...

Likes

Translate

Translate
Enthusiast ,
Feb 21, 2019 Feb 21, 2019

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)

        }

}

Likes

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
Advocate ,
Feb 21, 2019 Feb 21, 2019

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++;

Likes

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
Adobe Community Professional ,
Feb 21, 2019 Feb 21, 2019

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;

}

Likes

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
Adobe Community Professional ,
Feb 21, 2019 Feb 21, 2019

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

Likes

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
Adobe Community Professional ,
Feb 21, 2019 Feb 21, 2019

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!

Likes

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
Adobe Community Professional ,
Feb 21, 2019 Feb 21, 2019

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.obj);

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.obj);

and you would have this between lines 32 and 33

return tbls;

Likes

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
Adobe Community Professional ,
Feb 22, 2019 Feb 22, 2019

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...

Likes

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
Adobe Community Professional ,
May 28, 2019 May 28, 2019

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

Likes

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
Adobe Community Professional ,
Jun 18, 2019 Jun 18, 2019

Copy link to clipboard

Copied

LATEST

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:

Objectline 78 in script belowline 35 in script below
TablesFV_FindAnyTableFTI_TblAnchor
AFramesFV_FindAnchoredFrameFTI_FrameAnchor
MarkersFV_FindAnyMarkerFTI_MarkerAnchor
Footnotes (not tested)FV_FindFootnoteFTI_FnAnchor
VariableFV_FindAnyVariableFTI_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.

Likes

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