Skip to main content
Known Participant
September 12, 2019
Answered

Run ExtendScript down a column on a table

  • September 12, 2019
  • 3 replies
  • 3307 views

I am putting together a script to align numbers in a table by decimal/assumed decimals. (I think all of the parts I’ve found here on the forum – what a great resource!)

FrameMaker aligns like this:

We'd like it to align like this:

My script adds “.0” and changes the character style to white. (I got help with that part last week but the post got lost in the Adobe forum conversion.) That part works, but I can’t get it to do more than one cell. We can't run it on all tables in the document, or even a whole table. It will need to be by column. Right now, I'm thinking to put the cursor in the top cell of the column, then run the script. Here’s what I have.

#target framemaker  

var doc, pgf, cell, regex; 

//given the cell containing the insertion point
doc = app.ActiveDoc;  
pgf = doc.TextSelection.beg.obj;  
cell = pgf.InTextObj;  
regex = /\./; // this finds a decimal
    
// ...navigate down the column.  
while (cell.ObjectValid () === 1) {  //I think this is where it breaks down
  processDec (pgf, doc, regex);  
  cell = cell.CellBelowInCol;  
}  
// From here down it works great, on one cell. 
function processDec (pgf, doc, regex) {  //by FrameExpert  
    var end = Constants.FV_OBJ_END_OFFSET - 1, begin = 0, textRange;  
    var textList = pgf.GetText (Constants.FTI_CharPropsChange);  
   
    for (var i = textList.length - 1; i >= 0; i -= 1) {  
        begin = textList[i].offset;  
        if (begin !== end) {  
            textRange = new TextRange (new TextLoc (pgf, begin), new TextLoc (pgf, end));  
                if (regex.test (getText (textRange, doc)) === false) {  // if there is a decimal, nothing happens
                    
                    addDecimal ();
                } 
            end = begin;  
        }  
    }  
    if (end > 0) {  
        textRange = new TextRange (new TextLoc (pgf,0), new TextLoc (pgf,end));  

            if (regex.test (getText (textRange, doc)) === false) {  // if there is a decimal, nothing happens
                addDecimal ();
            }  
    }  
}  
  
function getText (textObj, doc) {  //by FrameExpert
  
    var text = "", textItems, i;  
       
    if (textObj.constructor.name !== "TextRange") {  
        textItems = textObj.GetText(Constants.FTI_String);  
    } else {  
         textItems = doc.GetTextForRange(textObj, Constants.FTI_String);  
    }    
    for (i = 0; i < textItems.len; i += 1) {  
        text += (textItems[i].sdata);  
    }  
    return text; 
}  
  
function addDecimal () {

var textRange = new TextRange;
    textRange.beg.obj = textRange.end.obj = pgf;
    textRange.beg.offset = 0;
    textRange.end.offset = Constants.FV_OBJ_END_OFFSET - 1;  

    doc.TextSelection = textRange;
    textRange = doc.TextSelection;
    
    doc.AddText(textRange.end, ".0");
    
    addWhite (); //calls function to apply the White character format to the .0
  }
   
function addWhite () { 
 
var textRange = new TextRange;
    textRange.beg.obj = textRange.end.obj = pgf;
    textRange.beg.offset = Constants.FV_OBJ_END_OFFSET - 3;     
    textRange.end.offset = Constants.FV_OBJ_END_OFFSET - 1;  
    applyCharFmt (textRange, "White", doc);  
}

function applyCharFmt (textRange, name, doc) {  
    var charFmt = 0;  
    charFmt = doc.GetNamedCharFmt (name);  
    if (charFmt.ObjectValid()) {  
        doc.SetTextProps (textRange, charFmt.GetProps());  
    }  
}  

 

If it's possible, I'd like it if we could run it on multiple selected columns. Can anyone help me fix this?

Thank you.

This topic has been closed for replies.
Correct answer Russ Ward

It works!

 

var pgf = cell.FirstPgf;
var text = getText(pgf, doc);
if(text.indexOf(".") === -1)
{
addDecimal ();
}

 

Thank you for your help, Russ!

 

Julie


Great. For your question about notifications, yes, I get notifications for everything, even things I do. And then when I click on links, it takes a while to find whatever is new because so much is hidden behind expansion links. At the risk of sounding like someone who just gets mad when something changes, I have to say that usability was one of the last things considered with this rollout. Or, if it was, somebody should look for a different job. Regarding your coding success, great news. I thought it could be much simpler. BTW, the check for -1 might be reliable, but for sure a check for <0 would be the most reliable. Keep coding! It makes FrameMaker fun and makes it a more valuable tool for you.

3 replies

Legend
September 17, 2019

Hi Julie, I think I can help. But I need you to help me first... Can you explain the basic logic of the processDec() function? It basically looks like a simple end goal... check if there is a decimal in the cell. If there is one, do nothing. If there is none, add ".0" to the end of the text.

 

If that is the goal, I can't follow your various loops. I don't know why you are retrieving FTI_CharPropsChange text items and I don't follow the second conditional - if(end > 0)...

 

If all you care about is checking for a decimal; that is, a period, it seems that it could be much simpler. I would do something like this (untested):

 

var pgf = cell.FirstPgf;
var text = getText(pgf, doc);
if(text.indexOf(".") > -1)
{
  //Do the decimal add...
}

 

You might even want to test an index >0 instead of -1, just to be sure there actually is a digit before the decimal. But that probably doesn't really matter.

 

So let me know if there is more to the story. The complexity of your code suggests that there is something else going on and I don't have the time to decipher it all 🙂  And apparently the history of this thread is not available now.

 

Russ

Legend
September 17, 2019
Sorry, I have the conditional backwards, should be if(text.indexOf(".") < 0)
Legend
September 20, 2019

Where do you do that now? I don't see that option anywhere.


Ha, well, excellent question. I haven't started any posts myself so I don't know. You probably need a PhD in UI Design and Analysis to figure it out. And then only after somebody shows you.
Legend
September 17, 2019

Hi,

 

You have gone a long time without a reply. Maybe you figured it out already. I think the lack of response is related to the big changes with these forums. I'm sorry that you did not get any help yet.

 

I think your problem is very simple and exactly where you identified it. The problem is that you are iterating through multiple cells, but never resetting the paragraph for processing to the new cells. I think you just need to add one line as shown below:

 

// ...navigate down the column.
while (cell.ObjectValid () === 1) { //I think this is where it breaks down
  var pgf = cell.FirstPgf;
  processDec (pgf, doc, regex);
  cell = cell.CellBelowInCol;
}

 

For multiple selected columns, you need to first be able to find out which cells are selected. Here is an uncommented function I use for that. You will need to interpolate the results into the desired columns. For example, for each selected cell returned, you would need to iterate up to find the top of the column, then run your column modifier routine. And you would want to remember the columns you processed (by remembering the top cell) so you don't process columns multiple times. I hope this helps.

 

Russ

 

 

 

 

function tbl_GetSelectedCells(oDoc, oTable)
{
    var cells = new Array();
    
    if(!oDoc.ObjectValid())
        return cells;
    
    if(!oTable.ObjectValid()) 
        oTable = doc.SelectedTbl;
    
    if(!oTable.ObjectValid())
        return cells;

    var oRow = oTable.TopRowSelection;
    var bottomRowSelected = oTable.BottomRowSelection;

    var leftColSelected = oTable.LeftColNum;
    var rightColSelected = oTable.RightColNum;

    while(oRow.ObjectValid())
    {
        var i = 0;
        oCell = oRow.FirstCellInRow;

        while(oCell.ObjectValid())
        {
            if(i >= leftColSelected && i <= rightColSelected)
                cells.push(oCell);

            i++;

            oCell = oCell.NextCellInRow;
        }

        if(oRow.id == bottomRowSelected.id) 
            oRow = oDoc.GetNamedColor ("InvalidateThisObject");
        else oRow = oRow.NextRowInTbl;
    }

    return cells;
}
jmyers2Author
Known Participant
September 17, 2019

Hi Russ,
Thank you for your reply. No, I hadn't received an answer yet. I figured the new format was why. 

I used the line you added in my initial code and it does move down the column now. But something is still wrong. I put the cursor in the first cell of each column and ran it. It does this:

(I used "bold" instead of "white" so I could see what it was doing.) The code says to use the addDecimal function if there is no decimal, but on some of the cells it is ignoring that. Is there something wrong with my textRange?

Thanks,
Julie

LinSims
Community Expert
Community Expert
September 13, 2019

I would suggest contacting someone like Rick Quatro. His TableCleanerES script already does formatting changes for columns on a mass basis, and I expect the parts of it that move from cell to cell or apply column formats could be adapted to what you want to do. Be aware that his scripting is part of how he makes a living, so he may charge for this. I can vouch that his scripts are excellent aids and that his charges are quite reasonable.