RHEMS技術研究室の西田です!
今回ブラウザ上にファイルまたはディレクトリをドラッグ&ドロップしてサーバにアップロードする、という機能が必要になったので、その際にハマったことや身についたナレッジなどを共有していきたいと思います!
#tl;dr.
・Webブラウザにファイルをドラッグ&ドロップする機能は簡単に実装できた
・複数のディレクトリをドラッグ&ドロップする機能は難しい。。。
・そうだ File and Directory Entry API を使おう!
#現在の進捗状況
・[単数|複数]の[ディレクトリ|ファイル]をドラッグ&ドロップで取得できた!
・あれ?中身が見れない!もしかしてバイナリ取得できてない???どうやってみるんだ。。。
・やっぱり取得できてるじゃん!やったね!
#実装
コードは以下のようになっています。
<div id="droparea">
<button class="btn btn-primary btn-block" id="cover">
ここにファイルを
<br>
ドロップしてください
</button>
</div>
<style>
#droparea {
padding: 100px 25%;
}
#cover {
width: 100%;
height: 70px;
}
</style>
async function scanFiles(entry, tmpObject) {
switch (true) {
case (entry.isDirectory) :
const entryReader = entry.createReader();
const entries = await new Promise(resolve => {
entryReader.readEntries(entries => resolve(entries));
});
await Promise.all(entries.map(entry => scanFiles(entry, tmpObject)));
break;
case (entry.isFile) :
tmpObject.push(entry);
break;
}
}
document.getElementById("droparea")
.addEventListener("dragover", event => {
event.preventDefault();
}, false);
document.getElementById("droparea")
.addEventListener("drop", async event => {
event.preventDefault();
const items = event.dataTransfer.items;
const results = [];
const promise = [];
for (const item of items) {
const entry = item.webkitGetAsEntry();
promise.push(scanFiles(entry, results));
}
await Promise.all(promise);
console.log(results); //テスト表示
/*--------------------追加コード--------------------*/
for(let result of results) {
result.file(file => {
const reader = new FileReader();
reader.readAsText(file);
reader.onload = () => {
console.log(result.fllPath);
console.log(file);
console.log(reader.result);
};
});
}
/*-----------------------------------------------*/
}, false);
追加コード部の処理がFileEntryから実体を取得し、表示するコードです。
この処理をゴニョゴニョすることで、サーバ側で同一ディレクトリ構造を復元したり、GoogleDriveのようにブラウザ上でディレクトリを扱えたり出来るようになります。
フルパスも中身も取得できてる上、複数選択しようが単数で投げようが、関係なくすべて処理してくれます。
ここに、条件を付け加えるだけで、文章のみ受け取ったり、画像だけ不可なども可能になります。
また、この機能は現在非標準ですが、GoogleChrome、Opera、FireFoxでの動作を確認しています。
Windowsマシンが届き次第、EdgeやIE(多分未対応)での動作も試してみます。