0

I am trying to append a Google Docs document to another one using Apps Script. Everything works fine except whenever there is an image nested inside a table cell, the image will disappear (just a placeholder with an exclamation mark is displayed).

enter image description here

Piece of code (just for tables):

function mergeTestMinimal() {
  var body = DocumentApp.openById("1XmWwK2ni2JyX4Ii1ow19AehLqPkdYGOsj5XFSrlkaw4").getBody(); //Document to insert new content
  var otherBody = DocumentApp.openById("1ygNn1kgiFchuSf1mBs6RiS4GiBx3KPcKK07E_WWlsBE").getBody(); //To be copied
  var totalElements = otherBody.getNumChildren();
  for (var j = 0; j < totalElements; ++j) {  
    var element = otherBody.getChild(j).copy();
    var type = element.getType();
    if (type == DocumentApp.ElementType.TABLE){
      body.appendTable(element);
    } 
  }
}

Is there anything wrong with my code or is it a bug in the append method?

EDIT: I read the suggested links but they don't solve the issue. It is explained how to merge two documents in the same way as I did it, but nested table images get corrupted there, too. otherBody.getChild(j) seems to lose the nested table images. Are there any workarounds?

Summer Moon
  • 107
  • 5
  • 1
    Hi, I cannot find the documentation related to `getActiveSection()`, can you provide a link to it? – Iamblichus Jan 02 '23 at 09:02
  • 1
    Hi, thanks a lot for looking into the issue. Yes, you are right, the method seems to be obsolete (but is still working). I replaced it with `getBody()`. It does not affect the issue. – Summer Moon Jan 02 '23 at 12:40
  • 1
    Can you provide sample documents to test this behavior? – Iamblichus Jan 03 '23 at 08:16
  • When this document is merged with another one (e.g. a blank one) the images get corrupted: https://docs.google.com/document/d/1HqrAZmTmisTi-902ovhOOBkrAZ3JXVG400xvVI4Hxso/edit?usp=sharing – Summer Moon Jan 03 '23 at 23:13

1 Answers1

2

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;
        }
      }
    }
  }
}
Summer Moon
  • 107
  • 5