tableのtr要素をドラッグ&ドロップで任意に入れ替え

http://oshiete.goo.ne.jp/qa/6275238.html

yyr446 さんの回答(無許可です^^;)を、自分流にインデント処理しながらちょこちょこと。
勉強させて頂きます。(明日から忙しいぞ!)

<!DOCTYPE html>
<title></title>
<style type="text/css">
table, th {
  border:1px #c88 outset;
}
td {
  border:1px #c88 inset;
}
</style>

<body>
<table id="dragtable">
  <tbody>
    <tr><th>A</th><th>B</th><th>C</th></tr>
    <tr draggable="true"><td>a</td><td>b</td><td>c</td></tr>
    <tr draggable="true"><td>あ</td><td>い</td><td>う</td></tr>
    <tr draggable="true"><td rowspan="2">1</td><td>2</td><td>3</td></tr>
    <tr draggable="true"><td>ろ</td><td>は</td></tr>
    <tr draggable="true"><td>x</td><td>y</td><td>z</td></tr>
    <tr draggable="true"><td>X</td><td>Y</td><td>Z</td></tr>
  </tbody>
</table>

<script type="text/javascript">

var bind = function (func, that) {
  return function () {
    func.apply (that, arguments);
  };
};

function Dragtable (table) {
  var canvas = document.createElement ('canvas');
  var ctx = canvas.getContext ('2d');
  
  table.addEventListener ('dragstart', bind (this.handleEvent, this), false);
  table.addEventListener ('dragover', bind (this.handleEvent, this), false);
  table.addEventListener ('drop', bind (this.handleEvent, this), false);
  table.addEventListener ('dragend', bind (this.handleEvent, this), false);

  canvas.width = canvas.height = 26;

  ctx.lineWidth = 2;
  ctx.moveTo (0, 0), ctx.lineTo (26, 13), ctx.moveTo (0, 26), ctx.lineTo (26, 13);
  ctx.stroke ();

  this.table = table;
  this.canvas = canvas;
  this.rowspan = 0;
}

Dragtable.prototype.handleEvent = function (event) {
  var dt = event.dataTransfer;
  var target = event.target;
  var trs;
  var tr;
  var i;
  var target_tr;
  var idx;
  var target_table;

  switch  (event.type) {
  case 'dragstart':
    trs = target.innerHTML;
    this.rowspan = 0;
    this.rowspanchk (target);
    
    if  (this.rowspan > 0)
      for  (i = 0; i < this.rowspan - 1; i++)
        trs += '~' + target.nextElementSibling.innerHTML;

    dt.setData ('text/plain', trs);
    dt.setDragImage (this.canvas, 13, 13);
    dt.effectAllowed = 'move';
    return;

  case 'dragover':
    if  (target.nodeName == 'TD' || target.nodeName == 'TH')
      event.preventDefault ();
    return;

  case 'drop':
    trs = dt.getData ('text/plain').split ('~');
    target_tr = target.parentNode;

    for (i = trs.length; i > 0; i--) {
      tr = target_tr.parentNode.insertRow (target_tr.rowIndex);
      tr.innerHTML = trs[i - 1];
      tr.setAttribute ('draggable', 'true');
      target_tr.parentNode.insertBefore (tr, target_tr.nextElementSibling);
    }
    event.preventDefault ();
    return;

  case 'dragend':
    if (dt.dropEffect == 'move')
      target_table = target.parentNode;

    idx = target.rowIndex;

    if (this.rowspan == 0)
      target_table.deleteRow (idx);

    else
      for (i = this.rowspan - 1; i >= 0; i--)
        target_table.deleteRow (idx + i);

    return;
  }
}


Dragtable.prototype.rowspanchk = function (tr) {
  var td = tr.childNodes;
  var rowspan = [];

  for (var i = 0; i < td.length; i++) {
    if (td[i].getAttribute ('rowspan') > 0)
      rowspan.push (td[i].getAttribute ('rowspan'));
  }

  rowspan.sort ();

  if (rowspan[0]) {
    this.rowspan += rowspan[0];
    arguments.callee (tr.nextElementSibling);
  }
};

myDragTable = new Dragtable (document.getElementById ('dragtable'));
</script>