is now part of CreativePro.com!

Tackling Tables through Scripting

29

With InDesign, you can make tables look pretty awesome, as there are many options to play with. But it’s a lot of work to apply this consistently to all of your tables, even if you use Table Styles. Table Styles also have their limitations, as they cannot apply all formatting. This article outlines how to use Javascript to do just about anything that you want, on just a single table or on every table throughout your document. Yes, this gets into some geeky scripting (don’t fear it! embrace it!), but even if you don’t want to learn how to script, you can download a great script that will help you manage tables, below.

Find which table to process

When you process tables, you need to make a decision: either you want to work on one single table and leave the rest unchanged, or you want something to apply to all tables. A single script can do both! For example, if you have a table selected, it could work on just that table; if none is selected, all are processed. How do you know if a table is selected? Let’s take a look at the Document Object Model when the text cursor is inside a table. Each of the framed objects is the parent object of the one above it.

The hierarchy of objects, from Cursor to Table to Document

There are different modes of selection in a table. You can have a simple text cursor blinking inside a cell; you can select a single cell, or an entire row or column; and you can have the whole table selected. To check where you are you can inspect the type of selection. If you find the user did not select the entire table, you move down the hierarchy until you find the ultimate parent ‘Table’, or  in case the cursor wasn’t ‘inside’ a table after all  something else. A short code fragment:

function checkWhichTable()
{
// ensure the user made a selection
if (app.selection.length != 1)
return null;
var currentTable = app.selection[0];
if (currentTable.hasOwnProperty("baseline"))
{
currentTable = app.selection[0].parent;
}
while (currentTable instanceof Cell || currentTable instanceof Row || currentTable instanceof Column)
currentTable = currentTable.parent;
if (!(currentTable instanceof Table))
{
// No table selected
return null;
}
return currentTable;
}

This code first assumes the text cursor is inside some text, so it would have the property ‘baseline’ (you can check for any property, as long as it’s one that is unique for the ‘Text’ object). If it is, the variable is updated to its parent, which — inside a table — should be a Cell. Now, as long as the variable points to either a Cell, Row, or Column, we keep moving down. At the very end, we should end up at an object of type Table.

This function tells us if you are ‘inside’ a single table or not. If you are, you can process this one; if you are not, you might want to stop and alert the user, or continue and process all tables. First, add the following, above the previous function:

app.doScript(checkUserSelection, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Process Table");

function checkUserSelection ()
{
var a_table = checkWhichTable();
if (a_table == null)
{
if (confirm("No table selected. Do you want to process *all* tables?") == false)
return;
allTables = app.activeDocument.stories.everyItem().tables.everyItem().getElements();
for (aTable=0; aTable<allTables.length; aTable++)
{
processTable (allTables[aTable]);
}
} else
{
processTable (a_table);
}
}

function processTable(table)
{
// do something here!
}

Then all you need to add is add code function processTable, as this is where you do ‘something’. So what can you do? Just about anything you want!

All of the code snippet examples below need to appear inside this function (I’m not repeating the function code for each of the snippets).

Set Table Options

In the function processTable you can change basic table parameters — this is equal to making changes in InDesign’s ‘Table Options’ dialog box. For instance, to set the ‘Space Before’ value, use this:

table.spaceBefore = "2mm";

See https://jongware.mit.edu/idcs6js/pc_Table.html for the entire list of table properties.

Handle Rows and Columns

If you have a variable pointing to a table, you can use simple indexing to access its columns and rows. For example, table.rows[0] indicates the very first row, so to set its fill color to a swatch called ‘Header’, you can do this:

table.rows[0].fillColor = "Header";

Other useful functions: add an empty row at the bottom

table.rows.add(LocationOptions.AT_END);
set the height of all rows

table.rows.everyItem().height = "36pt";

add a line below the first row

table.rows[0].bottomEdgeStrokeColor = "Black";
table.rows[0].bottomEdgeStrokeWeight = 0.75;

Change Individual Cells

Cells contain an enormous amount of formatting: the full list at https://jongware.mit.edu/idcs6js/pc_Cell.html shows there are more than 80 different properties to play with. Actually, the list is longer than that, but remember that you can only change the ones that are marked ‘r/w’ (for ‘read/write’).

Basic properties you might want to change are these:

Basic cell properties

Similar to leftInset, you can also use rightInset, topInset, and bottomInset. In the place of leftEdgeXxx (and the other three directions), you can change any of the properties StrokeColor, StrokeTint, StrokeWeight, StrokeType and some more (see the web page for the full list) — this could be topEdgeStrokeWeight, rightEdgeStrokeColor, etc. Note that the same rules apply as when changing strokes in the interface: changing the left stroke of a cell is the same as changing the right stroke of the cell to its left.
Cells are counted left-to-right, top-to-bottom. To add a diagonal line to the very first cell, use this:

table.cells[0].topLeftDiagonalLine = true;

You can apply the same formatting to all cells like this:

table.cells.everyItem().topInset = "1mm";

If you want to apply more than one change, you don’t have to repeat this line for every single change; you can apply them all at once.

table.cells.everyItem().properties = {
topInset:"1mm", bottomInset:"1.5mm",
leftEdgeStrokeColor:"Black"
};

You can still use and apply Cell Styles, of course. For instance:

table.cells.everyItem().appliedCellStyle = "MyCellStyle";

or event apply them selectively, such as on all even rows:

for (i=0; i<table.rows.length; i+=2)
{
table.rows[i].cells.everyItem().appliedCellStyle = "MyCellStyle";
}

Text Inside a Cell

Sometimes you need to act on the text inside a cell. For example, perhaps you want to set the background fill to red if it contains a negative number. You can access text using the cell’s .texts property:

for (i=0; i<table.cells.length; i++)
{
if (table.cells[i].texts[0].contents[0] == "-")
table.cells[i].fillColor = "Red";
}

However, note that the .texts property is an array (for unknown reasons)! It always has one single element, whether or not there is actually some text in the cell. If you need to process empty cells only (or the reverse, only cells that contain text), you can test its length:

for (i=0; i<table.cells.length; i++)
{
if (table.cells[i].texts[0].length == 0)
table.cells[i].fillColor = 'Red';
}

Resizing a Table

Now you know a script can access the text inside a table, and you know it can read and change the width of each column. Therefore, it is possible to check the width of the text inside each column and adjust the column widths so any remaining space is divided evenly across the columns — instant auto-layout! However, it’s a large script, so I’m not going to type it here. Instead, here is a download link: AutoformatTables.jsx (it’s a ZIP file, so you might need to unpack it manually after downloading).

The script makes all non-empty columns as narrow as possible without any line breaks. It then checks if this makes the table fit inside the original margins, and if so it divides the remaining space and is done. If not, it makes all columns as narrow as possible without having any overset text. If that’s not possible either, then there is nothing the script can do and it gives up.

Totally empty columns are kept unchanged; that way, you can manually add spacer columns where necessary.

Because the contents of each cell needs to be checked several times, the script may take a while to work on larger tables. It works best with ‘simple’ tables; it cannot work with rotated tables, lots of rotated single cells, or complicated split-and-merged combinations.

That’s it! You can freely combine the code snippets above, and write either a fully automated table formatting script, or just a small script to adjust one tiny aspect of all of your tables. Have fun!

Please remember that it’s not very useful to ask in the ‘Comments’ section below how to do a specific task which I didn’t discuss. Any questions that require more than a single line of code are better put in the Scripting Forum.

Dutchman Theunis de Jong is better known under his nickname "Jongware" and has been bothering people since 1966. Started as pressman's little helper in 1984, fresh from school. Really wanted to work in the graphics industry, so he had no problems starting at the very bottom :-) His computer talents were soon discovered, first by himself (being a math & science buff), then by his boss who quickly promoted him to the typesetter division. Worked with WordPerfect, PageMaker, and now InDesign -- but never with Quark. Well, hardly ever. Tends to dive in deep into technical stuff: PostScript, XML, XSLT, general programming in C++ (for DOS, Windows, and Mac OS X). Wrote programs in pure assembler for Z80, ARM4, 80x86, and 68000 processors. As it appeared, this seems the perfect background for right-brain activities such as Scripting and GREP, two InDesign features he fanatically uses (and occasionally abuses). Or was it left-brain? I always forget. I mean, he always forgets.
  • Marc says:

    Hey Theunis,

    Hmmm… Now I understand why you were so busy these days ;-)

    Nice post, by the way.

    @+
    Marc

  • Camilo says:

    It is a fantastic post. First time users may manage tables as a whole!. Thanks, Jong.

    I have a couple of questions.

    1) Tables are very easy to process when they are created directly in ID. For example, «Headers Rows» (previously defined with «Table Styles») get perfectly formatted. The problem is when the file has a lot of imported tables. To style them, the first step is select the documents to apply the desired style, previously defined in «Table Styles». In this moment all the rows, including the header, get changed ? to the alternate color, for example?. To solve this mess the function provided here is perfect:

    table.rows[0].fillColor = “Header”;

    although something to care is defining colors at 100% (default is 20% in «alternating patterns» menu); otherwise, the script will magically change the header to the new required color but applying the original percentage prescribed the «alternating pattern», the referred 20%.

    The script for change Headers Rows has to be run after the chosen «Table Style» tag was applied to the whole document? Otherwise, based percentages will affect the new color…

    2. It is possible with this script to apply a paragraph style automatically to all the headers? In a document with imported tables this has to be made manually…

    3. How to script the idea of having in the Header Row, only in specific columns (3, 5, for example) different colors?

    Thank you

  • Jongware says:

    Those are good questions! Answered in the Scripting forum.

  • Hollys says:

    I work in tables all the time and would love to be able to globally change the row height, auto space the columns, and other parameters but I did not understand this article at all. Maybe scripting is not for me. Is there by chance a video explaining all this?

    My publication can have up to 100 or more tables with class information. It would really be nice to be able to do some of the work using scripts.

  • Chuck says:

    Theeeeeeee-unis! Nice work, my man!

    (accounts for why you haven’t been posting lately, heh heh)

  • c. umana says:

    Holly: just download the autoformattables.jsx included above in the post, learn how tom install a script that will surely do a lot for you.

    Why scripting is not for you, if scripting will save your time and will allow more dedication to the copy?

    It is not very, very strange, telling here mr Jongware that this wonderful piece of information is useless for some people. That cannot be true. Is useful for ALL the world.

  • @Hollys: Scripting is not for everyone, but everyone can do it if they want to. Take a look at this earlier article, too: https://creativepro.com/javascript-for-the-absolute-beginner.php

  • c. umana says:

    I do not think Hollys need to learn to script.
    He (like me and many) need to use the wonderful scripts already written that are found here and everywhere. Anne Marie has here a blog on how to install and use.

  • mhn says:

    Hello,

    Found this article very informative and useful.

    I am working on a project where I have a indd file containing tables which are mostly inconsistent in formatting.

    The workflow I have developed so far goes something like this:

    [Manual work]
    I select the source table, convert it to text, select the resulting text, followed by Find/Replace to remove extra returns and white space, then I copy the selected text to clipboard.
    Then I switch to another indd file where I paste the text, select the text again, convert it to table with proper table style. Select the resulting table. (The purpose of converting the table to text is to remove all the inconsistent formatting from the table)

    [Script]
    With the help of good folks at InDesign Scripting forum, I have developed a small script that sets the column width and row height of the table and applies a paragraph style to text of first cell of the table.

    [Manual work]
    Then I place my cursor after the table and manually enter the row count of the table and apply a specific paragraph style to the count.

    Is there any chance that I can automate the [Manual work] part.

    Thanks and regards.

  • Mohamed says:

    First of all thank you for this useful and helpful script, but i have a question, why this script can not working with simple cases in rotated tables ?

    Thank you

    • Jongware says:

      Mohamed: I assume you are referring to “AutoformatTables”? Alas, there is no such thing as a “simple case” in a rotated table. “Width” and “height” work in reverse, and my way of measuring the text length — by looking at the *horizontal* positions of the start and end of a text line — does not work anymore. In a rotated cell (or a rotated table in its entirety), InDesign reports the *actual* x coordinates, unaware that it’s rotated. I still have to find a good solution for that; but, it must be added, rotated cells or tables are fairly rare in my usual workflow.

      • Mohamed says:

        Aha it’s understandable answer thank you, but i have another question, I already read this script twice and i need to know how can you calculate the number of line breaks to make it as least as possible and also this calculation of line breaks depend on which width? the original width of column?? Please let me know it’s important for me.

        Thank You and Best Regards

  • Mohamed says:

    Hi Jongware,

    After lots and lots of trying to fit rotated tables with measuring text width, i think that using baseline and endBasline is the key of this puzzle.
    Instead of using horizontalOffset we can use baseline to measure width of the text in rotated tables

  • Rinus Eigenraam says:

    Dear Jongware,

    First of all you made me very interested in scripting, you are awsome.

    I am using your script to change cell colours with calls with a specific value.

    What i actually wants is to change the row colour though row is not a good value and was wondering how i could fix this.

    Rinus

  • Eitan says:

    Great post! I’m using Indesign CC 2014 and tried running the script but I got an error on line 6:

    app.doScript (autoformattable, ScriptLanguage.JAVASCRIPT,[true],UndoModes.ENTIRE_SCRIPT, “Autoformat Table”);

    After reading your other post on adding Undo to your scripts, I changed it to:

    app.doScript (autoformattable, ScriptLanguage.JAVASCRIPT,undefined,UndoModes.ENTIRE_SCRIPT, “Autoformat Table”);

    and now it works great. Thanks for sharing this awesome script – it has saved me tons of time.

  • Ernie Samat says:

    Dear Jongware,
    Is there a script where you can alternate the back colours in a table full of rows. For example for every 10 rows the script will change the background colour to your desired colour?

    With thanks
    Ernie

  • Ernie Samat says:

    Hi again, sorry let me make myself clear regarding the script for alternate background colour.
    There are over 1000 rows in the table in Indesign. The table represents groups of Funds. To make the Funds more readable, every other group is defined with an alternate colour. At the moment I need to highlight every other group and change the background colour.
    Is there a script where it automatically does this?

    At the moment it takes nearly 45mins and there are always errors where I’ve missed a row or two I haven’t highlighted. A script would take seconds and guaranteed no errors.

    Thanks again
    Ernie

  • Rima says:

    Thank you very much! Very helpful article! Even though I have no previous experience with scripting in InDesign, I was able to manipulate my tables very effectively.

  • Brian says:

    I work with designing the occasional invoice or business form with pre-determined column widths and row heights. I would like to find a script (or any way) in indesign that would format these tables easier. Right now, I know its blasphemous to say, but Quark (with FormsX extension) does a much better job with this. I don’t know if I’m explaining myself well – Let’s say you have one row with colums that are 12 tenths, 6 tenths,10 tenths, 4 tenths, and 5 tenths. There would be an input field where we input these measurements and it would output a table with these measurements.

  • Gaurav Gupta says:

    Dear Jongware,

    I need your help. we have an requirement if table is splitting in two column on one page in that case we need to apply some other style on Last Column and first column(table is split into next column. We have tried lot but unable to identify the last row.

    Please help me.

    Thanks,
    Gaurav Gupta

  • Sumit Kumar says:

    Hi Jongware,

    Could you help me?

    How to become master in javascript like you?

    Regards,
    Sumit

  • Andrew Ballantine says:

    Hi Theunis, thanks for the informative feature – I’m getting into scripting to help process the very large documents I’m often tasked with producing, and this helped… I’m currently working on a document with several tables of thousands of rows each, and I’m hoping you can shed some light on creating a script that does the following: finds any row where the second column is empty, selects all the cells in the row, merges them and applies a cell style. Hope you can help…

  • Kiran says:

    I am looking for a script which adjust the table column.Table is inside the multi column text frame.
    i.e how to adjust table width in multi column textframe.

  • Shiv says:

    Auto format table jsx download link is broken? could anyone share it pls?

  • >