ブラウザにドラッグ&ドロップ
ちょっと前にはてブしたんだが。
Google Waveが発表されて、そのデモの中でブラウザにファイルをドラッグ&ドロップしてたとか。
そのやり方を解説してる方がいたので、そのままやってみた。
確かにできた。スゴイ!
で、javascriptでできるんだからFlashでもできるよね、と安直な発想でやってみた。
DnDSample.mxml
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="center" verticalAlign="middle" creationComplete="logic.onCreationCompleteHandler(event)" backgroundColor="0xffffff" backgroundGradientAlphas="[0,0]" xmlns:local="*"> <local:DnDSampleLogic id="logic"/> <mx:Label id="lbl" text="" fontSize="48" /> </mx:Application>
まぁ、メイン部分はたいしたことやってない。
アプリケーションのメインロジック。GearsのjavascriptとFlexを繋げてる。
DnDSampleLogic.as
package { import flash.events.MouseEvent; import flash.external.ExternalInterface; import flash.net.URLRequest; import flash.net.navigateToURL; import mx.core.IMXMLObject; import mx.events.FlexEvent; import utils.JSUtil; public class DnDSampleLogic implements IMXMLObject { protected var view:DnDSample; public function DnDSampleLogic() { } public function initialized(document:Object, id:String):void { view = document as DnDSample; } public function onCreationCompleteHandler(event:FlexEvent):void { // gears_init.jsの内容をそのまま書き込む(こういう使い方して問題ないのか?) JSUtil.writeJSFunction( "gears_init" ,[] , "if (window.google && google.gears) {" + "return;" + "}" + "var factory = null;" + "/* Firefox */" + "if (typeof GearsFactory != 'undefined') {" + "factory = new GearsFactory();" + "} else {" + "/* IE */" + "try {" + "factory = new ActiveXObject('Gears.Factory');" + "/* privateSetGlobalObject is only required and supported on IE Mobile on */" + "/* WinCE. */" + "if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {" + "factory.privateSetGlobalObject(this);" + "}" + "} catch (e) {" + "/* Safari */" + "if ((typeof navigator.mimeTypes != 'undefined')" + "&& navigator.mimeTypes['application/x-googlegears']) {" + "factory = document.createElement('object');" + "factory.style.display = 'none';" + "factory.width = 0;" + "factory.height = 0;" + "factory.type = 'application/x-googlegears';" + "document.documentElement.appendChild(factory);" + "}" + "}" + "}" + "if (!factory) {" + "return false;" + "}" + "if (!window.google) {" + "google = {};" + "}" + "if (!google.gears) {" + "google.gears = {factory: factory};" + "}" + "return true;" ); // 書き込んだgears_init.jsをおもむろに実行 ExternalInterface.call("gears_init"); // ドロップ時に呼ばれるコールバック関数を登録 ExternalInterface.addCallback( "sendData", function(obj:Object):void{ // コールバック関数 trace(obj); } ); // 以下、リンク先のサンプルのjavascriptを書き込む JSUtil.writeJSFunction( "addEvent" , ["element", "name", "handler"] , "if(platform != 'IE') {" + "element.addEventListener(" + "platform != 'Firefox' ? name : eventMap[name]," + "handler," + "false" + ");" + "} else {" + "element.attachEvent('on' + name, handler);" + "}" ); JSUtil.writeJSFunction( "escapeHtml" , ["s"] , "return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');" ); JSUtil.writeJSFunction( "handleEnterOver" , ["event"] , "event.returnValue = false;" + "desktop.setDragCursor(event, 'copy');" ); JSUtil.writeJSFunction( "handleLeave" , ["event"] , "event.returnValue = false;" + "desktop.setDragCursor(event, 'none');" ); JSUtil.writeJSFunction( "handleDrop" , ["event"] , "event.stopPropagation && event.stopPropagation();" + "targetSWF.sendData(desktop.getDragData(event, 'application/x-gears-files'));" ); JSUtil.writeJSFunction( "dnd_init" , [] , "desktop = null;" + "action = ['install', 'インストール'];" + "platform = null;" + "targetSWF = null;" + "var initialized = false;" + "try {" + "if(!window.google || !window.google.gears) throw null;" + "action = ['upgrade', '更新'];" + "desktop = google.gears.factory.create('beta.desktop');" + "var buildInfo = google.gears.factory.getBuildInfo();" + "platform = buildInfo.indexOf(';ie') > -1 ? 'IE' : platform;" + "platform = buildInfo.indexOf(';firefox') > -1 ? 'Firefox' : platform;" + "platform = buildInfo.indexOf(';safari') > -1 ? 'Safari' : platform;" + "platform = buildInfo.indexOf(';npapi') > -1 ? 'Npapi' : platform;" + "eventMap = {" + "'dragenter' : 'dragenter'," + "'dragover' : 'dragover'," + "'dragleave' : 'dragexit'," + "'drop' : 'dragdrop'" + "};" + "targetSWF = document.getElementById('" + ExternalInterface.objectID + "');" + "addEvent(targetSWF, 'dragenter', handleEnterOver);" + "addEvent(targetSWF, 'dragover', handleEnterOver);" + "addEvent(targetSWF, 'dragleave', handleLeave);" + "addEvent(targetSWF, 'drop', handleDrop);" + "initialized = true;" + "} catch(e) {" + "}" + "return initialized;" ); if(!ExternalInterface.call("dnd_init")) { view.lbl.htmlText = "<a href='http://gears.google.com/?action=install'>Gearsをインストールしてください</a>"; view.lbl.addEventListener( MouseEvent.CLICK, function(event:MouseEvent):void { navigateToURL(new URLRequest("http://gears.google.com/?action=install"), "_blank"); } ); } else { view.lbl.htmlText = "ここにドラッグ&ドロップしてください"; } } } }
上で使ってるFlexからjavascriptを書き込むユーティリティクラス。
JSUtil.as
package utils { import flash.external.ExternalInterface; public class JSUtil { public function JSUtil() { } public static function writeJS( js:String // javascriptコード ):Boolean { if (ExternalInterface.available == false) return false; try { ExternalInterface.call( "document.insertScript = " + js ); } catch(e:Error) { return false; } return true; } public static function writeJSFunction( functionName:String, // 関数名 functionArgments:Array, // 引数の配列 functionContent:String // 関数本体 ):Boolean { if (ExternalInterface.available == false) return false; try { var argName:Object; var argSep:String = ", "; var insertJS:String = "function () {" + "if(document. " + functionName + " == null) {" + functionName + " = function ("; if (functionArgments != null && functionArgments.length > 0) { for each(argName in functionArgments) { insertJS += argName.toString() + argSep; } insertJS = insertJS.substring(0, insertJS.lastIndexOf(argSep)); } insertJS += ") {" + functionContent + "}" + "}" + "}"; JSUtil.writeJS(insertJS); } catch(e:Error) { return false; } return true; } } }
これで、デスクトップ(エクスプローラ)からドラッグされたファイルを、
Flex側で受け取ることができるようになる。
何かGears使ってjavascript使って、と回りくどいやり方。
Flashが最初からサポートしてくれるといいのに。