2

I need the functionality of selecting and deselecting a table cell range. The attached code works perfectly but it uses JQuery while the rest of my project uses plain JavaScript. onmousedown, onmouseover, and onmouseup are the three mouse events used in this code.
I tried to convert this JQuery code to plain JavaScript but could not succeed. I would very much appreciate if you can help me in this regard.
Thank you!

var table = $("#table");    

var isMouseDown = false;
var startRowIndex = null;
var startCellIndex = null;

function selectTo(cell) {
    
    var row = cell.parent();    
    var cellIndex = cell.index();
    var rowIndex = row.index();
    
    var rowStart, rowEnd, cellStart, cellEnd;
    
    if (rowIndex < startRowIndex) {
        rowStart = rowIndex;
        rowEnd = startRowIndex;
    } else {
        rowStart = startRowIndex;
        rowEnd = rowIndex;
    }
    
    if (cellIndex < startCellIndex) {
        cellStart = cellIndex;
        cellEnd = startCellIndex;
    } else {
        cellStart = startCellIndex;
        cellEnd = cellIndex;
    }        
    
    for (var i = rowStart; i <= rowEnd; i++) {
        var rowCells = table.find("tr").eq(i).find("td");
        for (var j = cellStart; j <= cellEnd; j++) {
            rowCells.eq(j).addClass("selected");
        }        
    }
}

table.find("td").mousedown(function (e) {
    isMouseDown = true;
    var cell = $(this);

    table.find(".selected").removeClass("selected"); // deselect everything
    
    if (e.shiftKey) {
        selectTo(cell);                
    } else {
        cell.addClass("selected");
        startCellIndex = cell.index();
        startRowIndex = cell.parent().index();
    }
    
    return false; // prevent text selection
})
.mouseover(function () {
    if (!isMouseDown) return;
    table.find(".selected").removeClass("selected");
    selectTo($(this));
})
.bind("selectstart", function () {
    return false;
});

$(document).mouseup(function () {
    isMouseDown = false;
});
table td {
    border: 1px solid #999;
    width: 40px;
    height: 15px;
    margin: 10px;
}

td.selected {
    background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
Click and drag mouse or use shift key to select cells.
<table id="table">

  <tr>
    <td></td><td></td><td></td><td></td>
  </tr>
  <tr>
    <td></td><td></td><td></td><td></td>
  </tr>
  <tr>
    <td></td><td></td><td></td><td></td>
  </tr>
  <tr>
    <td></td><td></td><td></td><td></td>
  </tr>
  
</table>

</body>

1 Answer 1

4

Use querySelectorAll and play with the index or use foreach depending on the use.

window.onload = function() {

  var table = document.getElementById('table');
  var isMouseDown = false;
  var startRowIndex = null;
  var startColumnIndex = null;

  table.querySelectorAll('tr').forEach(function(tr, rowIndex) {
    tr.querySelectorAll('td').forEach(
      function(td, columnIndex) {
        td.addEventListener('mousedown', function() {
          isMouseDown = true;
          startRowIndex = rowIndex;
          startColumnIndex = columnIndex;
          table.querySelectorAll('td').forEach(function(td) {
            td.removeAttribute('class')
          })
          setSelectedInRange(startRowIndex, startColumnIndex, rowIndex, columnIndex)
        })
        td.addEventListener('mouseover', function() {
          if(!isMouseDown) return;
          setSelectedInRange(startRowIndex, startColumnIndex, rowIndex, columnIndex)
        })
      }
    )
  })

  document.addEventListener('mouseup', function() {
    isMouseDown = false;
  })
}

function setSelectedInRange(rowStart, columnStart, rowEnd, columnEnd) {
  var table = document.getElementById('table');
  table.querySelectorAll('td').forEach(function(td) {
    td.removeAttribute('class')
  })
  if(rowStart > rowEnd) {
    var temp = rowStart;
    rowStart = rowEnd;
    rowEnd = temp;
  }
  if(columnStart > columnEnd) {
    var temp = columnStart;
    columnStart = columnEnd;
    columnEnd = temp;
  }
  var rows = table.querySelectorAll('tr');
  for(var i = rowStart; i <= rowEnd; i++) {
    var currentRow = rows[i];
    var columns = currentRow.querySelectorAll('td');
    for(var j = columnStart; j <= columnEnd; j++) {
      columns[j].setAttribute('class', 'selected')
    }
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! I was not using a variable like tempRow in your setSelectedInRange function. I am still unclear about its logic in the code. Can you help me understand the role of tempRow variable?
It is used just to reverse the start and the end, the name is quite confusing but I will change it to temp, it's more accurate

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.