Mozilla's getting a new look. What do you think? https://mzl.la/brandsurvey

複数の項目のドラッグ&ドロップ

Mozillaはいくつかの非標準の機能によって、複数の項目のドラッグをサポートしています。それらの機能はtypesプロパティやgetDatasetDataclearDataの各メソッドに酷似していますが、データの取得や変更、削除の際などに項目のインデックスを追加の引数として要求します。

mozSetDataAtを使うと、dragstartイベントで複数の項目を登録することができます。これはsetDataメソッドとよく似た働きをします。

var dt = event.dataTransfer;
dt.mozSetDataAt("text/plain", "ドラッグされるデータ", 0);
dt.mozSetDataAt("text/plain", "ドラッグされる2つめのデータ", 1);

この例では2つのドラッグ項目を追加しています。最後の引数は追加する項目のインデックスを示しています。これらの項目は0番から順番に登録するべきで、最後の方(インデックスの大きなもの)から逆順に登録することはできません。また、すでにデータが登録されているインデックスを指定してもう1度データを登録すると、前に登録したデータを置き換えることができます。インデックスとして0を指定すると、setDataメソッドを呼んだのと等しく扱われます。

mozClearDataAtメソッドを使って、指定した項目を削除することもできます。

event.dataTransfer.mozClearDataAt("text/plain", 1);

あるインデックスで示される項目について、最後のデータ形式の削除によって項目全体を削除すると、残りの項目が繰り上がって項目のインデックスが変わることに注意してください。例えば、

var dt = event.dataTransfer;
dt.mozSetDataAt("text/uri-list", "URL1", 0);
dt.mozSetDataAt("text/plain",    "URL1", 0);
dt.mozSetDataAt("text/uri-list", "URL2", 1);
dt.mozSetDataAt("text/plain",    "URL2", 1);
dt.mozSetDataAt("text/uri-list", "URL3", 2);
dt.mozSetDataAt("text/plain",    "URL3", 2);
// [item1] data=URL1, index=0
// [item2] data=URL2, index=1
// [item3] data=URL3, index=2

このように2つの形式で提供されたデータを持つ3つの項目を登録した後で、

dt.mozClearDataAt("text/uri-list", 1);
dt.mozClearDataAt("text/plain", 1);

このように2番目の項目についてすべての形式のデータを削除すると、3番目だった項目が繰り上がって2番目の項目になり、インデックスが2から1に変わります。

// [item1] data=URL1, index=0
// [item2] data=URL3, index=1

幸いなことに、通常は項目を削除する必要がある場合は希で、それよりも、必要に応じて項目を追加するだけの場合の方がずっと多いです。

複数の項目のドラッグが使われる場合の代表は、複数のファイルやブックマークをドラッグする時です。この場合には、適切な形式でそれらの項目を追加してください。また必須ではありませんが、それぞれの項目は常に同じ形式でデータを追加するべきです。これによりドロップ対象は、一貫したデータの受け取りを期待できます。

複数のファイルがドラッグされているかどうかを確認するには、mozItemCountプロパティを調べます。このプロパティにはドラッグされている項目の数がセットされます。もしそのドロップ対象が1つの項目のドロップだけを受け付ける場合には、ドラッグされた項目すべてを拒否することもできますし、最初の項目だけを受け取ることもできます。複数の項目の受け取りを拒否するには、dragoverイベントをキャンセルしないか、effectAllowedプロパティにnoneを指定します。他のイベントリスナがすでにイベントをキャンセルしている場合に備えて、両方を実行しても構いません。

ドロップされた項目のうち最初の項目だけを扱う場合は、1つだけの項目のドラッグの場合と同様にgetDataを使います。これは、何も追加の処理が必要ないドロップ項目を1つだけ受け取るドロップ対象のために有用です。

それに対して、任意のインデックスの項目をデータトランスファーから取得するにはmozGetDataAtメソッドを使います。以下の例は、ドラッグされたファイルを取得し、それらを配列に追加するものです。

function onDrop(event)
{
  var files = [];
  var dt = event.dataTransfer;
  for (var i = 0; i < dt.mozItemCount; i++)
    files.push(dt.mozGetDataAt("application/x-moz-file", i));
}

mozTypesAtメソッドを使って、望んでいる形式のデータが存在しているかどうかを確かめたいとも思うでしょう。typesプロパティと同様に、このメソッドは、その項目が保持しているデータの型の文字列を返します。typesプロパティを取得する事は、インデックスが0の項目の型のリストを取得する事に等しいです。

var types = event.dataTransfer.mozTypesAt(1);

文字列でないデータのドラッグ

上で解説した追加のメソッドが扱えるデータは文字列に限定されず、どんな種類のデータでも指定することができます。例えば、ファイルはapplication/x-moz-file型でnsIFileのオブジェクトとして保持されてドラッグされます。setDataメソッドは文字列しかサポートしておらず、 ドラッグするファイルを指定するのには利用できないため、代わりにmozSetDataAtメソッドを使わなくてはなりません。

dt.mozSetDataAt("application/x-moz-file", file, 0);

複数の項目を扱う必要がない場合でも、このメソッドを使うことによって任意のオブジェクトをデータに指定できます。この場合には、インデックスとして0を指定しておきます。

同様に、ファイルやその他のオブジェクトを取得するにはmozGetDataAtメソッドを使う必要があります。もしgetDataを使った場合は、値が文字列でない型のデータは空文字として取得されます。ただし、数値のような単純な型のデータについては文字列に変換できるため、この場合はgetDataを使っても問題ありません。

複数項目のドロップの例

以下は、ドロップされた項目のデータとその形式を一覧表示するボックスの例です。

<html>
<head>
<script>

function dodrop(event)
{
  var dt = event.dataTransfer;
  var count = dt.mozItemCount;
  output("Items: " + count + "\n");

  for (var i = 0; i < count; i++) {
    output(" Item " + i + ":\n");
    var types = dt.mozTypesAt(i);
    for (var t = 0; t < types.length; t++) {
      output("  " + types[t] + ": ");
      try {
        var data = dt.mozGetDataAt(types[t], i);
        output("(" + (typeof data) + ") : <" + data + " >\n");
      } catch (ex) {
        output("<<error>>\n");
        dump(ex);
      }
    }
  }
}

function output(text)
{
  document.getElementById("output").textContent += text;
  dump(text);
}

</script>
</head>
<body>

<div id="output" style="min-height: 100px; white-space: pre; border: 1px solid black;"
     ondragenter="document.getElementById('output').textContent = ''; event.stopPropagation(); event.preventDefault();"
     ondragover="event.stopPropagation(); event.preventDefault();"
     ondrop="event.stopPropagation(); event.preventDefault(); dodrop(event);">
<div>

</body>
</html>

この例は、preventDefaultメソッドによってdragenterイベントとdragoverイベントを両方ともキャンセルします。これにより、要素の上でのドロップが可能になっています。

項目をドロップした時に、dodrop関数が呼ばれます。この関数はmozItemCountプロパティを見て、いくつの項目がドロップされたのかを調べ、それらに繰り返し処理を行います。それぞれの項目について、型の一覧を得るためにmozTypesAtメソッドが呼ばれます。この一覧の生成処理は、ドラッグに対して関連づけられたすべてのデータに対して繰り返されます。

この例は、あるドラッグ操作が保持しているデータを確かめたい時に便利です。ただ項目をこの例のドロップ対象にドロップするだけで、ドラッグされたどの項目がどんな形式でどのようなデータを保持しているのかを見ることができます。

ドキュメントのタグと貢献者

 このページの貢献者: Piro, drry
 最終更新者: Piro,