Merge same cells

Merge same cells

by Destan Sarpkaya

HTML

<table border=1>
  <tr>
    <td>A</td>
    <td>X</td>
    <td>E</td>
    <td>R</td>
  </tr>
  <tr>
    <td>A</td>
    <td>S</td>
    <td>D</td>
    <td>V</td>
  </tr>
  <tr>
    <td>A</td>
    <td>S</td>
    <td>E</td>
    <td>F</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>W</td>
    <td>E</td>
    <td>R</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>X</td>
    <td>D</td>
    <td>F</td>
  </tr>
  <tr>
    <td>Z</td>
    <td>S</td>
    <td>C</td>
    <td>F</td>
  </tr>
  <tr>
    <td>A</td>
    <td>X</td>
    <td>D</td>
    <td>E</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>X</td>
    <td>E</td>
    <td>D</td>
  </tr>
  <tr>
    <td>Z</td>
    <td>X</td>
    <td>S</td>
    <td>D</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>X</td>
    <td>W</td>
    <td>C</td>
  </tr>
</table>

<hr>

<table border=1>
  <tr>
    <td>A</td>
    <td>X</td>
    <td>E</td>
    <td>R</td>
  </tr>
  <tr>
    <td>A</td>
    <td>S</td>
    <td>D</td>
    <td>V</td>
  </tr>
  <tr>
    <td>A</td>
    <td>S</td>
    <td>E</td>
    <td>F</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>W</td>
    <td>E</td>
    <td>R</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>X</td>
    <td>D</td>
    <td>F</td>
  </tr>
  <tr>
    <td>Z</td>
    <td>S</td>
    <td>C</td>
    <td>F</td>
  </tr>
  <tr>
    <td>A</td>
    <td>X</td>
    <td>D</td>
    <td>E</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>X</td>
    <td>E</td>
    <td>D</td>
  </tr>
  <tr>
    <td>Z</td>
    <td>X</td>
    <td>S</td>
    <td>D</td>
  </tr>
  <tr>
    <td>Q</td>
    <td>X</td>
    <td>W</td>
    <td>C</td>
  </tr>
</table>

JavaScript

Array.prototype.slice.call(document.querySelectorAll('table')).forEach((t, i) => {
  i == 1 && t.querySelector('tr').querySelectorAll('td').forEach((tr, index, array) => mergeCells(t, index + 1))
})

/**
 * table - HTML Table node
 * columnIndex - starts from 1
*/
function mergeCells(table, columnIndex) {
  console.log(table, columnIndex)
  Array.prototype.slice.call(table.querySelectorAll(`table td:nth-child(${columnIndex})`)).reduce((accumulator, current, index, array) => {

    let sameAsBefore = accumulator.prev.innerHTML == current.innerHTML;

    if (sameAsBefore && index == array.length - 1) {
      // the last row is the same as previous. Need to handle now because there will be no loop afterwards.
      current.hidden = true;
      array[index - accumulator.count - 1].setAttribute('rowspan', accumulator.count + 2)
    }
    else if (sameAsBefore) {
      current.hidden = true;
    }
    else if (index - accumulator.count - 1 >= 0) {
      array[index - accumulator.count - 1].setAttribute('rowspan', accumulator.count + 1)
    }

    return {
      prev: current,
      count: sameAsBefore ? accumulator.count + 1 : 0
    }
  }, {prev: {}})
}