asdf: firefox und table.onkey*

Hey,

nach langer Suche wende ich mich nun ans forum.
Ich möchte für eine Tabelle (nur für die Tabelle, nicht für das document) die onkey* event(s) abfangen um die Tabelle zu bedienen.

  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html>  
<head>  
<title>test</title>  
<script type="text/javascript">  
var log = function (what)  
{  
  document.getElementById('log').innerHTML += what;  
};  
</script>  
</head>  
<body>  
  
<table id="edit">  
  <tbody onkeypress="log('onkeypress')" onkeydown="log('onkeydown')" onkeyup="log('onkeyup')">  
   <tr>  
      <td onkeypress="log('onkeypress td')" onkeydown="log('onkeydown td')" onkeyup="log('onkeyup td')">  
        asdf  
      </td>  
    </tr>  
  </tbody>  
</table>  
  
<div id="log" style="white-space:pre"></div>  
</body>  
</html>  

funktioniert so wie gewollt im opera. nur nicht im firefox (attachEventListener sowie onkey* = function(){} auch nicht) :(

Ich kann mir schon denken, warum das so ist, weil es ja eigentlich keinen sinn macht.

nach einigem fummeln kam ich dann zu dieser notlösung:

  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html>  
<head>  
<title>test</title>  
<script type="text/javascript">  
var log = function (what)  
{  
  document.getElementById('log').innerHTML += what;  
};  
</script>  
</head>  
<body>  
<table id="edit" onmouseover="this.getElementsByTagName('a')[0].focus()" onmouseout="this.getElementsByTagName('a')[0].blur()">  
  <tbody onkeypress="log('onkeypress')" onkeydown="log('onkeydown')" onkeyup="log('onkeyup')">  
    <tr>  
      <td onkeypress="log('onkeypress td')" onkeydown="log('onkeydown td')" onkeyup="log('onkeyup td')">  
        asdfasdf <a href="#" style="position:absolute;left:-999em">bla</a>  
      </td>  
    </tr>  
  </tbody>  
</table>  
<div id="log" style="white-space:pre"></div>  
</body>  
</html>  

irgendwelche vorschläge? es funktioniert, aber gibt mit selektiertem  text (was theoretisch gar nicht nötig ist, aber man weiss ja nicht wie der benutzer das sieht) beim verlassen und wieder eintreten natürlich probleme sowie mit der tabreihenfolge. Danke.

Tschö

  1. Hey asdf,

    der thread könnte dich interessieren. (hilft mir aber nix)

    rofl ...

    Tschö

    1. 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ö