tags:

views:

202

answers:

1

In Javascript:

I need to implement selection via click, control click and shift click on rows in an html table, such as in windows explorer, and I hate to write it if the code already exists.

Can anyone point me in the right direction?

thanks!

+1  A: 

The required script is very simple. Something like this will work:

var keyDown = null;
var selectedRows;
var allRows;

function bindEvents()
{
    allRows = document.getElementsByTagName("tr");
    document.onkeydown = function(e) { if (!e) e = window.event; if (e.ctrlKey) keyDown = "ctrl"; if (e.shiftKey) keyDown = "shift";};
    document.onkeyup = function(e) { keyDown = null; };
    for (var i = 0, l = allRows.length; i<l; i++)
    {
        allRows[i].onclick = new Function("selectRow(" + i + ")");
    }
}
function selectRow(rowID)
{
    if (!keyDown)
        selectedRows = [rowID];
    else
    {
        if (keyDown == "ctrl")
            selectedRows.push(rowID);
        else
        {
            if (selectedRows.length>0)
            {
                var lastSelected = selectedRows[selectedRows.length-1];
                for (var i=lastSelected+1; i<=rowID; i++)
                    selectedRows.push(i);
            }
            else
                selectedRows.push(rowID);
        }
    }
    for (var i=0, l = allRows.length; i<l; i++)
        allRows[i].style.backgroundColor = "";
    if (selectedRows.length>0)
        for (var i=0, l = selectedRows.length; i<l; i++)
            allRows[selectedRows[i]].style.backgroundColor = "red";
    keyDown = null;
}

Add body onload="bindEvents()" and it will work on all tables you have in the page (if you have more than one, you might have to change the script to only use the one you care about). It's not the most beautiful code, but it will do the trick.

Ilya Volodin
Woops, just noticed one issue with this script. It will work with shift if you select row 1 first and shift select row 5 (for example), but it will not work if you select row 5 first and shift select row 1. Not hard to change, just add a check for lastSelected > rowID and do a decrementing loop.P.S. Code above verified in IE8 + FF3.
Ilya Volodin
The keyup/keydown events are not necessary: the altKey, ctrlKey and shiftKey properties are in the event object of an onclick handler, too. Moreover, there's something not working properly: when I first select a row and then ctrl-click another one, the previously selected row is unselected. And you shouldn't use `new Function` if not necessary. You can just use `allRows[i].onclick = selectRow;` and use `this.rowIndex` in the event handler to get the row number.
Marcel Korpel
keyup/keydown is used cause you can't pass event as part of new Function. this.rowIndex would work, but would require some additional manipulations. As with everything in JS, there are 10000 ways to write the same thing. And select + ctrl+select works fine for me, not sure what could be wrong there.
Ilya Volodin
Yes, but not every way is considered good practice. A short explanation of why `new Function` is bad is here: http://javascript.about.com/library/blfunc.htm "Firstly the function content is passed as a literal in the last parameter to the call and is evaluated (the same as if it were in an `eval` statement) every time the statement is called. The second difference is that all of the variables defined within this type of function definition are not restricted in scope to the function itself." See also http://oreilly.com/javascript/excerpts/javascript-good-parts/bad-parts.html
Marcel Korpel
Agree on the count of new Function. It's defiantly not the most elegant way to write this, and it's not optimized. I don't know if it's going to be much slower then navigating from the target element over to the parent until you find "tr" tag and then pulling rowIndex from tr element, but most likely it will be. And I didn't know about the scope with new Function. Thanks for the info.
Ilya Volodin
It will be **much** slower, I read somewhere that this `eval` uation of a function is 80-90% slower than directly referencing an existing function. You don't have to look for the `tr` element, as `this` will have the scope of the clicked element. Another drawback is that minifiers cannot change/shorten the name of the referenced function, or worse, they actually shorten the function name but not the string that refers to it.
Marcel Korpel
good discussion, thanks!
sdfor