asdf: firefox und table.onkey*

Beitrag lesen

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ö