Closure Library でローカルファイルのドラッグ&ドロップを実装する
最近、 Closure Library が凄い勢いで更新されています。どうやら Google 社内で使用している開発リポジトリと Google Code の公開リポジトリの同期が簡単にできるような仕組みを用意したらしく、かなり小刻みにコミットが行われています。
もっとも、その多くはバグフィクス系なのですが、ときどき非常に面白い機能も追加されます。その一例が、本日ご紹介する FileDropHandler 、 HTML5 の機能を利用して、ローカルファイルを Web アプリケーションにドラッグ&ドロップできるようにするクラスです。
最近のブラウザがローカルファイルのドラッグ&ドロップをサポートしていることは、 Gmail がその機能を利用していることからご存じの方も多いでしょう。これは HTML5 のドラッグ&ドロップと File API の組み合わせで実現されており、現時点で Google Chrome, Safari, Firefox がサポートしています。これまでとても面倒だった複数ファイルのアップロードが簡単になり、 Web アプリケーションの使い勝手を劇的に改善してくれます。
Closure Library の FileDropHandler を利用すると、このようなローカルファイルのドラッグ&ドロップを簡単に実装できます。以下で FileDropHandler の使い方を解説しますので、皆さんのアプリケーションにもぜひ組み込んでみてください。
ファイルのドラッグ&ドロップを実装する
簡単なサンプルを作ってみましたので、ファイルのドラッグ&ドロップをサポートしたブラウザ(現時点では Google Chrome, Safari, Firefox のいずれか)で試してみてください。灰色の部分に適当なファイルをドラッグ&ドロップすると、そのファイル名を表示します。複数のファイルをドロップすることも可能です。
ソースコードは以下のような感じです。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ファイルのドラッグ&ドロップのテスト</title>
</head>
<body style="margin:0; padding:0;">
<div id="droptarget"
style="width:100%; height:200px; background-color:#eee;">
ここにドラッグしてください。
</div>
<div id="filenames"></div>
<!-- Closure Libraryのbase.jsの読み込み -->
<script src="closure-library/closure/goog/base.js"></script>
<script>
goog.require('goog.array');
goog.require('goog.string');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.FileDropHandler');
</script>
<script>
var handler = new goog.events.FileDropHandler(
goog.dom.getElement('droptarget'), true);
goog.events.listen(
handler, goog.events.FileDropHandler.EventType.DROP,
function(e) {
var files = e.getBrowserEvent().dataTransfer.files;
var names = goog.array.map(files, function(file) {
return goog.string.htmlEscape(file.name);
});
goog.dom.getElement('filenames').innerHTML = names.join('<br>');
});
</script>
</body>
</html>
ソースコードだけでだいたいわかるかもしれませんが、一応説明しておきます。まず Closure Library のしきたりとして最初に必要なファイルを goog.require() で読み込みます。ドラッグ&ドロップに必要なのは goog.events.FileDropHandler で、ほかは単なるユーティリティです。
goog.require('goog.array');
goog.require('goog.string');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.FileDropHandler');
ドラッグ&ドロップを処理するためには、ファイルを受け付ける要素を指定して FileDropHandler のインスタンスを作成します。ここでは id="droptarget" の DIV 要素を指定しています。第二引数は指定した要素以外の場所でのファイルドロップを禁止するかどうかの指定です。 true を指定すれば、間違って別の場所にドロップしてしまい、そのファイルがブラウザに読み込まれてしまうという間違いを防止できます。
var handler = new goog.events.FileDropHandler(
goog.dom.getElement('droptarget'), true);
指定した要素にファイルがドロップされると FileDropHandler インスタンスがイベントを発行するので、それを listen します。 e.getBrowserEvent().dataTransfer.files でドロップされたファイルの情報を格納した FileList オブジェクトが取得できるので、それを使って望みの処理を行うことができます。
goog.events.listen(
handler, goog.events.FileDropHandler.EventType.DROP,
function(e) {
var files = e.getBrowserEvent().dataTransfer.files;
var names = goog.array.map(files, function(file) {
return goog.string.htmlEscape(file.name);
});
goog.dom.getElement('filenames').innerHTML = names.join('<br>');
});
これだけでファイルのドラッグ&ドロップが処理できます。素晴らしく簡単ですね! :)
上記のサンプルでは単にファイル名を表示しているだけですが、もちろんファイル内容を読み込んで各種処理を行うことも可能です。 Netforest Developer's Note さんの記事がとてもわかりやすく、参考になると思います。ほんとうはファイルの読み込み関連も便利クラスでラップしてくれると嬉しいんですけどね。
別ページからの画像・リンクのドラッグ&ドロップ
ファイルのドラッグ&ドロップについては以上ですが、ドラッグ&ドロップ関連でもうひとつ面白いクラスがあるので、ついでに試してみました。他のページにある画像やリンクのドラッグ&ドロップを受け付けるための goog.ui.DragDropDetector です。ローカルファイルの取得に比べると便利さはイマイチですが、 Firefox, Google Chrome, Safari に加えて、なんと IE でも動作します(IE8 で確認しましたが、ソースを見る限り IE6, 7 でも動きそうです)。
こちらもサンプルを作ってみたので、試してみてください。ブラウザの新規ウインドウを作成して適当なページを開き、そこにある画像やリンクを以下の黒枠内にドラッグ&ドロップすると、その URL が表示されるはずです。
ソースコードは以下です。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DragDropDetectorのテスト</title>
<link rel="stylesheet" href="closure-library/closure/goog/css/dragdropdetector.css">
<style>
html, body {
width:100%; height: 100%; margin: 0; padding: 0;
}
</style>
</head>
<body>
<div>ここに他のページの画像やリンクをドラッグ&ドロップしてください。</div>
<div id="urls"></div>
<!-- Closure Libraryのbase.jsの読み込み -->
<script src="closure-library/closure/goog/base.js"></script>
<script type="text/javascript">
goog.require('goog.array');
goog.require('goog.string');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.ui.DragDropDetector');
</script>
<script type="text/javascript">
var detector = new goog.ui.DragDropDetector('dragdropdetector_target.html');
var events = [goog.ui.DragDropDetector.EventType.IMAGE_DROPPED,
goog.ui.DragDropDetector.EventType.LINK_DROPPED];
goog.events.listen(detector, events, function(e) {
goog.dom.getElement('urls').innerHTML = goog.string.htmlEscape(e.getUrl());
});
</script>
</body>
</html>
DragDropDetector を使用するには、ひとつ準備が必要です。 Closure Library に含まれている closure/goog/demos/dragdropdector_target.html というファイルを、 DragDropDetector を使用する HTML ページと同じドメインの任意の場所にコピーしておきます。どうやら、このファイルを IFRAME で表示して designMode で編集状態にすることで、ドロップされた画像・リンクの情報を取得しているようです。
準備ができたら、まずは必要な CSS ファイルを読み込みます。これは Closure Library の配布物に含まれています。
<link rel="stylesheet" href="closure-library/closure/goog/css/dragdropdetector.css">
そして、 goog.require() で必要なスクリプトを読み込みます。やはり DragDropDetector 以外は単なるユーティリティです。
goog.require('goog.array');
goog.require('goog.string');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.ui.DragDropDetector');
DragDropDetector のインスタンスを作成します。引数は先程コピーした dragdropdetector_target.html の URL です。
var detector = new goog.ui.DragDropDetector('dragdropdetector_target.html');
あとは、画像やリンクがドロップされた際に発行されるイベントを listen して、適切な処理を行えば OK です。このときのイベントオブジェクトは ImageDropEvent もしくは LinkDropEvent になり、 getUrl() でドロップされた画像・リンクの URL が取得できます。
var events = [goog.ui.DragDropDetector.EventType.IMAGE_DROPPED,
goog.ui.DragDropDetector.EventType.LINK_DROPPED];
goog.events.listen(detector, events, function(e) {
goog.dom.getElement('urls').innerHTML = goog.string.htmlEscape(e.getUrl());
});
以上で他のページからの画像・リンクのドラッグ&ドロップを受け付けることができます。こちらも簡単ですね。
なかなか使いどころが難しい機能ですが、例えば別ウインドウで画像検索サイトの検索結果を表示して、そこから画像をドラッグ&ドロップで張り付けられるようにする、なんてのは面白いのではないでしょうか。
本日は Closure Library のドラッグ&ドロップ機能をご紹介しました。最近の Google は Gmail などで HTML5 の機能を積極的に取り入れだしているので、その成果が順次 Closure Library にも反映されていくのでしょうね。また面白そうな機能を見つけたらご紹介しますので、今後ともよろしくお願いします!
詳しくはこちらの記事をどうぞ!

この記事にコメントする