ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

PukiWikiの添付ファイル使用時、ローカルファイルをドラッグ&ドロップしたい(残念賞版)

突然ですが、WikiWikiって便利ですよね。
自分は、個人的なメモは PukiWikiにメモっています。今だったら、Google DocumentとかにEvernoteにメモるというのもアリなんでしょうけど、貧弱なマシンには ちとリッチ過ぎるし、アクセス管理も自分で管理できるので、よく使っています。


で、よく使うPukiWikiなんですが、時折「うぎゃ〜」と叫ぶ事があります。
それは、添付ファイルのパス指定の時なんです。
…何で、アップロードするファイルを、ファイル入力欄にドラッグ&ドロップさせてくれないの?
1
1 posted by (C)wacky


セキュリティとか言われたら、まぁ納得するしか無いんですが、Googleのウェブアルバムでは、ドロップエリアにファイルをドラッグ&ドロップして、アップロード出来るんですね。
2
2 posted by (C)wacky


そうだよ。これがやりたいんだよ!
一々ファイルダイアログを開いて、アップロードするファイルをヘコヘコ選択していくなんて、前時代的な真似は やりたくないんだよ。
ついでに言うと、今使っているブラウザで、それがやりたいんだよ。
HTML5なら〜とか、足切りは勘弁してちょーだい。
という訳で、どうやれば出来るか、奮闘してみました。

情報収集

余談ですが、このファイル入力欄へのドラッグ&ドロップですが、Chromeだとデフォルトで出来ちゃいます。
なので、今回のネタはIEオンリーです。(FireFoxも、最新版だと出来るみたいだし〜)


まずは、Googleのウェブアルバムですが、ソースを眺めてみると、どうやらドロップエリアは、ActiveXコントロールっぽいです。


他に方法が無いのか?と言うと、↓このWeb siteでの検証では、ActiveXFTPクリップボードぐらいしか無い模様。


FTPの代わりに、WebDAVを使う自作プラグインが、PukiWikiのオフィシャルサイトにあります。


他には、オフィシャルサイトに、複数ファイルをアーカイブしたファイルをアップロードする事で、サーバー先で展開して格納してくれる。という自作プラグインもあるようです。これは、考え方の勝利という奴ですね。

方針決定

先のオフィシャルサイトの自作プラグインを検討したのですが、やっぱり「ドラッグ&ドロップしたい」んじゃぁ。という事で、ActiveXを貼り付けて、そこからパスをゲットする方法を検討します。


暫くググると、そのものズバリなものが見つかりました。

コードのキモは、objectタグでActiveXコントロールを貼り付ける際、OleDropMode プロパティを有効に設定する事と、OLEDragDropイベントでキャッチしたら、パス情報を取得する所みたいです。

<object id="IAnimation" 
classid="clsid:B09DE715-87C1-11D1-8BE3-0000F8754DA1">
<param name="OleDropMode" value="1">
</object>

<script type="text/JScript">

function IAnimation::OLEDragDrop(Data){
if(Data.GetFormat(15)){
var O = "";
var e = new Enumerator(Data.Files);
while(!e.atEnd()){
O += e.item() + "\n";
e.moveNext();
}
output.value = O;
BackColor=0x80000003;}
}

↑上で使っているActiveXはAnimationコントロールのようです。が、調べていくと、最近のWindowsのパッチで、このコントロールがWeb上で使えないよう Kill Bit指定されているようです。


他に、OleDropModeできるようなActiveXが無いものか?と調べていくと、某掲示板でグッドな情報が記載されています。うまうま。

833 :デフォルトの名無しさん:2008/05/29(木) 23:01:44 
ああスマン 
Clipboard.HTAってウィンドウにD&Dしたファイルをクリップボードにコピーするスクリプトなんだけど 
その「D&Dしたファイルを拾う方法」以外に無いの? って事 

Clipboard.HTAから最低限必要な部分だけを切り取ると 
<object id="dd_1c" classid="CLSID:8E3867A3-8586-11D1-B16A-00C0F0283628" > 
<PARAM NAME="OLEDropMode" VALUE="1"><PARAM NAME="Style" VALUE="1"><PARAM NAME="Simpletext" VALUE="ここにD&D"> 
</object> 
function dd_1c::OLEDragDrop(Data,e){ 
//Data.Files.;DDしたファイルの数 
//Data.Files.Item(n);n=1〜でDDしたファイルのフルパス 
if(e==7){ 
//こっちはファイルです 
}else{ 
//こっちはファイル以外の何か 
} 
} 
で、objectにファイルをD&DするとData.Files.Item(n)にD&Dしたファイルのパスが取得出来るんだけど 
この方法、「オブジェクトにD&Dしたファイルを拾う」事しか出来ないから、 
「このテキストボックスにファイルをD&Dしたら…」って事は出来ないんだよ 
だから他の方法無いかなって 


上の情報を組み合わせてみると、ローカルファイルを、IEにドラッグ&ドロップしてファイルパスを得られる事が判りました。

越えられない壁

ファイルパスを得られたら、INPUTタグのファイル入力欄に、スクリプトで書き込めば完了だ。と思ったのですよ。
が、そうは問屋が卸さないようで、TYPE='FILE'指定のかかったものは、スクリプトで設定出来ない模様。
確かに、直接ファイル入力欄にキー入力しようとしても、入力すらさせてくれない…。


調べていくと、昔はクリップボード経由でINPUTタグに入れる事も出来たようですが、現在は それも適わない模様。
セキュリティ厳しいなぁ。…まぁ、当然か。


TYPE='TEXT'指定に変えて、逃げる手も考えたのですが、他に弄らないといけないコードが多い事に気付いて、もう八方塞りに陥りました。orz
(PHPの言語仕様知らないし〜)

挫折

という訳で、

  • IEにローカルファイルをドラッグ&ドロップすると、ファイルパスをクリップボードにコピーする
  • ファイルダイアログを、とりあえず開くだけ行う

までは、実現する事にし、その後は

  • 人間の手で貼り付け&閉じる&アップロードを行ってもらう。

という中途半端な対応となりました。


以下に、plugin/attach.inc.php プラグインに対する、パッチコードを示します。(1.4.7で確認済み)

--- F:\Wacky\Test\pukiwiki\attach.inc.php	2010-09-05 17:07:25.281250000 +0900
+++ F:\Wacky\Test\pukiwiki\attach.inc.php.new	2010-09-05 17:07:33.578125000 +0900
@@ -419,11 +419,32 @@
   <span class="small">
    $msg_maxsize
   </span><br />
-  <label for="_p_attach_file">{$_attach_messages['msg_file']}:</label> <input type="file" name="attach_file" id="_p_attach_file" />
+  <label for="_p_attach_file">{$_attach_messages['msg_file']}:</label> <input type="file" name="attach_file" id="_p_attach_file"/>
   $pass
   <input type="submit" value="{$_attach_messages['btn_upload']}" />
  </div>
 </form>
+<!-- IE only -->
+<object id="DnD_Box" classid="clsid:8E3867A3-8586-11D1-B16A-00C0F0283628" width="350" height="100">
+	<param name="OleDropMode" value="1">
+	<param name="Style" value="1">
+	<param name="SimpleText" value="In this area, please do Drag & Drop of a file.">
+	<param name="allowScriptAccess" value="always">
+</object>
+<script type="text/JScript">
+function DnD_Box::OLEDragDrop(Data){
+	if(Data.GetFormat(15)){
+		var O = "";
+		var e = new Enumerator(Data.Files);
+		O = e.item();
+		//alert(O);
+		DnD_Box.SimpleText = O;
+		clipboardData.setData("Text", O);		// ファイルパスをクリップボードへ
+		//document.getElementById("_p_attach_file").value = clipboardData.getData("Text");
+		document.getElementById("_p_attach_file").click();	// ファイルダイアログを開くだけ
+	}
+}
+</script>
 EOD;
 }

最後に

という訳で、今回は途中挫折という結果に陥りました。
もし、HTMLに詳しい方が居られましたら、完全版を作って頂けないかな?と思う次第であります。まる。