先日Another HTML-lint gatewayを通し、怒られて気付いた(他にもいっぱい怒られちった)のだが、FC2ブログのコメント内の”&”は実体化参照されない仕様のようだ。例えば、<&>とコメント送信すると<&>というテキストが鯖に保存される。半角&はURLに含まれている場合があり、気付かないことも多い(オレだけ?)。
そこでコメント欄に書かれた”&”を”&”に変換してから送信するスクリプトを考えてみよう。(これは頭の体操や詰め将棋ライクなネタです。最良の解法はFC2に要望出して実装してもらうの一手(他力))
スクリプトのメイン、書き換え部分はちょー簡単。
コメント文字列 = コメント文字列.replace( /&/g, "&" );どうせなら、プラグイン化も視野にいれポン付けで動くものの方がシバリがあって面白い。プラグインするページには複数のフォーム、例えばメール用、サーチ用etcがあるかもしれない(もちろん無い場合だってありうる)。その中からコメント送信フォームを見つだすのがキモになる。<form>のIDは一律でないから使えない。が、name属性はユニークなので代用できる。
function hoge() { if ( document.forms && document.getElementsByTagName ) { with ( document ) { for ( var i=0; ( F = forms[i] ); i++ ) { for ( var j=0; ( T = F.getElementsByTagName("*")[j] ); j++ ) { if ( T.name && T.name == "comment[body]" ) { T.value = T.value.replace( /&/g, "&" ); break; } } } } }}5行目の記入欄を探す部分で、対象は<input>の場合や<select>の可能性だってありうる。なので(謎)<textarea>と決めつけない方がよさげ。ラジオボタンやセレクトのvalueを送信する、アンケート風なコメント欄だってやろうと思えば作れるのだFC2。(脱線)
さて、すべてに当てはまると限らないがスクリプトには実行のタイミングが重要なものもある。このサンプルでは、コメント書き終わりよりも後、かつ送信よりも前に行いたい。<form>にはonsubmitという条件にぴったりなイベントがあるので、ここで書き換える。
var taget_comment, before_event = null;function hoge() { if ( document.forms && document.getElementsByTagName ) { with ( document ) { for ( var i=0; ( F = forms[i] ); i++ ) { for ( var j=0; ( T = F.getElementsByTagName("*")[j] ); j++ ) { if ( T.name && T.name == "comment[body]" ) { taget_comment = T; if ( typeof F.onsubmit == "function" ) before_event = F.onsubmit; F.onsubmit = function() { if ( before_event ) before_event; taget_comment.value = taget_comment.value.replace( /&/g, "&" ); return true; } break; } } } } } } 1行目にグローバル変数を設定。他にどのようなスクリプトが共存しているか解らないので、変数名はなるべく複雑なものにするのがバッティングを避けるコツ(確実ではないが)。8行目でコメントが入る要素、9行目でonsubmitに他イベントが割り当てられていればその内容を、それぞれ変数に保存しておく。
最後に<body>が読み込まれたらスクリプト本体を実行させる。onloadイベントを上書きしないような配慮も。
var taget_comment, before_event = null;if ( document.getElementsByTagName ) { var B = document.getElementsByTagName( "BODY" )[0]; if ( typeof B.onload == "function" ) before_event = B.onload; B.onload = function() { if ( before_event ) { before_event; before_event = null; } hoge(); }}function hoge() { if ( document.forms && document.getElementsByTagName ) { with ( document ) { for ( var i=0; ( F = forms[i] ); i++ ) { for ( var j=0; ( T = F.getElementsByTagName( "*" )[j] ); j++ ) { if ( T.name && T.name == "comment[body]" ) { taget_comment = T; if ( typeof F.onsubmit == "function" ) before_event = F.onsubmit; F.onsubmit = function() { if ( before_event ) before_event; taget_comment.value = taget_comment.value.replace( /&/g, "&" ); return true; } break; } } } } } } 要素の探索、イベント割り当て、実行部分を分けて考えるのが早道か。(つづくかも)