Script to fit text to cell

New Here ,
Feb 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

I am rather new to InDesign scripting.

I have made a script that gets a table and, cell by cell, goes into the text, sees if it overflows and if so decreases the HorizontalScale by 1%, as many times as necessary to fit the text so removing any overset.

It works perfectly ONLY IF there is an alert that stops temporarily the execution.

If I let it go without it, it is not working.

This is my script 

 

 

 

function processTable(table) {
for (i=0; i<table.cells.length; i++)
{
horscale = 100;
while ((table.cells[i].overflows) && (horscale >=50)) {
//alert ("newTextSize: "+horscale); //if I leave this alert it works perfectly, if I take it out it doesn't
table.cells[i].texts[0].horizontalScale = parseFloat(horscale);
horscale = horscale - 1;
}
}
}
 
If I let it go without the alert (like above it is commented) the horscale gets always to 50, showing that it cannot check if text is overflowing in all steps.
Anyone can help? I would just need to "pause" an instant, I guess, or redraw or refresh or anything that lets InDesign re-check if the text is still overflowing during that iteration.
Thanks in advance
TOPICS
Scripting

Views

793

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 2 Correct answers

LEGEND , Feb 06, 2020 Feb 06, 2020
Add a 'recompose' after your scale operation to give InDesign a chance to update -- http://jongware.mit.edu/idcs6js/pc_Text.html#recompose

Likes

Translate

Translate
Adobe Community Professional , Feb 06, 2020 Feb 06, 2020
Table's parent would be a textframe. So for a non nested table the following should give you the page on which the table lies app.selection[0].parent.parentPage If the table is nested one level then the parent of the table would be a cell, parent of the cell would be the outer table and then parent of it will be the textframe. So in this case the following should work app.selection[0].parent.parent.parent.parentPage -Manan 

Likes

Translate

Translate
LEGEND ,
Feb 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

Add a 'recompose' after your scale operation to give InDesign a chance to update -- http://jongware.mit.edu/idcs6js/pc_Text.html#recompose

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 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

Yep, the .recompose() is required.

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
New Here ,
Feb 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

How do you "recompose"?

I tried:

-recompose() (not recognised as a valid function) and 

-table.cells[i].texts[0].recompose; It doesn't complain but nothing changes....

Thanks very much

Nicola

______________________

SORRY MY FAULT: missing parenthesis. It works, thank you very much for your help.

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
New Here ,
Feb 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

In the same scrit I need to know what's the page number where the table is...

I read the parent of a table is a story...but how do you get the page it is placed on? Sorry for this rather silly question but as I said I am rather new to scripting in Id.

Thanks

Nicola

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 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

Table's parent would be a textframe. So for a non nested table the following should give you the page on which the table lies

app.selection[0].parent.parentPage

 

If the table is nested one level then the parent of the table would be a cell, parent of the cell would be the outer table and then parent of it will be the textframe. So in this case the following should work

 

app.selection[0].parent.parent.parent.parentPage

 

-Manan 

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
New Here ,
Feb 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

Many thanks Manan for your support:

I have a table object so

table.parent.parentPage.name gives the result.

Have a good day

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
Explorer ,
Feb 07, 2020 Feb 07, 2020

Copy link to clipboard

Copied

you can refresh your document Accordingly After that statment 

table.cells[i].texts[0].recompose

and

app.documents[0].recompose()

 

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 06, 2020 Feb 06, 2020

Copy link to clipboard

Copied

Hmm, not sure about that behavior. I might try taking the second while argument and moving it inside the loop to force a break: 

 

if (horscale < 50) { break; }

 

Also, try resetting the horscale variable at the start of the for loop by throwing a "var" in front of it. It might be reading horscale from the previous iteration in the for loop.

 

Edit: Or just use recompose() as Jongware suggested. 🙂

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
Explorer ,
Jan 17, 2022 Jan 17, 2022

Copy link to clipboard

Copied

Apologies for (a) jumping in as an amateur and (b) dredging up the past! I seem to be at a similar stumbling point as the original post, and I'm attempting to follow similar steps to success. (Related, a great big thanks to Jongware's summary of tackling tables! It's helped me immensely just getting to this point!)

I think I've got the same code as what was suggested here, but my script seems to disregard the 'overflows' condition of the WHILE loop; all cells get their horizontal scale incrementally decreased regardless of overset text. I'm not sure what I might be doing wrong...! Ideally, this script will only reduce instances of overset text as minimally as required... and later, I'm hoping to add a condition where if the cell contains too much text, it allows multiple lines in that cell only.

Any help/advice would be greatly appreciated!

var table = app.documents[0].pages[0].textFrames[0].tables.everyItem();

var horscale = 100;

for (i=0; i<table.cells.length; i++) {
horscale = 100;
while ((table.cells[i].overflows) && (horscale >=50)) {
table.cells[i].texts[0].horizontalScale = parseFloat(horscale);
horscale = horscale - 5;
app.documents[0].recompose();
}
}

 

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 ,
Jan 17, 2022 Jan 17, 2022

Copy link to clipboard

Copied

Instead of

 

app.documents[0].recompose();

 

use 

 

table.cells[i].recompose();

 

P.

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
Explorer ,
Jan 17, 2022 Jan 17, 2022

Copy link to clipboard

Copied

Thanks for the nudge, Peter... replacing that line still resulted in all cells being affected. It's like the code is completely skipping this condition:

(table.cells[i].overflows)

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 ,
Jan 17, 2022 Jan 17, 2022

Copy link to clipboard

Copied

Remove

.everyItem()

from the first line.  With it, that line creates a one-element array, and you want a single table.

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
Explorer ,
Jan 18, 2022 Jan 18, 2022

Copy link to clipboard

Copied

I think I understand, Peter... everyItem is grabbing overflow data from every cell, and the While loop detects that overflow data, returns true, and applies it to everything it's processing.

I tried changing this to firstItem, and it works as expected in a document with only one table. When I scatter other tables on the page, of course, the code doesn't execute properly. My final document is going to have multiple tables per page.

For now, my simple mind can only think to first look at every TextFrame on the page, get the Index ID of which TextFrame has the specific Label as intended to be processed, and then use that Index ID to specify the TextFrame to target. It's not pretty, but I'll take it if it works! (Which is what my wife thought when marrying me.)

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 ,
Jan 18, 2022 Jan 18, 2022

Copy link to clipboard

Copied

You can iterate through every table in the document with:

var allTables = app.documents[0].stories.everyItem().tables.everyItem().getElements();
for (var t = 0; t < allTables.length; t++) { 
   var table = allTables[t];
   //do the rest
}

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 ,
Jan 18, 2022 Jan 18, 2022

Copy link to clipboard

Copied

Further to Brian's comments, which show you the most efficient way of getting a handle on a text frame's tables, your comment,

everyItem is grabbing overflow data from every cell

is not correct. Let's not go into why now (see https://www.indiscripts.com/post/2010/06/on-everyitem-part-1 and 
https://www.indiscripts.com/post/2010/07/on-everyitem-part-2 for details).

 

With the current (ancient) ExtendScript you can't collect the overset cells in one or more tables with one statement. Just use Brian's code to get each table in a document, then process each table.

 

 

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
Explorer ,
Jan 19, 2022 Jan 19, 2022

Copy link to clipboard

Copied

LATEST

Peter, thank you for those articles! Yes, I definitely had a naive interpretation of everyItem. 

With all your guidance (and Brian), I managed to develop this little script so that it now first fits the contents of every cell within that cell, and then shrinks each row height until the table no longer overflows the textFrame. Success! 

 

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