I need the help of an expert on my question below as it exceed and goes well beyond the level of knowledge that I have for programming in JavaScript.
Given the existing
I don't think this actually needs to be that long--you just need to keep the index of the currently highlighted row.
This has only been tested on Chrome (I don't have IE), but it should work.
(function() {
/**
* Gets the tr at the specified row or column
*/
var tbody = document.getElementsByTagName('tbody')[0];
function getRow(row) {
return tbody.getElementsByTagName('tr')[row];
}
// store these so we won't have to keep recalculating
var numRows = tbody.getElementsByTagName('tr').length;
// index of the currently highlighted row
var curRow = 0;
// highlight the initially highlighted cell
getRow(curRow).className = 'highlighted';
// listen for keydown event
if (addEventListener) {
window.addEventListener('keydown',keydownHandler, false);
} else if (window.attachEvent) {
window.attachEvent('onkeydown', keydownHandler);
}
// handle keydown event
function keydownHandler (evt) {
// return the old cell to normal
getRow(curRow).className = 'normal';
// increment/decrement the position of the current cell
// depending on the key pressed
if (evt.keyCode == 38 && curRow > 0) // up
curRow--;
else if (evt.keyCode == 40 && curRow < numRows-1) // down
curRow++;
// update the new cell
getRow(curRow).className = 'highlighted';
}
})();//end script
I have create a demo using JQuery here on JSBin
In general, we have 2 task:
To highlight the "clicked" row, I use this code
$("#mstrTable tr").click(function(evt){
var element = $(evt.target);
var tableElement = element.parents('table');
tableElement.find('tr').removeClass('highlighted');
element.parents('tr').addClass('highlighted');
});
To choose next/prev row, I use jQuery tree traversal function with some exception when there is no tr inside your tbody. Note that keyCode of left, right, up, down arrow are 37, 39, 38, 40 respectively.
$(document).keypress(function(evt){
var highlightedRow = $("#mstrTable .highlighted");
if (highlightedRow.length > 0) // table cell is selected
{
var tbodyElement = highlightedRow.parents('tbody');
var trElements = tbodyElement.find('tr');
var nextElement = highlightedRow.next('tr');
var prevElement = highlightedRow.prev('tr');
trElements.removeClass("highlighted");
switch(evt.keyCode)
{
case 40:
if(nextElement.length)
{
nextElement.addClass('highlighted');
}
else if (trElements.length)
{
$(trElements[0]).addClass('highlighted');
}
break;
case 38:
if(prevElement.length)
{
prevElement.addClass('highlighted');
}
else if (trElements.length)
{
$(trElements[trElements.length - 1]).addClass('highlighted');
}
break;
}
}
});
Here is the complete solution which selects rows in table just like a windows file selection works.
add class multiSelect to you table and then place this code in a JS file
$(document).ready(function() {
var selectionPivot;
// code for selected rows.
$('.multiSelect tbody').on( 'click', 'tr', function (e) {
var tbodyElement = $(this).parents('tbody');
var trElements = tbodyElement.find('tr');
if(!e.ctrlKey && (!e.shiftKey) ){
trElements.removeClass("row_selected");
selectionPivot=$(this);
}
if(e.shiftKey){
var bot = Math.min(selectionPivot[0].rowIndex, $(this)[0].rowIndex);
var top = Math.max(selectionPivot[0].rowIndex, $(this)[0].rowIndex);
trElements.removeClass("row_selected");
for(var i=bot; i<=top; i++){
trElements[i-1].className+=" row_selected";
}
}
else {
selectionPivot=$(this);
trElements.removeClass("focus");
$(this).addClass('focus');
if ( $(this).hasClass('row_selected') ) {
$(this).removeClass('row_selected');
}
else {
$(this).addClass('row_selected');
}
}
});
$(document).keypress(function(evt){
if(evt.shiftKey){
var highlightedRow = $(".multiSelect .focus");
if (highlightedRow.length > 0) // table cell is selected
{
var tbodyElement = highlightedRow.parents('tbody');
var trElements = tbodyElement.find('tr');
var nextElement = highlightedRow.next('tr');
var prevElement = highlightedRow.prev('tr');
trElements.removeClass("focus");
switch(evt.keyCode)
{
case 40:
if(nextElement.length)
{
nextElement.addClass('row_selected');
nextElement.addClass('focus');
}
else if (trElements.length)
{
$(trElements[0]).addClass('row_selected');
$(trElements[0]).addClass('focus');
}
break;
case 38:
if(prevElement.length)
{
prevElement.addClass('row_selected');
prevElement.addClass('focus');
}
else if (trElements.length)
{
$(trElements[trElements.length - 1]).addClass('row_selected');
$(trElements[trElements.length - 1]).addClass('focus');
}
break;
}
}
}
});
});
This is certainly not optimal, but as you're not using jQuery (or a similar library) you've incurred a lot of cross browser overhead. This should be backwards compatible up to IE8.
Live Demo
HTML
Only change here is the addition of the tabindex
<table tabindex='0' id="mstrTable" cellspacing="0" border="1">
JS
//From: http://forrst.com/posts/JavaScript_Cross_Browser_Event_Binding-yMd
var addEvent = (function( window, document ) {
if ( document.addEventListener ) {
return function( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
elem.addEventListener(type, cb, false );
}
else if ( elem && elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
addEvent( elem[i], type, cb );
}
}
};
}
else if ( document.attachEvent ) {
return function ( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
elem.attachEvent( 'on' + type, function() { return cb.call(elem, window.event) } );
}
else if ( elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
addEvent( elem[i], type, cb );
}
}
};
}
})( this, document );
//derived from: http://stackoverflow.com/a/10924150/402706
function getpreviousSibling(element) {
var p = element;
do p = p.previousSibling;
while (p && p.nodeType != 1);
return p;
}
//derived from: http://stackoverflow.com/a/10924150/402706
function getnextSibling(element) {
var p = element;
do p = p.nextSibling;
while (p && p.nodeType != 1);
return p;
}
;(function() {
var trows = document.getElementById("mstrTable").rows;
for (var t = 1; t < trows.length; ++t) {
trow = trows[t];
trow.className = "normal";
trow.onclick = highlightRow;
}//end for
function highlightRow() {
for ( var t = 1; t < trows.length; ++t ) {
trow = trows[t];
if (trow != this) { trow.className = "normal" }
}//end for
this.className = (this.className == "highlighted")?"normal":"highlighted";
}//end function
addEvent(document.getElementById('mstrTable'), 'keydown', function(e){
var key = e.keyCode || e.which;
if((key === 38 || key === 40) && !e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey){
var highlightedRows = document.querySelectorAll('.highlighted');
if(highlightedRows.length > 0){
var highlightedRow = highlightedRows[0];
var prev = getpreviousSibling(highlightedRow);
var next = getnextSibling(highlightedRow);
if(key === 38 && prev && prev.nodeName === highlightedRow.nodeName){//up
highlightedRow.className = 'normal';
prev.className = 'highlighted';
} else if(key === 40 && next && next.nodeName === highlightedRow.nodeName){ //down
highlightedRow.className = 'normal';
next.className = 'highlighted';
}
}
}
});
})();//end script