WAI ARIA のドラッグ&ドロップの実装(キー操作による)

このロゴだけど、田舎くさいと思うのは俺だけか?


追記:自分のコードは、棚にあがってるな。

開発環境
http://oshiete.goo.ne.jp/qa/6462119.html

エディターと、Firefox と、 alert([a,b,c])と、リロードなんだけど

WAI ARIA のドラッグ&ドロップの実装

眠いです。手抜きで、画像の @alt をコピーするだけ

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta http-equiv="Content-Script-Type" content="text/javascript">
  <meta http-equiv="Content-Style-Type" content="text/css">
  
  <title>WAI ARIA のドラッグ&ドロップの実装</title>
  
  <style type="text/css">
  #box0, #box1 {
    height: 60px;
    border: 2px #fdd solid;
    padding: 1ex;
  }
  
  #box0 img {
    width: 40px;
    height: 40px;
    border: 4px #888 outset;
  }
  #box1 {
    width:95%;
  }

  * [aria-grabbed="true"] {
    border: 4px #f00 inset !important;
  }

  * [aria-dropeffect]:focus {
    border: 4px #00f inset !important;
  }
  
  </style>
<head>

<body>
  <h1>WAI ARIA のドラッグ&ドロップの実装</h1>
  <h2>ここから下のボックスに数字を移動します</h2>
  <div id="box0">
    <img src="./img/0.gif" alt="0" aria-grabbed="false" aria-controls="copy" tabindex="0">
    <img src="./img/1.gif" alt="1" aria-grabbed="false" aria-controls="copy" tabindex="0">
    <img src="./img/2.gif" alt="2" aria-grabbed="false" aria-controls="copy" tabindex="0">
    <img src="./img/3.gif" alt="3" aria-grabbed="false" aria-controls="copy" tabindex="0">
    <img src="./img/4.gif" alt="4" aria-grabbed="false" aria-controls="copy" tabindex="0">
  </div>
  <hr>
  <input type="text" id="box1" tabindex="0" size="80" aria-dropeffect="none">
  <ul>
    <li>Web Forms/HTML5 の各属性は、WAI ARIA 属性にもマッピングされている
    <li>HTML 4.0+ARIA 1.0 文書型を宣言する
    <li>ラッグの対象には @aria-grabbed を付ける
    <li>ドラッグできないなら undefined、ドラッグ中でないなら false、ドラッグ中なら true
    <li>SPC でドラッグ対象選択、Shift-SPC で連続範囲選択、Ctrl-SPC で非連続選択
    <li>ドロップの対象には @aria-dropeffect="none" をセット
    <li>ドラッグ対象が選択されたら、ドラッグ対象の @aria-controls で識別されるドロップ対象の @aria-dropeffect を copy、move、link、execute、popup などの任意値のリストにセットする
    <li>Ctrl-M でドロップ。ESC でキャンセル
    <li>ドロップ対象の @aria-dropeffect を none に戻す
    <li>ドラッグ対象の @aria-grabbed を false に戻す
    <li>@tabindex には原則として -1 を与え、フォーカスを受け取った要素にのみ 0 を与えます
    <li>
    <li>
  </ul>
<script type="text/javascript">
<!--
//@cc_on

(function () {
  var doc = document;
  var memory = null; // 範囲選択のために位置を保存する
  var memory2 = null; // ドロップの対象のノードの位置を保存する


  // ノードの aria-grabbed を拾い出して属性地を置き換える
  var setAriaGrabbed = function (e) {
    var s;
    switch (this.state) {
    case 2 :
      s = String (e.getAttribute ('aria-grabbed') !== 'true');
      break;
    case 1 :
      s = 'true';
      break;
    case 0 : default :
      s = 'false';
    }
    e.setAttribute ('aria-grabbed', s);
  };


  // 全ての aria-grabbed を拾い出して属性地を置き換える
  var setAllAriaGrabbed = function (state) {
    var es = doc.querySelectorAll ('*[aria-grabbed]');
    if (es)
      Array.forEach (es, setAriaGrabbed, state);
  };


  // 指定範囲の属性値の変更
  var setRangeAriaGrabbed = function (s, e) {
    var ns = doc.querySelectorAll ('*[aria-grabbed]');
    var i = 0;
    var f = 0;
    var n;
    var mf = 0;

    if (! ns.length)
      return;

    while (n = ns[i++]) {
      
      if (n == s || n == e) {
        mf = 1;
        f += 1;
      }
      
      setAriaGrabbed.call ({ state: mf }, n);
      if (2 == f)
        mf = 0;
    }
  };
  
  // ドロップされたノードからデータを抜き取り、書き込む
  var setDropData = function (n) {
    var es = doc.querySelectorAll ('*[aria-grabbed="true"]');
    var dt;
    
    if (es) {
      //alert(es.length);
      dt = Array.map (es, function (e) { return e.alt });
      n.value = dt.join (',');
    }
  
  };  
  

  var keyHandler = function (evt) {
    var n = evt./*@if (1) srcElement @else@*/ target /*@end@*/;
    var k = evt.keyCode;
    var m;
    var a;
    
    if (27 === k) { // esc
      setAllAriaGrabbed (0);
      memory = null;
    }
    else if (9 == k) {
      if (memory2) {
        memory2.setAttribute ('aria-dropeffect', 'none');
        memory2 = null;
      }

      if (n.hasAttribute ('aria-dropeffect')) {
        n.setAttribute ('aria-dropeffect', 'copy');
        memory2 = n;
      }
    }
    else if (77 === k) {
      if (n.hasAttribute ('aria-dropeffect')) {
        if (evt.ctrlKey) {
          setDropData (n);
          setAllAriaGrabbed (0);
          n.setAttribute ('aria-dropeffect', 'none');
        }
      }
    }
    else if (n.hasAttribute ('aria-grabbed')) {
      if (32 == k) { // space
        if (! memory)
          memory = n;

        if (evt.shiftKey) {
          return setRangeAriaGrabbed (memory, n); // 連続範囲選択
        }
        else if (evt.ctrlKey) {
          ; // 非連続
        }
        else if (memory) {
          setAllAriaGrabbed (0); // 一度全選択解除
        }

        setAriaGrabbed.call ({ state: 2}, n); // 選択
        memory = n;
      }
    }
  };
  
  document./*@if (1) attachEvent ('on' + @else@*/ addEventListener (/*@end@*/
    'keydown', keyHandler, false);
})();

//-->
</script>
</body>
</html>