0
votes

I use this function to get a table from Google Spreadsheets and be able to paste it into Gmail with another function. It works really well except it doesn't include merged cells.

I do manage to get the merged cells, but I'm not able to 'paste' them into the HTML table. Right now the merged cells result in this. The cells that I would like to see merged look like this.

I've tried this Google Apps Script library, but merged cells is not supported.

You can find the Google Spreadsheet and Google Script on this page.

This is the function:

function GETTABLE(range){
  var ss = range.getSheet().getParent();
  var sheet = range.getSheet();
  startRow = range.getRow();
  startCol = range.getColumn();
  lastRow = range.getLastRow();
  lastCol = range.getLastColumn();

  // Read table contents
  var data = range.getValues();

  // Get css style attributes from range
  var fontColors = range.getFontColors();
  var backgrounds = range.getBackgrounds();
  var fontFamilies = range.getFontFamilies();
  var fontSizes = range.getFontSizes();
  var fontLines = range.getFontLines();
  var fontWeights = range.getFontWeights();
  var horizontalAlignments = range.getHorizontalAlignments();
  var verticalAlignments = range.getVerticalAlignments();
  var mergedRanges = range.getMergedRanges();

  // Get column widths in pixels
  var colWidths = [];
  for (var col=startCol; col<=lastCol; col++) { 
    colWidths.push(sheet.getColumnWidth(col));
  }

  // Get row heights in pixels
  var rowHeights = [];
  for (var row=startRow; row<=lastRow; row++) { 
    rowHeights.push(sheet.getRowHeight(row));
  }

  // Future consideration...
  var numberFormats = range.getNumberFormats();

  // Build HTML Table, with inline styling for each cell
  var tableFormat = 'style="border:1px solid black;border-collapse:collapse;text-align:center" border=1 cellpadding=5';
  var html = ['<table '+tableFormat+'>'];

  // Implement merged cells
  for (var i = 0; i < mergedRanges.length; i++) {
    html.push(mergedRanges[i].getA1Notation());
    html.push(mergedRanges[i].getDisplayValue());
  }

  // Column widths appear outside of table rows
  for (col=0;col<colWidths.length;col++) {
    html.push('<col width="'+colWidths[col]+'">')
  }

  // Populate rows
  for (row=0;row<data.length;row++) {
    html.push('<tr height="'+rowHeights[row]+'">');
    for (col=0;col<data[row].length;col++) {

      // Get formatted data
      var cellText = data[row][col];
      if (cellText instanceof Date) {
        cellText = Utilities.formatDate(
                     cellText,
                     ss.getSpreadsheetTimeZone(),
                     'MMM/d EEE');
      }
      var style = 'style="'
                + 'color: ' + fontColors[row][col]+'; '
                + 'font-family: ' + fontFamilies[row][col]+'; '
                + 'font-size: ' + fontSizes[row][col]+'; '
                + 'font-weight: ' + fontWeights[row][col]+'; '
                + 'background-color: ' + backgrounds[row][col]+'; '
                + 'text-align: ' + horizontalAlignments[row][col]+'; '
                + 'vertical-align: ' + verticalAlignments[row][col]+'; '
                +'"';
      html.push('<td ' + style + '>'
                +cellText
                +'</td>');
    }
    html.push('</tr>');
  }
  html.push('</table>');

  return html.join('');
}
1
Welcome. Have you already reviewed developers.google.com/apps-script/reference/spreadsheet and searched this site for related questions?Rubén
something more you could share is what happens when you use this function to fetch a spreadsheet with merged cells; "it doesn't include merged cells" is ambiguous: do rows with merged cells end up with fewer columns? do they have the right number of columns to match the merged cells, but the cells are empty? do they have the number of columns that would be there if the cells weren't merged, and they are empty? etc.landru27
@Rubén Thank you. I've managed to get the merged cells with "var mergedRanges = range.getMergedRanges();", but I don't know how to implement them in the HTML code.user10626633
@landru27 Thank you, i will add this into my question.user10626633
@landru27 I've added additional information and my findings in the question.user10626633

1 Answers

0
votes

I was able to get this to work by checking if the cell was merged or not using .isPartOfMerge(). If it was a part of a merged cell it then checks the cells to the right that are blank and also considered merged cells. If it meets these two criteria it creates a colspan element to capture how wide the cell should be. If the merged cell continues to the next row it won't catch this.

This may not be the most efficient code as I used a if and else if statement to write out the table and it gets repetitive with the code.

function getHtmlTable(range){
  var ss = range.getSheet().getParent();
  var sheet = range.getSheet();
  startRow = range.getRow();
  startCol = range.getColumn();
  lastRow = range.getLastRow();
  lastCol = range.getLastColumn();

  // Read table contents
  var data = range.getDisplayValues();

  // Get css style attributes from range
  var fontColors = range.getFontColors();
  var backgrounds = range.getBackgrounds();
  var fontFamilies = range.getFontFamilies();
  var fontSizes = range.getFontSizes();
  var fontLines = range.getFontLines();
  var fontWeights = range.getFontWeights();
  var horizontalAlignments = range.getHorizontalAlignments();
  var verticalAlignments = range.getVerticalAlignments();

  // Get column widths in pixels
  var colWidths = [];
  for (var col=startCol; col<=lastCol; col++) { 
    colWidths.push(sheet.getColumnWidth(col));
  }
  // Get Row heights in pixels
  var rowHeights = [];
  for (var row=startRow; row<=lastRow; row++) { 
    rowHeights.push(sheet.getRowHeight(row));
  }

  // Future consideration...
  var numberFormats = range.getNumberFormats();

  // Get Merged ranges
  var mergedCells = range.getMergedRanges();

  // Build HTML Table, with inline styling for each cell
  var tableFormat = 'style="border:1px solid black;border-collapse:collapse;text-align:center" border = 1 cellpadding = 5';
  var html = ['<table '+tableFormat+'>'];
  var sameText = false
  // Column widths appear outside of table rows
  for (col=0;col<colWidths.length;col++) {
    html.push('<col width="'+colWidths[col]+'">')
  }
  // Populate rows
  for (row=0;row<data.length;row++) {
    html.push('<tr height="'+rowHeights[row]+'">');
    for (col=0;col<data[row].length;col++) {
      if(sheet.getRange(startRow+row,startCol+col).isPartOfMerge() && data[row][col] !="") {
      // Get formatted data
        var colspan = 1;
        for (var colcount=col+1;colcount<data[row].length;colcount++) {
          if(sheet.getRange(startRow+row,startCol+colcount).isPartOfMerge() && data[row][colcount] =="") {
            colspan = colspan + 1; 
          }
          else {
            colcount = data[row];
          }
        }
      var cellText = data[row][col];
      if (cellText instanceof Date) {
        cellText = Utilities.formatDate(
                     cellText,
                     ss.getSpreadsheetTimeZone(),
                     'MMM/d EEE');
      }
      var style = 'style="'
                + 'color: ' + fontColors[row][col]+'; '
                + 'font-family: ' + fontFamilies[row][col]+'; '
                + 'font-size: ' + fontSizes[row][col]+'; '
                + 'font-weight: ' + fontWeights[row][col]+'; '
                + 'background-color: ' + backgrounds[row][col]+'; '
                + 'text-align: ' + horizontalAlignments[row][col]+'; '
                + 'vertical-align: ' + verticalAlignments[row][col]+'; '
                +'"';
      html.push('<td ' + style + 'colspan = "' + colspan +'">'
                +cellText
                +'</td>');
      }
      else if(sheet.getRange(startRow+row,startCol+col).isPartOfMerge() && data[row][col] =="") {
      //nothing happens just leave blank
      }
      else {
      // Get formatted data
      var cellText = data[row][col];
      if (cellText instanceof Date) {
        cellText = Utilities.formatDate(
                     cellText,
                     ss.getSpreadsheetTimeZone(),
                     'MMM/d EEE');
      }
      var style = 'style="'
                + 'color: ' + fontColors[row][col]+'; '
                + 'font-family: ' + fontFamilies[row][col]+'; '
                + 'font-size: ' + fontSizes[row][col]+'; '
                + 'font-weight: ' + fontWeights[row][col]+'; '
                + 'background-color: ' + backgrounds[row][col]+'; '
                + 'text-align: ' + horizontalAlignments[row][col]+'; '
                + 'vertical-align: ' + verticalAlignments[row][col]+'; '
                +'"';
      html.push('<td ' + style + '>'
                +cellText
                +'</td>');
    }

    } 

    html.push('</tr>');
  }
  html.push('</table>');

  return html.join('');
}