gmailでメールを書くとき、添付するファイルを選んでからしばらくすると、いつの間にか添付ファイルがアップロードされています。
添付するファイルを選ぶと、はじめファイル名が表示されていたのが
実は、あまり名前も聞かなくなった Google Page Creator がリリースされたときにいちばんびっくりしたのはページの右下にこのgmailの自動アップロードとよく似たしくみがあったことでした。で、さっそく解析してマネしてみたことがあります。今回はgmailでその仕組みを見てみます。
ちなみにその Google Page Creator には、ログインすると右下にこんな
changeイベントを監視して、変化があったときにself.form.submit() で自分自身が属するformをsubmitしています。
このときformタグの属性にtargetが設定されているのがミソです。gmailの場合formタグは
<form id="compose_form" class="cf cn" onsubmit="return false"
enctype="multipart/form-data" method="post" target="hst" accept-charset="utf-8" action="">
になっています。targetに設定されているhstはiframeになっていました。ただ、インラインのスタイルシートで left: -10000px; が設定されているので画面には表示されないようになっています。余談ですが、自分でこれと同じ仕組みをマネして作るときは、動くようになるまで画面の中にirameを表示されるようにしてエラーを見たりできる状態にしておいて、完成したときに画面の外に飛ばすスタイルをつけるとデバッグが楽になります。
<iframe id="hst" scrolling="auto" frameborder="0"
onload="try{if(top.js.init)top.js._IF_OnLoaded('hst')}catch(e){}"
style="width: 100%; height: 100%; position: absolute; top: 0pt; left: -10000px;"
src="https://mail.google.com/mail/?view=page&name=hist1" name="hst">
スクリプトによってiframeをターゲットにしてsubmitされると、iframeの中のコンテンツが書き変わります。
iframeに表示されるコンテンツはjavascriptを実行するためのHTMLです。(一部セッションキーっぽいところは書き換えてあります)
<html><head><meta content="text/html; charset=UTF-8" http-equiv="content-type"></head>
<script>D=(top.js&&top.js.init)?function(d){top.js.P(window,d)}:function(){};
if(window==top){top.location="/mail/?ik\u003d02ad21601d&cmid\u003d1&newatt\u003d1&rematt\u003d0&autosave\u003d1&fs\u003d1";}
</script>
<script><!--
D(["v","lynnnnnnnn5r","66eeeeeeeeee2","37","1","1x4nxxxxxxxxxxxx"]
);
D(["ds",[["inbox",0]
,["drafts",122]
,["spam",6490]
]
]
);
D(["sr","1",1,"Your message has been saved.","112c3167d00000000",1,[["0.1","kbd.jpg","image/jpeg",828,-1,"f_f0000000"]
]
,"9:46 pm",0,0,1,"23",,0,[]
,[]
]
);
D(["ds",[["inbox",0]
,["drafts",122]
,["spam",6490]
]
]
);
//--></script>
<script>var loaded=true;D(['e',5,1180097217948]);</script>
ここから先は読んでいませんが、おそらくDという名前の関数がgmailの本体側で定義されていて、その関数の中で表示を書き換えているのでしょう。
やっていることは XMLHttpRequest + JSONP とおなじで、ただファイルをアップロードするときにtargetを設定しなければページ遷移が起きてしまうので、ブラウザ上で見えない位置に配置したiframeをtargetにしてsubmitしているわけです。

changeイベントをハンドルして自動的にデータをサーバに送って同期を取るのは一般的ですが、プロフィールの画像だけは最後にsubmitを押さないと反映されない、みたいなインターフェイスにするしかありませんでした。
が、この方法を使えば <input type="file" /> で画像ファイルを選択した瞬間にアップロード、サムネイルを生成してユーザのプロフィール画像を即反映させる、というUIを作ることができます。
ファイルのアップロードだけボタンを押さないといけないのがインターフェイスとして美しくないと感じていたならば、この方法でAjaxっぽいUIを実現してみてはいかがでしょう。
トラックバック元エントリにこのエントリへのリンクがない場合はトラックバックを受け付けません。
http://labs.gmo.jp/mt/mt-tb.cgi/127
comments
!ぽおおおおおお!