Here my maybe not very elegant workaround. The problem was that body.getChild(index)
lost nested images inside a table cell.
This also happened when I inserted or appended a table as a whole, no matter if the source was a body child or from body.getTables()
. The images got corrupted.
I now run manually through the table cell by cell in the aftermath and replace each corrupted inline imgage (placeholders with exclamation mark) with the belonging image from body.getTables()
. Now they are displayed correctly. Very strange.
Be careful: If a table is nested inside a table, it will be an additional entry in the array body.getTables()
but NOT be part of the body children body.getChild(index)
(--> only top level tables). I had to link the two in a way that the indices don't get mixed up.
Here my code:
function mergeDocs() {
var dstBody = DocumentApp.openById("1XmWwK2ni2JyX4Ii1ow19AehLqPkdYGOsj5XFSrlkaw4").getBody(); //Doc to append content to
var srcBody = DocumentApp.openById("1ygNn1kgiFchuSf1mBs6RiS4GiBx3KPcKK07E_WWlsBE").getBody(); //Source Doc to be copied
var totalElements = srcBody.getNumChildren();
for (var j = 0; j < totalElements; ++j) {
var dstChild = srcBody.getChild(j).copy();
var type = dstChild.getType();
if (type == DocumentApp.ElementType.PARAGRAPH) dstBody.appendParagraph(dstChild);
else if (type == DocumentApp.ElementType.TABLE){
var allSrcTables = srcBody.getTables();
var tableIndex;
var tables = allSrcTables.forEach(function(table){
// !! getChildIndex(table) will crash if a table is nested inside is a table --> nested tables are part of body.getTables() but NOT part of the body children (body.getChild(j)): No belonging body child index can be found for a subtable!!
//only execude the method getChildIndex() if a table is not nested inside another table
if(table.getParent().getType() !== DocumentApp.ElementType.TABLE_CELL){
var childIndex = srcBody.getChildIndex(table);
if (childIndex == j){
tableIndex = allSrcTables.indexOf(table);
}
}
});
var srcTable = allSrcTables[tableIndex];
var newTable = dstBody.insertTable( dstBody.getNumChildren()-1, srcTable.copy());
//replace all corrupted inline images with working ones from srcBody.getTables();
replaceCorruptedImages(srcTable, newTable);
}
else if (type == DocumentApp.ElementType.LIST_ITEM) dstBody.appendListItem(dstChild);
else throw new Error('Unknown element type: ' + type);
}
}
function replaceCorruptedImages(srcTable, dstTable) {
var numRows = dstTable.getNumRows();
var dstRow, numCells, dstCell, actCellIndex;
for (var actRowIndex = 0; actRowIndex < numRows; actRowIndex++) {
dstRow = dstTable.getRow(actRowIndex);
numCells = dstRow.getNumCells();
for (actCellIndex = 0; actCellIndex < numCells; actCellIndex++) {
dstCell = dstRow.getCell(actCellIndex);
//dstCell.clear();
var srcCell = srcTable.getCell(actRowIndex, actCellIndex);
var numCellChildren = srcCell.getNumChildren();
for (var y = 0; y < numCellChildren; y++) {
var cellChild = srcCell.getChild(y);
var childCopy = cellChild.copy();
switch(childCopy.getType()) {
case DocumentApp.ElementType.INLINE_IMAGE:
dstCell.getChild(y).removeFromParent();
dstCell.appendInlineImage(childCopy);
//images may be nested inside a paragraph
case DocumentApp.ElementType.PARAGRAPH:
var numParaChildren = childCopy.getNumChildren();
for (var z = 0; z < numParaChildren; z++){
var paraChild = childCopy.getChild(z);
var paraChildCopy = paraChild.copy();
if (paraChildCopy.getType() == DocumentApp.ElementType.INLINE_IMAGE){
dstCell.getChild(y).getChild(z).removeFromParent();
dstCell.getChild(y).appendInlineImage(paraChildCopy);
}
}
break;
// recursive function in case a table is nested inside a table
case DocumentApp.ElementType.TABLE:
replaceCorruptedImages(cellChild, dstCell.getChild(y));
break;
}
}
}
}
}