NoviceMe
NoviceMe

Reputation: 3256

How to move arrow up or down in contenteditable

I have a html table in which I can write anything and tabs work. But I am trying to make up and down arrow work as well. I tried few scripts online but not able to make any of those work as those are for particular scenarios. like:

$(document).keydown(function(e){
    switch(e.which){
        case 37: // left arrow            
            $(e.target).closest('td').nextAll('td.editable:first').find('div');
            break;
        case 39: // right arrow
            $(e.target).closest('td').nextAll('td.editable:first').find('div');
            break;
        default: // exit for other keys
            return;
    }
    e.preventDefault(); // prevent default action
});
table{
    border: 1px solid black;
    table-layout: fixed;    
}
tr {
    height: 28px; 
    width: 30px;
}
td{
    border:1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table style="width: 600px;border: 1px solid black;">
<tbody>
<tr style="height: 16px;">
<td colspan="6" style="text-align: center; height: 16px; border: 1px solid black;">
<p><strong>Groups</strong></p>
</td>
</tr>
<tr style="border: 1px; border-color: red;">
<td><p style="text-align: left;"><em><strong>Areas</strong></em></p></td>
<td style="border-color: red;border: 1px solid red;"><div  class="editable"></div></td>
<td style="border-color: red;border: 1px solid red;"><div  class="editable"></div></td>
<td style="border-color: red;border: 1px solid red;"><div  class="editable"></div></td>
<td style="border-color: red;border: 1px solid red;"><div  class="editable"></div></td>
<td style="border-color: red;border: 1px solid red;"><div  class="editable"></div></td>
</tr>
<tr>
<td style="border-color: red;border: 1px solid red;"><div class="editable"></div></td>
<td><div class="editable"></div></td>
<td><div class="editable"></div></td>
<td><div class="editable"></div></td>
<td><div class="editable"></div></td>
<td><div class="editable"></div></td>
</tr>
</tbody>
</table>

Is there a simple script that will make arrows usable in this table?

Upvotes: 1

Views: 1636

Answers (2)

zer00ne
zer00ne

Reputation: 43920

Wouldn't it better to use all 4 arrow keys?

  1. Use .next() for down and right arrow keys.

  2. Use .prev() for up and left arrow keys.

  3. Keep track of your position with .index()

  4. Use .parent() to find the <td> and <tr> (or .closest() if from e.target to <tr>).

  5. Use .eq() and the return index number of .index() to find the same positioned <td> in a neighboring <tr>.

Confused? ...me too just take a look at the Demo.

Demo

Details commented in comments

/* Don't know if you already made the divs contenteditable but
|| if you haven't yet, here's a simple way of doing it.
*/
$('.editable').attr('contenteditable', true);

// Delegate the keydown event to Document Object
$(document).on('keydown', function(e) {
  // Prevent default action
  e.preventDefault();
  /* Establish references to all elements that could possibly be
  || involved. 
  */
  // Reference the <div> being typed into
  var start = $(e.target);
  // Reference the <td> that the <div> is the child of
  var cell = start.parent('td');
  // Reference the <tr> that the <td> is child of 
  var row = cell.parent('tr');
  // Determine the index position of the <td>
  var idx = row.find('td').index(cell);
  //console.log(idx);

  switch (e.which) {
    // Up 
    case 38:
      /* Find the <tr> that's above the current <tr>
      || Find the <td> in the same position as current <td>
      || Find the <div> in that <td> 
      */
      row.prev('tr').find('td').eq(idx).find('.editable').focus();
      break;
      // Left
    case 37:
      /* Find the <td> that's to the left of current <td>
      || Find the <div> within that <td>
      */
      cell.prev('td').find('.editable').focus();
      break;
      // Right
    case 39:
      /* Find the <td> that's to the right of current <td>
      || Find the <div> within that <td>
      */
      cell.next('td').find('.editable').focus();
      break;
      // Down
    case 40:
      /* Find the <tr> that's below the current <tr>
      || Find the <td> in the same position as current <td>
      || Find the <div> in that <td> 
      */
      row.next('tr').find('td').eq(idx).find('.editable').focus();
      break;
      // Ignore other keys
    default:
      return;
  }
  // Stop event bubbling
  e.stopPropagation();
});
table {
  border: 1px solid black;
  table-layout: fixed;
}

tr {
  height: 28px;
  width: 30px;
}

td {
  border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table style="width: 600px;border: 1px solid black;">
  <tbody>
    <tr style="height: 16px;">
      <td colspan="6" style="text-align: center; height: 16px; border: 1px solid black;">
        <p><strong>Groups</strong></p>
      </td>
    </tr>
    <tr style="border: 1px; border-color: red;">
      <td>
        <p style="text-align: left;"><em><strong>Areas</strong></em></p>
      </td>
      <td style="border-color: red;border: 1px solid red;">
        <div class="editable"></div>
      </td>
      <td style="border-color: red;border: 1px solid red;">
        <div class="editable"></div>
      </td>
      <td style="border-color: red;border: 1px solid red;">
        <div class="editable"></div>
      </td>
      <td style="border-color: red;border: 1px solid red;">
        <div class="editable"></div>
      </td>
      <td style="border-color: red;border: 1px solid red;">
        <div class="editable"></div>
      </td>
    </tr>
    <tr>
      <td style="border-color: red;border: 1px solid red;">
        <div class="editable"></div>
      </td>
      <td>
        <div class="editable"></div>
      </td>
      <td>
        <div class="editable"></div>
      </td>
      <td>
        <div class="editable"></div>
      </td>
      <td>
        <div class="editable"></div>
      </td>
      <td>
        <div class="editable"></div>
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 0

grateful
grateful

Reputation: 1128

This would be considerably easier with class names for the <td> or <div> elements, but in their absence, here is a solution. See https://api.jquery.com/category/traversing/tree-traversal/ for more info.

Also, use .focus() to focus the field:

$(document).keydown(function(e) {

  switch (e.which) {
    case 37: // left arrow       
      $(e.target).parent().prev().find('div').focus()
      break;
    case 39: // right arrow
      $(e.target).parent().next().find('div').focus()
      break;
    case 40: // down
      $(e.target).parent().parent().next().children().eq($(e.target).parent().index()).find('div').focus()
      break;
    case 38: // up
      $(e.target).parent().parent().prev().children().eq($(e.target).parent().index()).find('div').focus()
      break;
    default: // exit for other keys
      return;
  }

});
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>

<table style="width: 1400px;border: 1px solid black;">
  <tbody>
    <tr style="height: 16px;">
      <td colspan="6" style="text-align: center; width: 979px; height: 16px; border: 1px solid black;">
        <p><strong>Groups</strong></p>
      </td>
    </tr>
    <tr border: 1px; border-color: red; ">
<td><p style="text-align: left; "><em><strong>Areas</strong></em></p></td>
<td style="border-color: red;border: 1px solid red; "><div contenteditable>fgjhdfjdg</div></td>
<td style="border-color: red;border: 1px solid red; "><div contenteditable><sadffsf</div></td>
<td style="border-color: red;border: 1px solid red; "><div contenteditable>zxcvxzcv</div></td>
<td style="border-color: red;border: 1px solid red; "><div contenteditable>cvbnvbn</div></td>
<td style="border-color: red;border: 1px solid red; "><div contenteditable>REQZX</div></td>
</tr>
<tr>
<td style="border-color: red;border: 1px solid red; "><div contenteditable>CVBXCB</td>
<td><div contenteditable>HJM,HJ</td>
<td><div contenteditable>ASDFAS</td>
<td><div contenteditable>NBCN</td>
<td><div contenteditable>RTWETB</td>
<td><div contenteditable>XCVBXCB</td>
</tr>
</tbody>
</table>

<style>
table{
    border: 1px solid black;
    table-layout: fixed;    
}
tr {
    height: 28px; 
    width: 100px;
}
td{
    border:1px solid #000;
}
</style>

Upvotes: 2

Related Questions