mouse hover with multiple td rowspan
EDIT: Added a way to find the top of each block.
EDIT 2 - Do the hard work up front Thinking about this again, it is better to just work out at the start which rows are in each block and store that list with each row, e.g. each alphabet row stores a reference to an array containing rows 1-4. So when you hover, you just need to get the array of rows stored in the parent row and apply the class to those.
By checking the maximum rowspan in the top row of the block, you aren't restricted to just checking the first cell. In the updated code, I have moved Alphabet to the middle to demonstrate this and add a couple of other blocks to demonstrate single row blocks work.
function findBlocks(theTable) {
if ($(theTable).data('hasblockrows') == null) {
console.log('findBlocks'); // to prove we only run this once
// we will loop through the rows but skip the ones not in a block
var rows = $(theTable).find('tr');
for (var i = 0; i < rows.length;) {
var firstRow = rows[i];
// find max rowspan in this row - this represents the size of the block
var maxRowspan = 1;
$(firstRow).find('td').each(function () {
var attr = parseInt($(this).attr('rowspan') || '1', 10)
if (attr > maxRowspan) maxRowspan = attr;
});
// set to the index in rows we want to go up to
maxRowspan += i;
// build up an array and store with each row in this block
// this is still memory-efficient, as we are just storing a pointer to the same array
// ... which is also nice becuase we can build the array up in the same loop
var blockRows = [];
for (; i < maxRowspan; i++) {
$(rows[i]).data('blockrows', blockRows);
blockRows.push(rows[i]);
}
// i is now the start of the next block
}
// set data against table so we know it has been inited (for if we call it in the hover event)
$(theTable).data('hasblockrows', 1);
}
}
$("td").hover(function () {
$el = $(this);
//findBlocks($el.closest('table')); // you can call it here or onload as below
$.each($el.parent().data('blockrows'), function () {
$(this).find('td').addClass('hover');
});
}, function () {
$el = $(this);
$.each($el.parent().data('blockrows'), function () {
$(this).find('td').removeClass('hover');
});
});
findBlocks($('table'));
body {
padding: 50px;
}
table {
width: 100%;
border-collapse: collapse;
}
td, th {
padding: 20px;
border: 1px solid black;
}
.hover {
background: red;
}
<table>
<tbody>
<tr>
<td>Symbols</td>
<td>+</td>
<td>-</td>
<td>*</td>
</tr>
<tr>
<td rowspan="2">a</td>
<td>b</td>
<td rowspan="4">Alphabet</td>
<td>c</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
</tr>
<tr>
<td rowspan="2">f</td>
<td>g</td>
<td>h</td>
</tr>
<tr>
<td>i</td>
<td>j</td>
</tr>
<tr>
<td>Bitwise</td>
<td>&</td>
<td>|</td>
<td>^</td>
</tr>
<tr>
<td rowspan="3">Number</td>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
<td>9</td>
</tr>
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
Try this
$(function () {
$("td").hover(function () {
$el = $(this);
$el.parent().addClass("hover");
var tdIndex = $('tr').index($el.parent());
if ($el.parent().has('td[rowspan]').length == 0) {
$el.parent().prevAll('tr:has(td[rowspan]):first')
.find('td[rowspan]').filter(function () {
return checkRowSpan(this, tdIndex);
}).addClass("hover");
}
}, function () {
$el.parent()
.removeClass("hover")
.prevAll('tr:has(td[rowspan]):first')
.find('td[rowspan]')
.removeClass("hover");
});
});
function checkRowSpan(element, pIndex) {
var rowSpan = parseInt($(element).attr('rowspan'));
var cIndex = $('tr').index($(element).parent());
return rowSpan >= pIndex + 1 || (cIndex + rowSpan) > pIndex;
}
Fiddler here