Javacript: How to duplicate a table header row (in InDesign Server version)?

Community Beginner ,
May 06, 2022 May 06, 2022

Copy link to clipboard

Copied

I created this code for duplicating a header row into body row, but unfortunately, this code doesn't go well with the InDesign server version, since the .select() method is not available (but works okay in desktop version) 

// create a simple table with one header row, put the cursor on the FIRST cell and run this code
table = app.selection[0].parent;
table.rows[0].select();
app.copy();
var newRow = table.rows.add(LocationOptions.AFTER, table.rows[0], {rowType:RowTypes.BODY_ROW});
newRow.select();
app.paste();


Is there any way to copy a HEADER_ROW, create a new BODY_ROW and paste the copied HEADER_ROW into the selected BODY_ROW? Later, I would do some changes to the body_row.

 

Any idea which will work in the Server version? Please let me know your thoughts?

TOPICS
Scripting

Views

197

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 06, 2022 May 06, 2022

Copy link to clipboard

Copied

Hi @Shiv Allva,

You will have to think which table you want to select. In your current code you are working with selection to identify the table of interest but on the server you will have to think of another logic to identify the table.

If it's just a single table in the document then you can use something like the following

 

var table = app.documents[0].tables[0]

 

Alternatively, you can iterate all the tables in the document using the above collection and find the table that is of interest to you. The criteria to choose the table will have to be thought by you based on your workflow.

-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
Community Beginner ,
May 06, 2022 May 06, 2022

Copy link to clipboard

Copied

@Manan Joshi That was just a sample codesnippet. But the query is how to duplicate the first header_row as body_row? Problem here is Server version doesn't have .select(). So want to know if there is an alternative way to achieve this solution in server?

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 06, 2022 May 06, 2022

Copy link to clipboard

Copied

Hi @Shiv Allva , why not just make the new row and set its contents to the header’s contents, or do you need to style it the same way?

 

//a document with one table
var table = app.documents[0].textFrames[0].parentStory.tables[0];
var newRow = table.rows.add(LocationOptions.AFTER, table.rows[0]);
newRow.properties = {rowType:RowTypes.BODY_ROW, contents:table.rows[0].contents}

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 07, 2022 May 07, 2022

Copy link to clipboard

Copied

Hi @Shiv Allva, the problem here is that Table Rows (and Columns) don't have a duplicate method. You are using select/copy/paste to solve this problem, which doesn't work on the server version as you mention.

 

Have a look at this function I've written called duplicateRowOrColumn. It is my attempt at creating the equivalent functionality to the missing method, and I hope it will work in your case. See my example 1 in my code. (Example 2 is commented out but shows a different usage.) Script isn't well tested at all, so let me know if you have problems with it.

- Mark

example-duplicate-row-column.gif

(Screenshot above shows little sample table with example 1 AND example 2 both run at once.)

 

 

 

 

/*
    Move Or Duplicate Row Or Column
    for Adobe Indesign 2022

    Utility function to move or duplicate a table row or column

    by m1b
    here: https://community.adobe.com/t5/indesign-discussions/javacript-how-to-duplicate-a-table-header-row-in-indesign-server-version/m-p/12926231
    and here: https://community.adobe.com/t5/indesign-discussions/swapping-columns-in-indesign-with-a-java-script/m-p/13014567

    v2022-06-19
    • added move function
    • added idea by @rob day to simplify the setting of cell properties.
*/


function main() {

    var doc = app.documents[0],
        table = doc.textFrames[0].parentStory.tables[0];


    /*
        example 1:
        duplicate first row after itself
    */
    var newRow = duplicateRowOrColumn(table.rows[0], LocationOptions.AFTER);
    // then convert to body row
    if (newRow != undefined && newRow.isValid)
        newRow.rowType = RowTypes.BODY_ROW;


    /*
        example 2:
        swap first and second columns
    */
    var movedColumn = moveRowOrColumn(table.columns[1], LocationOptions.BEFORE, table.columns[0]);



    /**
     * Duplicate a table Row or Column
     * @dependency moveRowOrColumn function
     * @param {Row|Column} rowOrColumn - the row or column to duplicate
     * @param {LocationOptions} [locationOption] - LocationOptions.AFTER or LocationOptions.BEFORE
     * @param {Row|Column} [referenceRowOrColumn] - after or before this row or column
     * @returns {Row|Column} - the duplicate row or column
     */
    function duplicateRowOrColumn(rowOrColumn, locationOption, referenceRowOrColumn) {
        return moveRowOrColumn(rowOrColumn, locationOption, referenceRowOrColumn, true);
    }

    /**
     * Move a table Row or Column
     * Note: because there is no way to natively
     * move a row or column, the function creates
     * a new, matching, column in the new position
     * and removes the old one. Therefore, anyone
     * using the function must replace their existing
     * reference with the returned row or column.
     * eg. var myColumn = moveRowOrColumn(myColumn);
     * @param {Row|Column} rowOrColumn - the row or column to duplicate
     * @param {LocationOptions} [locationOption] - LocationOptions.AFTER or LocationOptions.BEFORE
     * @param {Row|Column} [referenceRowOrColumn] - after or before this row or column
     * @param {Boolean} [duplicate] - if true, duplicate rowOrColumn
     * @returns {Row|Column} - the moved row or column
     */
    function moveRowOrColumn(rowOrColumn, locationOption, referenceRowOrColumn, duplicate) {
        // defaults:
        locationOption = locationOption || LocationOptions.AFTER;
        referenceRowOrColumn = referenceRowOrColumn || rowOrColumn;
        duplicate = (duplicate === true);

        if (!rowOrColumn.isValid) {
            alert('Duplicate Row or Column: rowOrColumn is invalid.');
            return;
        }

        var type = rowOrColumn.constructor.name,
            cells = rowOrColumn.cells.everyItem().getElements(),

            // make the new row or column
            newRowOrColumn = (
                type == 'Row'
                    ? table.rows
                    : table.columns
            ).add(locationOption, referenceRowOrColumn),

            newCells = newRowOrColumn.cells.everyItem().getElements();

        // loop over each cell
        for (var i = 0; i < newCells.length; i++) {

            // copy properties to new cell
            newCells[i].properties = cells[i].properties;

            // except contents, we need to do that manually
            newCells[i].contents = '';
            if (cells[i].cellType == CellTypeEnum.TEXT_TYPE_CELL) {
                // duplicate text
                cells[i].texts[0].duplicate(LocationOptions.AFTER, newCells[i].texts[0]);
            }

            else if (cells[i].cellType == CellTypeEnum.GRAPHIC_TYPE_CELL) {
                // duplicate graphic cell
                newCells[i].convertCellType(CellTypeEnum.GRAPHIC_TYPE_CELL);
                var rect = cells[i].allPageItems[0],
                    newRect = newCells[i].allPageItems[0];
                // duplicate content
                newRect.contentPlace(rect);

                // position content
                if (rect.pageItems[0].isValid) {
                    var delta = getRelativePosition(rect.pageItems[0], rect),
                        newDelta = getRelativePosition(newRect.pageItems[0], newRect),
                        deltaMove = getRelativePosition([delta[1], delta[0]], [newDelta[1], newDelta[0]]);
                    newRect.pageItems[0].move(undefined, deltaMove);
                }
            }
        }

        // remove old rowOrColumn
        if (duplicate !== true)
            rowOrColumn.remove();

        return newRowOrColumn;

        /**
         * Calculates relative position between two items or bounds
         * @param {PageItem|Array} item1 - can be PageItem or bounds [T,L,B,R]
         * @param {PageItem|Array} item2 - can be PageItem or bounds [T,L,B,R]
         * @returns {Array} - [x,y]
         */
        function getRelativePosition(item1, item2) {
            var b1 = item1.hasOwnProperty('geometricBounds')
                ? item1.geometricBounds
                : item1;
            var b2 = item2.hasOwnProperty('geometricBounds')
                ? item2.geometricBounds
                : item2;
            if (
                b1.constructor.name == 'Array'
                && b2.constructor.name == 'Array'
            )
                return [b2[1] - b1[1], b2[0] - b1[0]];
        }

    } // end duplicateRowOrColumn

}

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Move Or Duplicate Row Or Column");

 

 

 

Edit: Updated script to handle moving as well as duplicating, after answering this question, and added @rob day's way of applying cell properties.

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 29, 2022 May 29, 2022

Copy link to clipboard

Copied

Hi @Shiv Allva, did you solve this problem? - Mark

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
Community Beginner ,
Jun 20, 2022 Jun 20, 2022

Copy link to clipboard

Copied

while running your script, there was an error: Cannot set row type

 

Observation: I can see the firstrow is duplicated in the indd, but the script can't change the newRow to Body_Row.
     // newRow.rowType = RowTypes.BODY_ROW;

After the error, the new row doesn't anymore show in the InDesign.

 

Checking check this image for more details:

forum_feedback.png

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 20, 2022 Jun 20, 2022

Copy link to clipboard

Copied

Hi @Shiv Allva, oh I'll have to look into that problem. Can you share an indesign file with a table that currently doesn't work with script? It would make it easier for me to understand the problem. My first thought is perhaps that your table had two header rows and we duplicated the first—and in that case it would be illegal to change rowType to body row because you can't have header-body-header-body-body-body etc.

- Mark

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
Community Beginner ,
Jun 21, 2022 Jun 21, 2022

Copy link to clipboard

Copied

Yes, there are two header rows! If this info doesn't help, then I can try to provide you with a sample.

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
Community Beginner ,
Jun 21, 2022 Jun 21, 2022

Copy link to clipboard

Copied

Here is the sample indd. I even tried with one header row, but it throws an error on the property copying logic.

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 21, 2022 Jun 21, 2022

Copy link to clipboard

Copied

LATEST

Thanks @Shiv Allva I've tested script on your test file and I get the error too. I'll get to the bottom of it as soon as I get time.

- Mark

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 20, 2022 Jun 20, 2022

Copy link to clipboard

Copied

Hi Mark,

just tested your new version of the code v2022-06-19 with one of my test tables.

It contents a special "condition" so to say. A graphic cell where I rotated the container frame for an image.

 

I get inconsistent results with two variations.

[1] Frame has no image

[2] Frame has an image

Both results are wrong. And different.

I could tell from some experiments with cell.select() and copy/paste that even that will not get you very far.

In fact, InDesign was crashing as I tried to paste one of the two columns. It was the "easier" one with two text cells and no contents at all to a column that contained a graphic cell.

 

Details below.

On the left the original table, on the right the result after running code v2022-06-19 with:

 

// Text frame with table selected:

var doc = app.documents[0];
var table = app.selection[0].parentStory.tables[0];

var movedColumn = 
moveRowOrColumn
(
	table.columns[1] , 
	LocationOptions.BEFORE , 
	table.columns[0]
);

 

Top table.

Container frame in graphic cell rotated to 15°.

Container frame selected.

m1b-v2022-06-19-Source-1-GraphicCell-Rect-SELECTED.PNG

 

Result top table. Container frame selected.

Note, that the red rectangle is now inside of that container frame!

m1b-v2022-06-19-Result-1-GraphicCell-Rect-SELECTED.PNG

 

Result top table. Contents of container frame selected:

m1b-v2022-06-19-Result-1-GraphicCell-Rect-Contents-SELECTED.PNG

 

 

Now on to the tables at the bottom where I filled the rotated container frame of the graphic with an image.

 

Bottom table.

Selected: Container frame in graphic cell rotated to 15°

m1b-v2022-06-19-Source-2-GraphicCell-Rect-SELECTED.PNG

 

Bottom table. Selected: Contents of the container frame in graphic cell:

m1b-v2022-06-19-Source-2-GraphicCell-Rect-Contents-SELECTED.PNG

 

Result of bottom table. Selected: Container frame in graphic cell

m1b-v2022-06-19-Result-2-GraphicCell-Rect-SELECTED.PNG

 

Result of bottom table. Selected: Contents of container frame in graphic cell

m1b-v2022-06-19-Result-2-GraphicCell-Rect-Contents-SELECTED.PNG

 

 

Well, food for thoughts…

 

Regards,
Uwe Laubender

( ACP )

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 20, 2022 Jun 20, 2022

Copy link to clipboard

Copied

Copy/paste selected columns with the GUI. Left the source, right the result:

GUI-CopyPasteColumns-Source-vs-Result.PNG

This time this also was working for my second table without crashing InDesign 2022 version 17.3.0 on Windows 10. Maybe I did something differently? Perhaps I was changing my selection more slow or I had the order differently.

Phase 1, copy column 2 to columns 1:

GUI-Table-2-CopyPasteColumns-Source-vs-Result-1.PNG

Phase 2, copy column 1 to column 2:

GUI-Table-2-CopyPasteColumns-Source-vs-Result-2.PNG

 

Regards,
Uwe Laubender
( Adobe Community Professional )

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 20, 2022 Jun 20, 2022

Copy link to clipboard

Copied

Here the sample InDesign document from my Dropbox account:

https://www.dropbox.com/s/doyakxa5p8l46hj/DupTableColumnsOrRows-SAMPLES-2022.indd?dl=1

 

Regards,
Uwe Laubender
( Adobe Community Professional )

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 20, 2022 Jun 20, 2022

Copy link to clipboard

Copied

Hey thanks for all that testing @Laubender! That has given me impetus for improving the script. At the time I wrote it, I recall deciding that if user has complex stuff going on in a cell (ie. more than just a graphic frame with a single graphic) then I won't bother handling that case. But it would be cool if it worked. I'll look into it when I get a chance. I have downloaded your sample file.

- Mark

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