DataTransferItem.webkitGetAsEntry()

DataTransferItem で記述された項目がファイルの場合、 webkitGetAsEntry() はそれを表す FileSystemFileEntry または FileSystemDirectoryEntry を返します。ファイルでない場合は null を返します。

メモ: この関数は、現時点では Firefox を含む非 WebKit ブラウザーでは webkitGetAsEntry() として実装されています。将来的には getAsEntry() に改名される可能性があるので、両方の関数を探して防御的なコードを記述すべきです。

構文

js
webkitGetAsEntry()

引数

なし。

返値

ドロップされたアイテムを記述する FileSystemEntry (en-US) ベースのオブジェクトです。 これは FileSystemFileEntryFileSystemDirectoryEntry のどちらかになります。 ドロップされたアイテムがファイルでない場合、あるいは DataTransferItem オブジェクトが読み込みモードまたは読み書きモードでない場合、このメソッドは中断して null を返します。

この例では、ドロップゾーンが作成されており、 drop イベントに応答して、ドロップされたファイルとディレクトリーをスキャンし、階層的なディレクトリーリストを出力しています。

HTML コンテンツ

HTMLは、ドロップゾーンそのものを、ID "dropzone" を持つ <div> 要素と、ID "listing" を持つ非順序リスト要素で確立しています。

html
<p>Drag files and/or directories to the box below!</p>

<div id="dropzone">
  <div id="boxtitle">Drop Files Here</div>
</div>

<h2>Directory tree:</h2>

<ul id="listing"></ul>

CSS コンテンツ

例で使用されるスタイル設定を示します。

css
#dropzone {
  text-align: center;
  width: 300px;
  height: 100px;
  margin: 10px;
  padding: 10px;
  border: 4px dashed red;
  border-radius: 10px;
}

#boxtitle {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
  color: black;
  font:
    bold 2em "Arial",
    sans-serif;
  width: 300px;
  height: 100px;
}

body {
  font:
    14px "Arial",
    sans-serif;
}

JavaScript コンテンツ

最初に、再帰的な関数である scanFiles() を見ていきましょう。 この関数は、スキャンして処理するファイルシステムの項目を表す FileSystemEntry (en-US) を入力として受け取り(item 引数)、その内容のリストを格納する要素(container 引数)を受け取ります。

メモ: ディレクトリー内のすべてのファイルを読み込むには、空の配列を返すまで readEntries を繰り返し呼び出す必要があります。 Chromium ベースのブラウザーでは、以下の例では最大 100 件までしか返しません。

js
let dropzone = document.getElementById("dropzone");
let listing = document.getElementById("listing");

function scanFiles(item, container) {
  let elem = document.createElement("li");
  elem.textContent = item.name;
  container.appendChild(elem);

  if (item.isDirectory) {
    let directoryReader = item.createReader();
    let directoryContainer = document.createElement("ul");
    container.appendChild(directoryContainer);
    directoryReader.readEntries((entries) => {
      entries.forEach((entry) => {
        scanFiles(entry, directoryContainer);
      });
    });
  }
}

scanFiles() はまず、スキャンする項目を表す新しい <li> 要素を作成し、項目の名前をテキストコンテンツとしてそこに挿入し、それをコンテナーに追加しています。 コンテナーは、この例では常にリスト要素です。

現在の項目がリストに掲載されると、その項目の isDirectory (en-US) プロパティが調べられます。 アイテムがディレクトリーの場合、そのディレクトリーに再帰的に移動する必要があります。 最初の手順は、ディレクトリーのコンテンツのフェッチを処理する FileSystemDirectoryReader (en-US) を作成することです。 これは、項目の createReader() (en-US) メソッドを呼び出すことによって行われます。 次に、新しい <ul> が作成され、親リストに追加されます。このリストには、リストの階層で次のレベルに位置するディレクトリーのコンテンツが格納されます。

その後、directoryReader.readEntries() (en-US) が呼び出されて、ディレクトリー内のすべての項目が読み込まれます。 これらは順番に scanFiles() の再帰的な呼び出しに渡され、処理されます。 ファイルであるものはリストに掲載され、ディレクトリーであるものはリストに掲載され、リストの階層の新しいレベルが下記の一覧に追加され、といった具合になります。

次に、イベントハンドラーが決まります。まず、dragover イベントが既定のハンドラーで処理されないようにして、ドロップゾーンがドロップを受け取れるようにします。

js
dropzone.addEventListener(
  "dragover",
  (event) => {
    event.preventDefault();
  },
  false,
);

このコースのイベントハンドラーは、もちろん drop イベントに対するハンドラーであり、すべてを開始させます。

js
dropzone.addEventListener(
  "drop",
  (event) => {
    let items = event.dataTransfer.items;

    event.preventDefault();
    listing.textContent = "";

    for (let i = 0; i < items.length; i++) {
      let item = items[i].webkitGetAsEntry();

      if (item) {
        scanFiles(item, listing);
      }
    }
  },
  false,
);

これは、ドロップされたアイテムを表す DataTransferItem オブジェクトのリストを event.dataTransfer.items から取得します。 そして、 Event.preventDefault() を呼び出して、イベントが終了した後にそれ以上処理されないようにします。

これで、いよいよリストの構築が始めます。最初に listing.textContent を空にして、リストを空っぽにします。 これにより、ディレクトリー項目の挿入を始めるための空の <ul> が残ります。

次に、削除された項目のリストにある項目を反復処理します。 それぞれについて、webkitGetAsEntry() メソッドを呼び出して、ファイルを表す FileSystemEntry (en-US) を取得します。 これが成功したら、 scanFiles() を呼び出して項目を処理します。ファイルであればリストに追加し、ディレクトリーであれば追加してその中に入っていきます。

結果

これらがどのように動作するかは、下記で試してみてください。いくつかのファイルとディレクトリーを探し、それらをドラッグして、出力結果を確認してください。

仕様書

この API には W3C または WHATWG の公式な定義がありません。

ブラウザーの互換性

BCD tables only load in the browser

関連情報