I think the approach just needs some tweaking. Constraints can be calculated at the click of a cell; when the mouse moves, you know when to stop staining cells.
Here's a breakdown:
jQuery(function($) { document.onselectstart = function () { return false; } var $table = $('#contentPlaceHolderMain_tableAppointment'), columns = [], dragInfo = null; $table.find('td').each(function() { var i = $(this).index(); (columns[i] = columns[i] || []).push(this); });
This creates a composite array so that you can reference each column more easily. This will come in handy later.
$table.on('mouseup', function() {
This is the same as the previous code, except that you notice two differences:
I am setting the click event handler to $table instead of document ; this prevents some overhead from getting clicks outside the table.
Since .live() deprecated, .on() should be used instead.
Go to the mousedown handler.
$table.on('mousedown', 'td', function() { var $this = $(this), columnIndex = $this.index(); if ($this.is('.selected') || columnIndex < 2) { return; } var thisRow = $this.parent().index(), selectionRowAbove = -Infinity, selectionRowBelow = Infinity; $.each(columns[columnIndex], function(rowIndex) { if ($(this).is('.selected')) { if (rowIndex < thisRow && rowIndex > selectionRowAbove) { selectionRowAbove = rowIndex; } else if (rowIndex > thisRow && rowIndex < selectionRowBelow) { selectionRowBelow = rowIndex; } } });
By adding a listener on td instead of tr , you do not need to find the closest cell; It is calculated for you. This part of the function produces red cells above and below the current cell.
// unmark cells $table.find(".csstdhighlight").removeClass("csstdhighlight"); dragInfo = { column: columnIndex, enclosure: { above: selectionRowAbove, below: selectionRowBelow }, min: thisRow, max: thisRow }; $this.addClass('csstdhighlight'); });
The last part of the function saves all the drag and drop data that you will need later.
$table.on('mousemove', 'td', function() { if (!dragInfo) { return; } var $this = $(this), columnIndex = $this.index(), rowIndex = $this.parent().index(); if (columnIndex != dragInfo.column || rowIndex == 0 || rowIndex <= dragInfo.enclosure.above || rowIndex >= dragInfo.enclosure.below) { dragInfo = null; return; }
These conditions ensure that the choice remains within the limits that we determined earlier.
// mark cells var cells = [columns[columnIndex][rowIndex]]; while (dragInfo.min > rowIndex) { cells.push(columns[columnIndex][dragInfo.min--]); } while (dragInfo.max < rowIndex) { cells.push(columns[columnIndex][dragInfo.max++]); } $(cells).addClass('csstdhighlight'); }); });
The last part of the function marks the choice; he does this by calculating the differences between the last call, so you donβt need to mark the cells again.
Demo