Hey asdf,
danke für den link, hier nun meine "fertige" version (nicht wirklich glücklich damit):
// GridView.js
var extend =
{
has: function(val)
{
for(var i = 0; i < this.length; ++i)
if (this[i] == val) return true;
return false;
},
notContainedIn: function(arr)
{
if (typeof(arr.pop) == 'undefined') throw("need another array, not " + typeof(arr));
var ret = [];
if (this.length) for (var i = 0; i < this.length; ++i) if (!arr.has(this[i])) ret.push(this[i]);
return ret;
},
convert: function(cb)
{
var ret = []
for (var i = 0; i < this.length; ++i) ret.push(cb(this[i]));
return ret;
},
each: function(cb)
{
for (var i = 0; i < this.length; ++i) cb(this[i]);
}
};
for (var f in extend)
{
if (typeof(Array.prototype[f]) != 'undefined') throw('dude, array can already do '+f);
Array.prototype[f] = extend[f];
};
var GridSelector = function(table, callback)
{
var local = this;
this.selecting = false;
this.isFocused = false;
this.startElement = null;
this.stopElement = null;
this.fakeLink = null;
this.affected = [];
this.fakeName = 'myFakeControl';
this.old = document.onmouseup;
table.onkeydown = function(e){return local.onkeydown(e);};
table.onkeypress = function(e){if (e.which == 13) {local.stopSelection();local.unfocus();local.fakeLink.blur(e);};};
table.onmouseover = function(e){local.fakeLink.focus(e);};
var td = table.getElementsByTagName('td');
for(var i = 0; i < td.length; ++i)
{
td[i].onmouseover = function(e){local.selectCell(this, e);};
td[i].onmousedown = function(e){local.startSelection(this, e); return false;};
};
if (!(td[0].childNodes.length && td[0].childNodes[0] && td[0].childNodes[0].tagName && td[0].childNodes[0].tagName.toLowerCase() == 'a' && td[0].childNodes[0].className.indexOf(this.fakeName) > -1))
{
this.fakeLink = document.createElement('a');
this.fakeLink.onfocus = function(){local.focus();};
this.fakeLink.onblur = function(){local.unfocus();};
this.fakeLink.className = this.fakeName;
this.fakeLink.innerHTML = '';
this.fakeLink.href = '#';
this.fakeLink.style.position = 'absolute';
this.fakeLink.style.left = '-999em';
td[0].appendChild(this.fakeLink);
};
this.onkeydown = function(e)
{
if (e.which == 37 || e.which == 38 || e.which == 39 || e.which == 40)
{
if (!this.startElement || !this.selecting)
{
var stop = this.stopElement;
this.startSelection(table.rows[this.startElement?this.startElement.y:0].cells[this.startElement?this.startElement.x:0]);
if (stop) this.selectCell(table.rows[stop.y].cells[stop.x]);
};
var x = this.stopElement.x;
var y = this.stopElement.y;
if (e.which == 40)
{
y = y + 1 > table.rows.length - 1?table.rows.length -1:y + 1;
} else if (e.which == 38) {
y = y - 1 < 0?0:y - 1;
} else if (e.which == 39) {
x = x+1 > table.rows[y].cells.length -1?table.rows[y].cells.length -1:x+1;
} else if (e.which == 37) {
x = x - 1 < 0?0:x - 1;
};
this.selectCell(table.rows[y].cells[x]);
return false;
};
};
this.focus = function(e)
{
if (!this.isFocused)
{
table.className += ' focused';
this.isFocused = true;
};
};
this.unfocus = function(e)
{
if (this.isFocused)
{
table.className = table.className.replace(/\ ?focused/gi, "");
this.isFocused = false;
};
};
this.mark = function(cell)
{
if (cell.className.indexOf('selected') > -1) return;
cell.className += ' selected';
};
this.unmark = function(cell)
{
cell.className = cell.className.replace(/\ ?selected/gi, "");
};
this.startSelection = function(cell, e)
{
this.focus();
document.onmouseup = function(e){local.stopSelection(e); if (local.old) local.old(e);};
this.selecting = true;
this.startElement = {x: cell.cellIndex, y: cell.parentNode.rowIndex};
this.selectCell(cell, e);
};
this.selectCell = function(cell, e)
{
if (!this.selecting) return;
var currentlySelected = [];
this.calculateHits(cell).each
(
function(hit)
{
currentlySelected.push(hit);
local.mark(table.rows[hit.split(/,/)[1]].cells[hit.split(/,/)[0]]);
}
);
this.affected.notContainedIn(currentlySelected).each
(
function(hit)
{
local.unmark(table.rows[hit.split(/,/)[1]].cells[hit.split(/,/)[0]]);
}
);
this.affected = currentlySelected;
this.stopElement = {x: cell.cellIndex, y: cell.parentNode.rowIndex};;
};
this.stopSelection = function()
{
if (!this.selecting) return;
this.unfocus();
document.onmouseup = this.old;
var ret = [];
this.affected.each
(
function(hit)
{
ret.push(table.rows[hit.split(/,/)[1]].cells[hit.split(/,/)[0]]);
}
);
this.selecting = false;
if (callback) callback({indices: this.affected, cells: ret});
};
this.calculateHits = function(cell)
{
var low =
{
x: (this.startElement.x < cell.cellIndex ? this.startElement.x:cell.cellIndex),
y: (this.startElement.y < cell.parentNode.rowIndex ? this.startElement.y:cell.parentNode.rowIndex)
};
var high =
{
x: (this.startElement.x >= cell.cellIndex ? this.startElement.x:cell.cellIndex),
y: (this.startElement.y >= cell.parentNode.rowIndex ? this.startElement.y:cell.parentNode.rowIndex)
};
return this.createVectors(low, high);
};
this.createVectors = function(low, high)
{
var ret = [];
for (var i = low.x; i < high.x + 1; ++i)
for (var j = low.y; j < high.y +1; ++j)
ret.push(i+","+j);
return ret;
};
};
un ne kleine webseite dazu:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<style type="text/css">
table td.selected {background:orange}
table.focused {border-color: orange !important}
</style>
<title>test</title>
<meta name="content-type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="GridSelector.js"></script>
</head>
<body>
<table id="test" style="border:1px solid black" cellpadding="5" border="1">
<tbody>
<tr>
<td>a</td>
<td>a</td>
<td>a</td>
<td>a</td>
<td>a</td>
<td>d</td>
<td>a</td>
</tr>
<tr>
<td>a</td>
<td>a</td>
<td>a</td>
<td>a</td>
<td>d</td>
<td>a</td>
<td>a</td>
</tr>
<tr>
<td>a</td>
<td>a</td>
<td>ad</td>
<td>a</td>
<td>a</td>
<td>a</td>
<td>a</td>
</tr>
</tbody>
</table>
<ul>
<li>control fokussieren: maus drüber oder tab bis rand orange</li>
<li>auswählen: mit der maus selektieren und loslassen, oder mit den pfeiltasten (hoch runter rechts links)</li>
<li>selektion übernehmen: maus selektieren und loslassen, mit tasten auswählen und enter drücken</li>
<li>control verlassen: mit der maus ausserhalb klicken, enter drücken, tab drücken</li>
</ul>
<div id="log" style="white-space:pre">
</div>
<script type="text/javascript">
var grid = new GridSelector(document.getElementById('test'), function(cells){try{document.getElementById('log').innerHTML += cells.toSource();} catch(e) {alert("i don't know toSource()");};});
</script>
</body>
</html>
Tschö