Can you set rowspan / colspan through apps script

2019-07-29 10:47发布

Does anyone have an example of how/if we can set the row/colspan on a TableCell (?) Element in an Apps Script generated Google Document?

Does this need to be done using the .setAttributes() method?

3条回答
成全新的幸福
2楼-- · 2019-07-29 11:02

i found this question, because i wanted to get rid of a RowSpan within a table and searched for an answer to the question "How can i set RowSpan or ColSpan to 1.

As you lot did, i had to realize that there is no way to get writable access to these hidden properties of a TableCell.

But on my research i found an answer to this question. It's an uncomfortable workaround, but once when it is set up properly, it works very nice:

The key is that you can delete a cell and replace it by a deep copy of a cell, which you spanned manually before.

If you have a table with some spanning cells, created manually, for example a table with 3 rows and 3 cells, which you spanned them all, then you can make a deep detached copy of the spanning cell and insert it anywhere in another table. The inserted cell in the destination table will span the surrounding cells as it does in the source table.

You have to know that the contents of the surrounding cells are still there, but cannot be seen. And if you delete the spanning cell again or you do the unspanning manually, they will be shown again.

This insert of the already spanning srcCell has the same effect as if you would lay a 3x3 cells overlapping white paper on the destination table. All the cells are still there, but you can't see them. The guugel-doc engine shows only the contents of the spanning cell.

And this behavior can be copied. Isn't that nice?

I know, this is a moloch, if you have to span many cells with many different spanning-widths and directions, but if you designed it for your needs, it maybe worth the time you have to spend for the spanning cell patterns.

One could create a document, which holds only tables with all the spanning cells, you need. And you can use this document as your "Spanning Cells Source".

You can make a copy of the following test-document, which contains 3 tables and clearly shows the principle behind it. The first table holds a 3x3 spanning cell at tableindex 0,0. The second table holds the indexes of each cell in the cell itself as row,col pairs and a "TestCell", which should span 3x3 other cells. The 3rd table is for comparison only:

https://docs.google.com/document/d/1G8C2JP_4689RFmtxHZ2djslwoGWwHwieHfbIwr2XzeQ/edit

And then you have access to the bound script, which preserves the contents of the "TestCell", replaces it by a 3 times 3 spanning cell and puts the content back again. You will see the following bound script:

var doc     = DocumentApp.getActiveDocument();
var docBody = doc.getBody();

function myFunction() {
  var tables   = docBody.getTables();
  var srcTable = tables[ 0 ];
  var dstTable = tables[ 1 ];

  var foundText = docBody.findText( "TestCell" );
  if ( foundText ) {
    //  The cell that should span others
    var dstCell = foundText.getElement().getParent().getParent();

    //  If you want to preserve the contents of the cell
    var cellContents = [];
    var numChildren  = dstCell.getNumChildren();
    for ( var i = 0; i<numChildren; i++ ) {
      cellContents.push( dstCell.getChild( i ).copy() );
    }

    //  Row- and ColumnIndex of the future spanning cell
    var dstRowIndex = dstTable.getChildIndex( dstCell.getParent() );
    var dstColIndex = dstCell.getParent().getChildIndex( dstCell );

    //  Deep, detached copy of an already spanning cell
    var srcCell = srcTable.getCell( 0, 0 ).copy();

    // delete dstCell and insert the deep, detached copy of the spanning cell
    dstCell.removeFromParent();
    dstCell = dstTable.getChild( dstRowIndex ).insertTableCell( dstColIndex, srcCell );

    //  If you preserved the contents of the deleted, non-spanning cell,
    //     you can put them back again
    for ( var i = numChildren-1; i>=0; i-- ) {
      var childType = cellContents[ i ].getType();
      // Do not forget to extend this switch by your other ElementTypes !!!
      switch ( childType ) {
        case DocumentApp.ElementType.PARAGRAPH:
          dstCell.insertParagraph( 0, cellContents[ i ] );
          break;
      }
    }
    //  Get rid of the default single and empty PARAGRAPH of the srcCell,
    //      if you had to put back the contents of the delted non-spanning cell
    dstCell.removeChild( dstCell.getChild( dstCell.getNumChildren() - 1 ) );
  }
}

I hope, this can help.

Thank you very much for your attention,

Richard

查看更多
来,给爷笑一个
3楼-- · 2019-07-29 11:03

I have discovered a very kludgy workaround for the lack of colspan in GAS...

  1. create a table (FlexTable, Grid, etc.) with the columns/row you want
  2. when you get to an area where you'd like to use colspan or rowspan, create a new table (with different cell widths and heights
  3. keep on creating a new table every time you want to change the cell widths or heights
  4. create a VerticalPanel and add each of the tables you created in steps 1-3 in order

You now have the appearance of a single table with colspan and rowspan features.

Not very elegant, but it's the only solution I've been able to come up with.

查看更多
神经病院院长
4楼-- · 2019-07-29 11:07

No, there is currently no way to do this. I don't see a feature request on the Issue Tracker, either.

There is a .merge() method on the TableCell object, which sounds promising. However, when it's used it combines the "current" TableCell object with the "previous" sibling TableCell by appending the content of the "current" TableCell to the "previous" one, then deleting the "current" one.

Before

Before

After

After

Code

I modified the code from a previous answer to experiment with .merge(), here it is:

function mergeExperiment() {
  var folder = "StackOverflow";
  var docname = "Experiment.gdoc";
  var docId = getFileByName_(folder, docname).getId();

  var doc = DocumentApp.openById(docId);
  var docBody = doc.getActiveSection();

  var totalElements = doc.getNumChildren();
  var el=[]
  for( var j = 0; j < totalElements; ++j ) {
    var element = doc.getChild(j);
    var type = element.getType();

    switch (type) {
      case DocumentApp.ElementType.PARAGRAPH:
        break;

      case DocumentApp.ElementType.TABLE:
        var tablerows=element.getNumRows();
        for ( var row = 0; row < tablerows; ++row ) {
          var tablerow = element.getRow(row)
          for ( var cell=0; cell < tablerow.getNumCells(); ++cell) {
            // Experiment - merge two cells in the second row
            if (row==1 && cell==1) {
              tablerow.getChild(cell).merge();
            }
          }
        }
        break;
    }
  }
}
查看更多
登录 后发表回答