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?
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
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?
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}
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
(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.
Copy link to clipboard
Copied
Hi @Shiv Allva, did you solve this problem? - Mark
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:
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
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.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
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
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.
Result top table. Container frame selected.
Note, that the red rectangle is now inside of that container frame!
Result top table. Contents of container frame selected:
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°
Bottom table. Selected: Contents of the container frame in graphic cell:
Result of bottom table. Selected: Container frame in graphic cell
Result of bottom table. Selected: Contents of container frame in graphic cell
Well, food for thoughts…
Regards,
Uwe Laubender
( ACP )
Copy link to clipboard
Copied
Copy/paste selected columns with the GUI. Left the source, right the result:
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:
Phase 2, copy column 1 to column 2:
Regards,
Uwe Laubender
( Adobe Community Professional )
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 )
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