風柳メモ

ソフトウェア・プログラミング関連の覚書が中心

jQuery.uploadの不具合?

http://lagoscript.org/jquery/upload?locale=jaは、

jQuery.uploadは、AjaxスタイルでファイルをアップロードするためのjQueryプラグインです。

http://lagoscript.org/jquery/upload?locale=ja

と書かれているとおり、ファイルを画面遷移無しでアップロードできる便利なjQueryのプラグイン……なのですが。


本日、使っていると、コールバックされるテキスト(html)が壊れてしまっているケースがあったので、注意が必要です。
具体的には、テーブルの1行分を渡そうとして、

<tr></tr>

の部分だけを返そうとすると、はまります。
能書きはいいから、解決方法を早く、というせっかちな人はこちらをどうぞ。

具体例

こちらのサンプルをお試しください。
選択する(アップロードする)ファイルは別になんでもよいです。ファイル名と型を拾っているだけですので。

POSTの応答として、TABLE要素をすべて返すテスト1の場合では問題なく表示されるのですが、TR要素しか返さないテスト2の場合は、そもそも戻ってきたhtmlの段階で、タグが消えてしまっています。

サンプルのソースコード

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>jQuery.uploadの不具合?</title>
<style>
table, table th, table td {
	border: solid 1px navy;
	border-collapse: collapse;
}
pre {
	border: solid 1px purple;
}
</style>
<script src="./jquery-1.7.1.min.js"></script>
<script src="./jquery.upload-1.0.2.min.js"></script>
<script>
(function(w,d){

function escape_html(html){
	var	ehtml=html.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;');
	return ehtml;
}

$().ready(function(){
	$('input[type=file]').change(function() {
		var jq_input=$(this), jq_form=jq_input.parent('form'), id_base=jq_form.attr('id');
		jq_input.upload(jq_form.attr('action'), function(html) {
			$('#container1_'+id_base).append($(html));
			$('#container2_'+id_base).val(html);
			$('#container3_'+id_base).html(escape_html(html));
		}, 'html');
	});
})
})(window, document);
</script>
</head>

<body>
<h1><a href="http://lagoscript.org/jquery/upload?locale=ja">jQuery.upload</a>の不具合?</h1>

<div>
	<h2><a href="./table.php">テスト1 (&lt;table&gt;〜&lt/table&gt;)</a></h2>
	<form action="./table.php" method="POST" enctype="multipart/form-data" id="test1">
		<input type="file" value="" id="upload_file" name="upload_file" />
	</form>
	<h3>結果</h3>
	<div id="container1_test1"></div>
	<h4>HTML(TEXTAREA)</h4>
	<textarea id="container2_test1" rows="12" cols="80"></textarea>
	<h4>HTML(エスケープ後)</h4>
	<pre id="container3_test1"></pre>
</div>
<hr />
<div>
	<h2><a href="./tr.php">テスト2 (&lt;tr&gt;〜&lt/tr&gt;)</a></h2>
	<form action="./tr.php" method="POST" enctype="multipart/form-data" id="test2">
		<input type="file" value="" id="upload_file" name="upload_file" />
	</form>
	<h3>結果</h3>
	<table>
		<tbody id="container1_test2">
		</tbody>
	</table>
	<h4>HTML(TEXTAREA)</h4>
	<textarea id="container2_test2" rows="12" cols="80"></textarea>
	<h4>HTML(エスケープ後)</h4>
	<pre id="container3_test2"></pre>
</div>

</body>
</html>

jQuery.uploadの使い方としては、特に特殊なことはやっていないつもりです。


追記

余談ながら、

<tr></tr>

だけを返すとはまる、ということであれば、サーバ側で

<table><tbody><tr></tr></tbody></table>

とダミーの<table>…</table>でくくっておいて、クライアント側で$('<table>…</table>').find('tr:first')なりして取り出せばよい、という話もあります。
これなら、new FormData() をサポートしないブラウザでもなんとか。


追記その2

そういえば、TABLE要素っていろいろ特殊だったなぁ、と思い出してみたり。
過去に

【JavaScript】IE6におけるtable要素の初期化: 風柳亭
【JavaScript】IE6でTABLE要素内をHTMLで書換える関数: 風柳亭

こんな記事も書いていた。