W3Cの HTML5 Drag And Drop API の仕様書を解読中です。
まだ途中ですがメモ。
原文はこちら
http://www.w3.org/TR/2012/CR-html5-20121217/editing.html#dnd
以下翻訳。
7.7 ドラッグ&ドロップ
このセクションではイベント駆動のドラッグ&ドラッグ機構について定義する。
この仕様は具体的にドラッグアンドロップを動かす具体的な仕組みについては述べない。
ポインティングデバイスによる視覚的な伝達手段では、ドラッグ操作はデフォルトの mousedown イベント、それに続くいくつかの mousemove イベント、そしてマウスが離されることでドロップをトリガーできる。
ポインティングデバイス以外の入力方式を使うとき、ユーザは自分の意図する目的のために、何をドラッグしたいのか、どこにドロップしたいのかを明確に示さなければならないだろう。
どのような方法でも、ドラッグ&ドロップ操作には開始座標が必要(マウスがどこでクリックされたのか、ドラッグのために選択された要素の開始セクションなど)、もしかしたらいくつかの中間ステップを持つかもしれない(エレメントがドラッグ中にマウスを動かされた場合、ユーザがドロップ可能な座標にエレメントを持ってきた時など)、そして必ず終了座標も持つ(上記のエレメントからマウスボタンが離された、エレメントの選択が確定した)、またはキャンセルされる場合もある。終了座標は最後に選択されたドロップ可能要素の座標でなければならない(もし操作がキャンセルされなかったら、中間ステップで使用したエレメントでなければならない)。
7.7.1 導入
このセクションは標準的ではない。
ドラッグ可能要素を作るのは簡単:要素に draggable 属性を与える、そしてドラッグされているデータを保存する dragstart イベントリスナをセットする。
イベントハンドラは一般的に、テキストドラッグがテキスト選択ではないことをチェックする必要がある。そして DataTransfer オブジェクトにデータを保存する必要があり、許可されたエフェクトを追加する(コピー、移動、リンク、またはそれらの組み合わせ)。
例
<p>好きなフルーツはなんですか?</p>
<ol ondragstart="dragStartHandler(event)">
<li draggable="true" data-value="fruit-apple">りんご</li>
<li draggable="true" data-value="fruit-orange">みかん</li>
<li draggable="true" data-value="fruit-pear">なし</li>
</ol>
<script>
var internalDNDType = 'text/x-example'; // あなたのサイトに合わせて書き換える
function dragStartHandler(event) {
if (event.target instanceof HTMLLIElement) {
// 移動させるデータとして要素の data-value="" 属性を使う
event.dataTransfer.setData(internalDNDType, event.target.dataset.value);
event.dataTransfer.effectAllowed = 'move'; // move を許可する
} else {
event.preventDefault(); // LI要素以外はドラッグさせない
}
}
</script>
ドロップを受け入れるためには、ドロップ対象は dropzone 属性を持ち、drop イベントを監視する。
dropzone 属性の値は受け入れるデータの種類("string:text/plain"であらゆるテキストを受け入れる、または"file:image/png"でPNG画像ファイルを受け入れるなど)、フィードバックの種類(move だとデータが移動される)を指定する。
メモ:dropzone属性を使う代わりに、dragenterイベント(ドロップをアクセプトするかどうかを判断する)とdragoverイベント(ユーザに何をフィードバックするのか)を使える。
drop イベントは現在のドロップを受け入れる。このイベントはキャンセルされることが必要、dropEffect はsource が使うことができる。(またはリセットされる)
例
<p>一番好きな果物をドロップしてね</p>
<ol dropzone="move string:text/x-example" ondrop="dropHandler(event)">
<!-- "text/x-example"を自分のサイトに合わせて変えるのを忘れないように -->
<script>
var internalDNDType = 'text/x-example'; // 自分のサイトに合わせて書き換える
function dropHandler(event) {
var li = document.createElement('li');
var data = event.dataTransfer.getData(internalDNDType);
if (data == 'fruit-apple') {
li.textContent = 'りんご';
} else if (data == 'fruit-orange') {
li.textContent = 'みかん';
} else {
li.textContent = '知らない果物';
}
event.target.appendChild(li);
}
</script>
</ol>
ドラッグされた元々の要素を画面から削除するために、 dragend イベントを使う。
元々のマークアップをアップデートしてイベント処理をしている。
<p>好きな果物は?</p>
<ol ondragstart="dragStarthandler(event)" ondragend="dragEndHandler(event)">
..上のコード...
</ol>
<script>
function dragStarthandler(event) {
// …上のコード...
}
function dragEndHandler(event) {
// …上のコード…
event.target.parentNode.removeChild(event.target);
}
</script>
7.7.2 ドラッグデータの保存
ドラッグ&ドロップ操作の基礎にあるデータは、drag data storeとして知られていて、以下の情報から成り立っている。
◯drag data item listはドラッグされたデータのリストで、それぞれ以下の情報から成り立っている。
- drag data item kind:データの種類
- Plain Unicode string:テキスト
- File:ファイル名とバイナリデータ
- drag data item type string:一般的には MIME type でデータタイプかフォーマットを与える。MIME type が与えられない場合は過去の名残などの理由がある。API は MIME types を使うことを強要しない。他の値でも動く。すべてのケースにおいて、すべての値は API によって ASCII コードの変換される。
メモ:dropzone属性にスペースを含む文字列は使えない、MIME types か空白を含まない文字列を使うことが推奨される。
item type は Unicode 文字列であることが条件。
実際のデータ:drag data item kind 毎に、バイナリデータとファイルネーム(Unicode)を持つ。
drag data store item list はリストにアイテムが追加されたらソートされる。
◯ドラッグ次のUIフィードバックに以下の情報が使われる
- ユーザエージェントは デフォルトフィードバックとして、drag data store default feed back を持つ。
- オプションで、drag data store bitmap と drag data store hot spot coordinate としてビットマップ画像と座標の組を持てる
◯drag data store mode は以下のいずれかをとる。
- Read/write mode:dragstart イベント用。新しいデータは drag data store に追加できる。
- Read-only mode:drop イベント用。ドラッグデータとして表現されるアイテムリストを読める。新しいデータの追加はできない。
- Protected mode:その他のイベント用。ドラッグデータとして表現される drag data store のフォーマットと種類を数えることができるが、読み込んだり追加したりすることはできない。
◯drag data store allowed effects state という文字列。
drag data store が作られた時、上記のデータは以下のように初期化されなければならない。drag data store item list は空、drag data store default feedback は存在しない、drag data store bitmap と drag data store hot spot coordinate を持たない、drag data store mode は protected mode、drag data store allowed effects state は "uninitialized"になる。
7.7.3 DataTransfer インタフェース
DataTransfer オブジェクトはドラッグ&ドロップ操作の根底に隠れている drag data sotre を表に出すために使われる。
interface DataTransfer {
attribute DOMString dropEffect;
attribute DOMString effectAllowed;
readonly attribute DataTransferItemList items;
void setDragImage(Element image, long x, long y);
};
以下は非標準。実装についての要求。
---
dataTransfer.dropEffect
現在選択されている操作の種類を返す。もし effectAllowed で許可されていない種類だった場合は操作は失敗する。選択している操作を変更するために、この値を設定できる。可能な値は "none", "copy", "link", "move"のいずれか。
dataTransfer.effectAllowed
許可する操作の種類を返す。許可する操作を変更するためにセットすることができる(dragstartイベントの間だけ)。設定できる値は "none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", "uninitialized"のいずれか。
dataTransfer.items
ドラッグデータと一緒に DaraTransferItemList を返す。
dataTransfer.setDragImage(element, x, y)
ドラッグフィードバックをアップデートして、以前のフィードバックと置き換えるために使う。
dataTransfer.types
dragstart イベントでセットしたフォーマットのリストを返す。また、もしいくつかのファイルがドラッグされていたら、types の1つは "Files" になる。
data = dataTransfer.getData(format)
具体的なデータを返す。データなかったら空文字列を返す。
dataTransfer.setData(format, data)
具体的なデータを追加する
dataTransfer.clearData([format])
format で設定されているデータを削除する。引数がない場合はすべてのデータを削除する。
dataTransfer.files
ドラッグされている FileList があれば返す。
---
DataTransfer オブジェクトはドラッグ&ドロップイベントの間使われる。そしてドラッグ&ドロップイベントが発生している間は有効である。
DataTransfer オブジェクトは drag data store と関連している。
dropEffect 属性はユーザがドラッグ&ドロップ操作をしている間のフィードバックを制御する。DataTransferオブジェクトが作成された時、dropEffect 属性として文字列の値がセットされる。取得するとき、必ず現在の値を返さなければならない。セットするとき、新しい値が "none", "copy", "link", "move"のいずれかだったら、 dropEffect属性は新しい値に変更されなければならない。その他の値は無視されなければならない。
effectAllowed 属性は dragenter イベントと dragoverイベントの間、 dropEffect属性を初期化するためにドラッグ&ドロップ処理モデルによって使われる。DragTransferオブジェクトが作成された時、effectAllowed属性は文字列で初期化される。取得するとき、必ず現在の値を返す。セットするとき、もじ drag data sotre の mode が read/write であり、 "none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", "uninitialized" だったら新しい値に書き換える。その他だったら変更しない。
items 属性は DataTransfer オブジェクトに関連付いた DataTransferItemList オブジェクトを返さなければならない。どんな時でも同じデータを返さなければならない。
setDragImage(element, x, y) メソッドは必ず以下のステップで実行されること。
1. もし DataTransfer オブジェクトが drag data store と今後関連づかないなら、以下のステップはやらなず、何も起きない。
2. もし drag data store の mode が read/write mode だったら、以下のステップをやらず、何も起きない。
3. もし element 引数が img 要素だったら、 drag data store bitmap に要素の画像をセットする。そうじゃなければ drag data store bitmap に、与えられた要素から画像を生成してセットする。(具体的なsより方法についてはここでは述べない)
4. drag data store hot spot coordinate に、与えられた x, y をセットする。
type 属性は live read only 配列を以下のステップで返さなければならない。同じオブジェクトはいつでも必ず同じ値を返す。
1. 空の配列 L から始める
2. DataTransfer オブ絵jクトが今後 drag data store と関連づかないなら、配列は空とする。以下のステップをやらずに、空の配列 L を返す。
3. drag data store item list の各要素の kind (Unicode文字列)について、 L に追加する。
4. drag data store item list の中に kind が File のアイテムがあったら、L に "Files" を追加する。
5. これらのステップによって生成された文字列が L に入る。
getData(format) メソッドは以下のステップで実行されなければならない
1. DataTransfer オブジェクトが今後 drag data store と関連づかないなら、空文字を返して以下のステップはやらない。
2. drag data store の mode が protected だったら、空文字を返して何もしない。
3. fomart に最初の引数を小文字に変換したものを代入
4. convert-to-URL に false を代入
5. format が "text" だったら、"text/plain" に変更
6. format が "url" だったら、"text/uri-list" に変更して convert-to-URL を true にする
7. drag data store item list に kind が Unicode 文字列かつ type string が format と同じアイテムがなければ、空文字を返して以下のステップを中止する。
8. result に drag data store item list 内の kind が Unicode 文字列で type string が format と同じアイテムを代入する。
9. convert-to-URL が true だったら、text/uri-list にあった形式にパースして、result にセットする。
10. result を返す
setData(format, data) は以下のステップで実行されなければならない
1. DataTransfer オブジェクトが drag data store に関連づかないなら何もしない。
2. drag data store の model が read/write mode でなければ、何もしない。
3. format に最初の引数の format を小文字に変換して代入する
4. formart が text だったら text/plain に変更する。format が url だったら text/uri-list に変更する。
5. drag data store item list から、 kind が Unicode でtype string が format のアイテムを削除する。
6. drag data store item list に kind が Unicode で type string が format、data が第2引数に渡された文字列をセットする。
clearData() は以下のステップで実行されなければならない
1. DataTransfer オブジェクトが drag data store と以後関連づかないなら、何もしない。
2. drag data store の mode が read/write じゃなかったら、何もしない。
3. メソッドが引数なしで呼ばれたら、drag store item list 内で kind が Unicode の要素を削除して、以後のステップをやらない。
4. format に第一引数を小文字にした文字列を代入する
5. format が text だったら text/plain にする。 url だったら text/uri-list にする。
6. kind が Unicode で、type が format と同じアイテムを drag data store item list から削除する。
メモ:clearData() メソッドはドラッグにファイルが挿入されているかどうかに影響されない。clearData() が呼ばれて types 属性リストが空だったとしても影響されない。
files 属性は File オブジェクトを含む live FireList 配列を以下のステップによって表現して返す。同じオブジェクトはいつでも同じ値を返す。
1. 空の配列 L から始める
2. DataTransfer オブジェクトが drag data store と以後関連づかないなら、FileList を空にして以下のステップをやらない。空のリスト L を返す。
3. drag data store の mode が protected mode だったら、以下のステップをやらずに空のリスト L を返す。
4. drag data store item list の kind が File のアイテムに対して、L にアイテムのデータ(ファイルとファイル名)を追加する。
5. 以上のステップで見つかったのもを L とする。
メモ:このバージョンの API はドラッグ中の types を表には出さない。
7.7.3.1 DataTransferItemList インタフェース
各 DataTransfer オブジェクトは DataTransferItemList に関連づいている。
interface DataTransferItemList {
readonly attribute unsigned long length;
getter DataTransferItem (unsigned long index);
deleter void (unsigned long index);
void clear();
DataTransferItem? add(DOMString data, DOMString type);
DataTransferItem? add(File data);
}
以下は非標準。実装について。
----
items.length
drag data store の要素数を返す
items[index]
指定された位置にある DataTransferItem オブジェクトを返す
delete items[index]
指定された位置のアイテムを削除する
items.clear()
drag data store のすべてのアイテムを削除
items.add(data)
items.add(data, type)
引数として受け取ったデータを drag data store に追加する。もし data がプレーンテキストだったら type も与えられているべきである。
DataTransferItemList の DataTransfer オブジェクトは drag data store に関連づいている、DataTransferItemList オブジェクトの mode は drag data store mode と同じ。DataTransferItemList オブジェクトのDataTransfer オブジェクトがdrag data store と関連づいていないバア愛、DataTransferItemList オブジェクトの mode は disabled になる。このセクションで参照されるdrag data store は DataTransferItemList オブジェクトの DataTransfer オブジェクトと関連づいている。
length 属性は disabled のとき必ず 0 を返さなければならない。それ以外は drag data store item list の長さを返す。
DataTransferItemList が disabled モードではないとき、 0 から n - 1 までの間の値をとる。n は drag data store item list の長さ。
DataTransferItemList オブジェクトのインデックス i を決めるために、ユーザエージェントは drag data store の i 番目として表現される DataTransferItem オブジェクトを返さなければならない。DataTransferItemList オブジェクトから取得してきた要素は、同じものならどんなときでも必ず同じ値を返さなければならない。DataTransferItem オブジェクトは DataTransferItemList オブジェクトのように、初期化時に同じDataTransferオブジェクトから関連付けられる。
i としてインデックスされた DataTransferItemList のプロパティを削除するために、ユーザエージェントは以下のステップで実行しなければならない。
1. DataTransferItemList が read/write モードではなかったら、InvalidStateError 例外をスローして以下のステップを中止する。
2. drag data store の i番目のデータを削除する
DataTransferItemList が read/write モードだったら clear() メソッドは drag data store のすべての要素を削除しなければならない。それ以外は何もしてはいけない。
add() メソッドは以下の手順に従わなければならない。
1. DataTransferItemList が read/write モードではなかったら、nullを返して以下のステップを中止する。
2. 以下のリストから適切なステップにジャンプする
→ 第一引数が文字列
drag data store item list 内に kind が Unicode で type がメソッドの第二引数と同じ物があれば、NotSupportedError 例外をスローして以下のステップを中断する。
それ以外なら、drag data store item list に kind が Unicode で type がメソッドの第二引数であり、データがメソッドの第一引数の文字列であるアイテムを追加する。
→ 第一引数が File
kind が FIle で type が File のファイルタイプでデータが引数として渡された File であるアイテムを drag data store item list に追加する。
3. 新しく追加されたアイテムの index プロパティとその値(新しく作られた DataTransferItem)を返す。
7.7.3.2 DataTransferItem インタフェース
各 DataTransferItem は DataTransfer に関連している。
interface DataTransferItem {
readonly attribute DOMString kind;
readonly attribute DOMString type;
void getAsString(FunctionStringCallback? _callback);
File? getAsFile();
};
[Callback, NoInterfaceObject]
interface FunctionStringCallback {
void handleEvent(DOMString data);
}
以下は非標準
---
item.kind
drag data item kind を返す。"string" か "file"。
item.type
drag data item type を返す。
item.getAsString(callback)
drag data item kind の文字列を引数として callback を呼び出す
file = item.getAsFile()
アイテムの kind が File だったら File を返す
---
DataTansferItem と DataTransfer は drag data store と drag data store item list に関連づいていて、DataTransferItem を内部に持っている。DataTransferItem の mode はdrag data store mode と同じものである。DataTransferItem の DataTransfer が drag data store と関連づいていない、または DataTransfer が関連した drag data store item list から削除されていた場合、DataTransferItem の mode は disabled になる。このセクションで言う drag data store はDataTransferItem の DataTransfer オブジェクトに関連した drag data store である。
DataTransferItem が disable モードなら kind は空文字を返さなくてはならない。それ以外なら以下の表に合わせた値を撮らなくてはならない。
Kind | String
Plain Unicode string | "string"
File | "file"
DataTransferItem が disable なら type は空文字を返さなくてはならない。それ以外なら DataTransferItem の drag data item type string を返さなくてはならない。
getAsString(callback) は以下の手順で動かなくてはならない。
1. callback が null なら以下の手順を中止する
2. DataTransferItem が read/write モードまたは read-only mode ではなかったら以下の手順を中止して、callback は呼ばない。
3. drag data item kind が Unicode 文字列じゃなかったら以下の手順を中止して callback は呼ばない。
4. それ以外なら、callback をタスクキューに追加する。DataTransferItem として表現される実際のデータを渡して callback を呼び出す。
getAsFile() は以下のように動作しなければならない
1. DataTransferItem が read/write または read-only ではなかったら null を返して以下のステップを中止
2. drag data item kind は File ではなかったら、 null を返して以下のステップを中止
3. DataTransferItem として表現される File を返す